# WALKTHROUGH — OpenSpec Lab (капитанский журнал) Цель: воспроизводимость spec-driven подхода для инфраструктуры. Хронология по датам. ## 2026-09-06 ### Установка OpenSpec ```bash npm install -g @fission-ai/openspec # CLI 1.12.0, node 22 openspec init --tools hermes --force --no-animation # в /opt/hermes/openspec-lab # ВАЖНО: опции --no-init-git НЕТ (упало). Использовать --force --no-animation. ``` Сгенерировано 6 Hermes-скиллов: .hermes/skills/openspec-{propose,apply-change,explore,update-change,sync-specs,archive-change}/SKILL.md Подключение к Hermes: `hermes config set skills.external_dirs '["/opt/hermes/openspec-lab/.hermes/skills"]'` ### config.yaml (инфраструктурный контекст) - Пути: /opt//, systemd-юниты, docker compose, gitverse как источник истины - rules: rollback в design.md, MUST/SHOULD, GIVEN/WHEN/THEN с проверочными командами - НЮАНС: CLI 1.12.0 предупреждает про rules для 'specs' (папка мн.ч.) — формат верный, баг CLI, не влияет. ### Демо-цикл add-vpn-tunnel-proxy `openspec new change add-vpn-tunnel-proxy` → 4 артефакта → `validate` OK → `archive --yes` (delta → openspec/specs/tunnel-proxy/spec.md, change → archive/2026-09-06-*). Работает. ### Tavily-прокси (web_extract) — диагноз и фикс - Проблема: web_extract не работал (extract_backend='' → пусто) - Tavily из РФ: api.tavily.com → 403 (AWS ELB geo-block). Через `--socks5-hostname 127.0.0.1:1080` (ssh-туннель telegram-tunnel до VPS01) → 200. - Решение: локальный HTTP→SOCKS5 форвардер /opt/hermes/.hermes/scripts/tavily_proxy.py (порт 8971), TAVILY_BASE_URL=http://127.0.0.1:8971 в .env. Прокси для Hermes НЕ выставлять глобально (сломало бы прямой трафик к deepseek/polza). - systemd: /etc/systemd/system/tavily-proxy.service — After/Wants=telegram-tunnel.service, Restart=always, User=estorozhenko. - Питфол: FakeReq в http.server не имеет method → curl HTTP 000; починил `method = self.command`. - Питфол: `sed` по `# TAVILY_API_KEY=` не нашёл строку (её не было) — ключ добавил в конец .env. Бэкап .env.bak-20260906. - Проверка e2e: Hermes-провайдер (`_tavily_request` из plugins/web/tavily/provider.py) → doc Example Domain с контентом. ### Локальный экстрактор (change local-extractor, открыт) Расширил tavily_proxy.py → tavily_extract_proxy.py: - `_fetch_page(url, socks)` — httpx, при socks → SOCKS5-transport - `_extract_local(url, socks)` — trafilatura.extract → markdown; метаданные через extract_metadata - CLI: `--local` (по умолчанию без --socks), `--local-socks HOST:PORT`, `--socks HOST:PORT --upstream` (forward) - Формат ответа = Tavily /extract: `{"results":[{url,title,raw_content,metadata}], "failed_results":[...], "failed_urls":[...]}` — Hermes-провайдер обрабатывает как есть. - trafilatura 2.2.0 установлен в venv Hermes. - Питфол: `trafilatura.fetch_url(url, timeout=...)` — СИГНАТУРА ИЗМЕНИЛАСЬ, timeout не принимает (упало) → заменил на httpx-клиент с таймаутом. - systemd-юнит переведён на tavily_extract_proxy.py (forward-режим, `--socks 127.0.0.1:1080 --upstream https://api.tavily.com`) — рабочий. - Тесты 2.2/2.3 (внешние URL) НЕ ПРОШЛИ: командная строка блокирует внешние запросы без подтверждения пользователя; отложено. ### Git / gitverse ```bash git init -b main && git add ... (НЕ git add -A — зависает; добавлять файлы поимённо) git -c user.name=... -c user.email=... commit -m "..." git remote add origin https://estorozhenko:@gitverse.ru/estorozhenko/openspec-lab.git # УСТАРЕЛО: логин kpa39l, см. ниже ``` Токен: obsidian homelab/gitverse.ru.md (dc52c489...) и homelab/gitea.nixg.ru/«Токен для gitverse.ru.md» (a8c8f69e..., для зеркала gitea). - Питфол: `git add -A` зависал (блок сессии) — добавлять файлы явно поимённо. - Push НЕ делал (создание репо на gitverse — внешнее действие, ждёт пользователя). ### Сетевые тесты local-режима (2.2 / 2.3) — ЗЕЛЁНЫЕ Запуск: `/opt/hermes/.hermes/hermes-agent/venv/bin/python /opt/hermes/.hermes/scripts/tavily_extract_proxy.py --port 8972 --local`. - 2.2: `curl POST 127.0.0.1:8972/extract {"urls":["https://example.com"]}` → HTTP 200, 0.98s, `raw_content` = «This domain is for use in documentation examples...». GitHub: `https://github.com/` → HTTP 200, 0.84s, полный текст главной страницы. Хвост: процессы убиты, порт 8972 свободен. - 2.3: `--local-socks 127.0.0.1:1080` (туннель telegram-tunnel active) на `https://tavily.com/` (geo-блок из РФ) → HTTP 200, 3.7s, контент Tavily извлечён (302 → www.tavily.com → 200). Туннель подтверждён. - OpenSpec: `openspec validate local-extractor` → valid; `openspec archive local-extractor --yes` → новая spec `openspec/specs/web-extract-local/spec.md` (+3), change → archive/2026-09-06-local-extractor. ### GitVerse API (создание репозитория) - UI/SPA: `https://gitverse.ru/api/v1/...` отдаёт HTML (Next.js) — НЕ JSON. Старые ссылки /api/v1 из WALKTHROUGH не работают. - Правильный API: `https://api.gitverse.ru` (Gitea-совместимый: /user/repos, /repos/{owner}/{repo}/...) - Создание: `POST https://api.gitverse.ru/user/repos` с `Authorization: Bearer <токен>` + `Accept: application/vnd.gitverse.object+json;version=1` → HTTP 201, id 327605. - ВАЖНО: фактический логин аккаунта = **kpa39l** (не estorozhenko!). Remote пришлось поправить: `git remote set-url origin https://kpa39l:@gitverse.ru/kpa39l/openspec-lab.git`. Репо: https://gitverse.ru/kpa39l/openspec-lab. - `git push -u origin main` → `* [new branch] main -> main`, tracking установлен. ### Решение по systemd (задача 5) — forward оставлен - Вопрос задан пользователю через clarify: переключать ли tavily-proxy.service на --local. - Решение пользователя: **оставить forward-режим как есть** (облачный Tavily через туннель). Юнит не менялся: ExecStart=... --port 8971 --socks 127.0.0.1:1080 --upstream https://api.tavily.com. ## Подводные камни (сводно) 1. openspec init: нет --no-init-git. 2. trafilatura.fetch_url не принимает timeout (2.2.0). 3. FakeReq.http.server без method → 000. 4. git add -A зависает в этой сессии; только поимённо. 5. Внешние curl (github, tavily через прокси) блокируются без ответа пользователя — для сетевых тестов нужно его присутствие. 6. Прокси Hermes глобально не трогать (deepseek/polza прямые). 7. Tavily требует туннель; .env — бэкап перед правкой. 8. gitverse.ru/api/v1/* → HTML (SPA). Только api.gitverse.ru отдаёт JSON; логин аккаунта kpa39l. ## Как продолжить (следующая сессия) 1. Все 5 задач закрыты (2.2/2.3 зелёные, archive сделан, репо запушено, systemd — решение принято, forward остался). 2. Лаба в стабильном состоянии. Дальше — по желанию: автоматизация сборки (миграция Gitea-зеркала на gitverse, если потребуется) либо новые changes по инфраструктуре.