Files
spec-driven-infra/references/openspec-infra-test-2026-09.md
2026-09-06 13:51:26 +00:00

103 lines
4.9 KiB
Markdown

# OpenSpec for Infra — Hands-on Validation (2026-09)
Full end-to-end test on this host. All commands verified.
## Setup
```bash
# node 22 present at ~/.local/bin
npm install -g @fission-ai/openspec@latest # v1.12.0, binary -> /opt/hermes/.hermes/node/bin/openspec
mkdir -p /opt/hermes/openspec-lab && cd /opt/hermes/openspec-lab
openspec init --tools hermes --force --no-animation
# Output: "6 skills in .hermes/", "Commands skipped for: hermes (no adapter)"
# Structure created:
# .hermes/skills/openspec-{propose,explore,apply-change,update-change,sync-specs,archive-change}/SKILL.md
# openspec/config.yaml
# openspec/specs/.gitkeep, openspec/changes/archive/.gitkeep
```
Hermes wiring:
```bash
hermes config set skills.external_dirs '["/opt/hermes/openspec-lab/.hermes/skills"]'
hermes config get skills # -> external_dirs: '["..."]'
```
## Infra config.yaml (working)
```yaml
schema: spec-driven
context: |
Домен: self-hosted инфраструктура (homelab / VPS), Linux (Ubuntu/Debian), Docker (docker compose), systemd.
Окружение: Hermes-агент на хосте, SSH-доступ к VPS.
Ключевые сервисы: prosody (XMPP + Slidge мост), netbox (docker), garage (S3), searxng, mtproto-proxy, nntp, tproxy-web-proxy, telegram-tunnel.
Управление: systemd-юниты, docker-compose.yml, конфиги в /opt/<service>/; рестарт сервисов — только извне (SSH sudo systemctl restart).
Соглашения: отдельный каталог /opt/<service>/ на сервис; секреты в .env; порты фиксируются в README.md; апдейты через git.
rules:
proposal:
- Указывать затронутые сервисы и порты
- Включать план отката (rollback)
specs:
- Требования в формате MUST/SHOULD/MAY
- Сценарии проверки: GIVEN/WHEN/THEN с конкретными командами верификации (systemctl status, curl, docker ps)
design:
- Указывать конкретные файлы конфигов и юнитов
- Включать команды применения и проверки
tasks:
- Каждая задача — проверяемый шаг с командой верификации
```
## Change lifecycle test (add-vpn-tunnel-proxy)
```bash
openspec new change add-vpn-tunnel-proxy
# -> openspec/changes/add-vpn-tunnel-proxy/.openspec.yaml (schema: spec-driven, created: 2026-09-06)
openspec status --change add-vpn-tunnel-proxy --json
# artifacts: proposal, specs (outputPath "specs/**/*.md"), design, tasks
# applyRequires: ["tasks"], planningHome.root, actionContext.allowedEditRoots
openspec instructions proposal --change add-vpn-tunnel-proxy --json
# -> instruction (Why/What Changes/Capabilities/Impact), template, context (injected), rules
# NOTE: stderr warns "Rules for 'specs' must be an array of strings, ignoring this artifact's rules" — harmless
```
Wrote the 4 artifacts by hand (proposal.md, specs/tunnel-proxy/spec.md with ADDED requirements + GIVEN/WHEN/THEN scenarios, design.md with files/commands/rollback, tasks.md with checkboxes).
```bash
openspec validate add-vpn-tunnel-proxy # -> "Change 'add-vpn-tunnel-proxy' is valid"
openspec status --change add-vpn-tunnel-proxy # -> 4/4 artifacts complete
openspec list # -> add-vpn-tunnel-proxy 0/7 tasks
# Without --yes, archive fails (asks y/N, no stdin):
openspec archive add-vpn-tunnel-proxy # -> error: 7 incomplete tasks, no answer from stdin
sed -i 's/^- \[ \]/- [x]/' openspec/changes/add-vpn-tunnel-proxy/tasks.md
openspec archive add-vpn-tunnel-proxy --yes
# -> "Specs updated successfully. Change archived as '2026-09-06-add-vpn-tunnel-proxy'."
# -> openspec/specs/tunnel-proxy/spec.md created (2 requirements merged)
# -> openspec/changes/archive/2026-09-06-add-vpn-tunnel-proxy/ (all 4 artifacts)
```
Merged main spec (auto-generated):
```markdown
# tunnel-proxy Specification
## Purpose
TBD - created by archiving change add-vpn-tunnel-proxy. Update Purpose after archive.
## Requirements
### Requirement: Persistent SOCKS5 Tunnel
The system MUST maintain a persistent SOCKS5 proxy tunnel from the host to VPS01, listening on 127.0.0.1:1080.
#### Scenario: Tunnel starts on boot
- GIVEN the host boots ...
#### Scenario: Tunnel dies ...
```
## Gotchas hit
1. `openspec init --no-init-git` → "unknown option" — that flag does not exist in v1.12.0 (git init runs by default).
2. `openspec instructions ... --json | python3 -m json.tool` → JSON decode error because warnings go to **stdout**, not stderr. Use `> out.json 2> err.txt`.
3. Rules for `specs` artifact always warn (even well-formed) — cosmetic, ignore.
4. Archive needs tasks done → use `--yes` after completing tasks.
5. `hermes config get skills` prints external_dirs as a string — normal.