Skip to content

Repository files navigation

Fox AI devcontainer

Общее dev-окружение для проектов foxford: образ девконтейнера, AI-обвязка (скиллы, MCP-серверы, Hermes-роли) и скелет нового проекта — всё ставится на машину разработчика одной командой, без registry и ручной настройки.

Архитектура и внутреннее устройство платформы — в SPEC.md (нужно только если ты её поддерживаешь или расширяешь, не для повседневной работы).

Что такое devcontainer и почему он

Dev Container — открытая спецификация (за ней стоит VS Code, GitHub Codespaces, JetBrains): описание окружения разработки как Docker-образа, который редактор поднимает и подключается к нему, а код редактируется как обычно. Инструментарий, версии языков и зависимостей живут внутри контейнера, а не на хосте.

Мы взяли его за основу по трём причинам:

  • Изоляция. Тулчейн проекта (ноды, компиляторы, глобальные CLI) не течёт в систему разработчика и не конфликтует с другими проектами на той же машине — у каждого свой контейнер.
  • Воспроизводимость. Один и тот же образ у всех разработчиков.
  • Одна команда, любая ОС. macOS, Linux, WSL — install.sh сам определяет ОС и доводит хост до состояния «докер есть, дальше редактор всё поднимет сам», без ручной настройки под каждую платформу отдельно.

Быстрый старт

# 1. Поставить платформу (клон + CLI в ~/.local/bin)
curl -fsSL https://raw.githubusercontent.com/foxford/ai-devcontainer/main/install.sh | bash

# 2. Проверить машину (docker, персист-каталоги, образ)
adc doctor

Требования на машине: git, VS Code | Cursor (или совместимый редактор с devcontainers). Всё остальное — docker, rsync, jq — install.sh проверит и поставит сам под ОС хоста (macOS/Linux, включая WSL).

Новый проект

adc new my-service ~/Development/@foxford/my-service
cd ~/Development/@foxford/my-service && code .
# → Reopen in Container: образ dev-base:local соберётся сам (~5-10 мин в первый
#   раз, дальше docker-кеш), postCreate засидит .hermes/.agents/skills,
#   поставит AI-тулзы, построит graphify-граф, разведёт скиллы по агентам.

Существующий репозиторий

cd ~/Development/@foxford/existing-repo
adc sync --adopt      # заводит .devcontainer/, код проекта не трогает
code .
# → Reopen in Container: дальше всё как у нового проекта.

CLI

Команда — adc (ставит install.sh).

Команда Где Что делает
adc new <name> [dir] [--type <t>] хост новый проект из skeleton (git init, имя подставлено); без --type спросит тип, если их несколько
adc sync [--adopt] [--type <t>] везде применить платформу к проекту: скиллы, доки, MCP, .gitignore; печатает, что именно приехало с прошлого раза. --adopt заводит .devcontainer/ в репозитории, который раньше платформой не управлялся (код проекта не трогает)
adc update везде на хосте: git pull платформы + пересборка образа. В контейнере (клон read-only) — то же, что sync
adc doctor везде проверить: docker, образ, персист, PATH, доступные типы скаффолда; из каталога проекта — ещё и его devcontainer.json
adc skill <cmd> везде скиллы проекта: list / status / fork / unfork / migrate / sync
adc mcp <cmd> контейнер MCP-серверы проекта: list (все слои и что активно), add / rm, enable / disable, sync
adc plans [--all] везде задачи проекта: что в работе, что дольше всех не двигалось, сколько закрыто
adc ensure-image хост собрать/дособрать dev-base:local вручную (обычно не нужно — сама встаёт при первом контейнере)
adc prepare хост хостовая подготовка проекта; её зовёт initializeCommand — руками не нужна

Граница «хост / контейнер» жёсткая: команда, набранная не на той стороне, отказывается с объяснением, а не работает наполовину. Причина не в аккуратности — снаружи контейнера ~/.codex, ~/.hermes и ~/.dsh принадлежат самому разработчику и общие на все его проекты, а тома /opt/ai-tools там нет вовсе: adc mcp sync на хосте подмешал бы серверы одного проекта в личный конфиг. По той же причине adc sync на хосте раскладывает скиллы и доки, но раздачу MCP пропускает и говорит об этом.

Обновление платформы не трогает существующие проекты само по себе: окружение подтянется при следующем Rebuild Container, конфиг-пакеты — руками (подробности — в SPEC.md).

Известные грабли

⚠️ Claude не показывает MCP-серверы проекта, хотя adc mcp list зелёный. Почти всегда — нет маунта ~/.claude.json. Это файл рядом с ~/.claude, а не внутри; в нём лежит одобрение проектных серверов из .mcp.json, и без персиста оно теряется на каждом rebuild. Проверить — adc doctor из каталога проекта: он назовёт недостающий маунт и даст готовую строку. Дальше — adc prepare на хосте и Rebuild Container.

⚠️ «Rebuild Container Without Cache» в VS Code — не использовать. Команда добавляет к сборке --pull, который тянет базовый образ из registry, а dev-base:local существует только локально → pull access denied. Обычные «Reopen in Container» / «Rebuild Container» работают. Нужна пересборка с нуля:

docker rmi dev-base:local && adc ensure-image

Скиллы

Стоковые скиллы живут в платформе (skills/) и в проект не копируются — подмешиваются из /opt/ai-devcontainer/skills. Проект хранит только то, чем отличается: <repo>/.agents/skills/. Собранное дерево, которое видят агенты, — <repo>/.claude/skills/ (в .gitignore, пересобирается на каждом postCreate).

adc skill list                          # что откуда приезжает
adc skill fork senior-qa                # взять SKILL.md под правку проектом
adc skill fork impeccable scripts/live.mjs   # перекрыть можно ЛЮБОЙ файл
adc skill status                        # разошлась ли платформа под форками
adc skill unfork senior-qa              # вернуться на платформенную версию
adc skill sync                          # пересобрать после adc update

На хосте то же самое — adc skill <cmd> из каталога проекта.

Проект, у которого скиллы вендорены по старой схеме, переводится разово: adc skill migrate — файлы, совпадающие с платформой, выкидываются (поедут централизованно), отличающиеся остаются форками. Без миграции проект не получит обновлений: его копии перекрывают платформенный слой целиком.

MCP-серверы

Четыре слоя. Правило приоритета одно и запоминается фразой: проектное бьёт глобальное, моё бьёт общее.

Слой Где лежит Чей и где виден
--global mcp/servers.json платформы общий, во всех проектах · только чтение
--user /opt/ai-tools/share/mcp/servers.json мой, во всех моих проектах
--project <repo>/.agents/mcp.json команды, уезжает в гит
--local <repo>/.agents/mcp.local.json мой, только в этом проекте

Имена слоёв — те же, что у claude mcp add --scope, чтобы не заводить свой словарь. Пользовательский слой живёт в томе platform-ai-tools, общем на все проекты: токен вроде OBSIDIAN_API_KEY вписывается один раз на машину, а не заново в каждом новом проекте.

adc mcp list                                  # все слои: что есть, что активно, почему нет
adc mcp add --json '<сниппет из README>'      # вставить как есть с сайта сервера
adc mcp add linear -- npx -y linear-mcp-server
adc mcp add linear --url https://… --header 'Authorization: Bearer ${TOKEN}'
adc mcp enable figma                          # спросит недостающий токен и запишет
adc mcp disable playwright --local            # перекрыть нижний слой
adc mcp sync                                  # пересобрать (после adc update)

Слой не спрашивается молча: без флага и без TTY команда берёт локальный — самый узкий. Тихо положить личный сервер в гит команды нельзя.

Секрет в проектный слой не попадёт. .agents/mcp.json лежит в гите, поэтому adc mcp add --project вынимает литеральный токен в .agents/mcp.secrets.env (он в .gitignore) и оставляет в слое ${ИМЯ}. Вписанный руками секрет ловит adc mcp sync и предлагает adc mcp fix-secrets. В --local и --user токен не трогаем: те слои в гит не едут.

Раскладывать приходится в четыре места: проектный скоуп для MCP есть только у Claude Code (<repo>/.mcp.json), а Codex, Hermes и DSH держат серверы в home (~/.codex/config.toml, ~/.hermes/config.yaml, ~/.dsh/cordis.patch.yml). Персист в платформе пер-проектный, так что проекты за эти конфиги не дерутся.

.mcp.jsonартефакт сборки, а не конфиг: он пересобирается на каждом sync и несёт раскрытые токены. Править его руками бесполезно (правка теряется), поэтому в скелете он скрыт из проводника VS Code через files.exclude.

Сервер Что даёт Когда появляется
playwright браузер агента: клики, снапшоты, консоль всегда
chrome-devtools профилирование, трейсы, троттлинг, Core Web Vitals как встанет браузер
figma фреймы, токены дизайна, код по выделению явный опт-ин FIGMA_MCP_ENABLED

Сервер, которому не хватает токена или браузера, не раздаётся вовсе (поле x-requires) — иначе агент получал бы инструменты, падающие на первом вызове. Такой сервер виден в adc mcp list как с причиной и командой починки; включить — adc mcp enable <имя>, она сама спросит недостающую переменную. Выключить лишний — adc mcp disable <имя> (это null поверх нижнего слоя).

Секреты — два файла, той же цепочкой: /opt/ai-tools/share/mcp/secrets.env (один на машину) и <repo>/.agents/mcp.secrets.env (перекрывает его, в .gitignore, права 600). ${ИМЯ} раскрывает wire-mcp — сам, а не агент: ${VAR} умеют Claude и Hermes, на Codex не проверено, и схема «у двоих работает, у третьего молча пусто» хуже честной.

⚠️ OAuth-серверы включаются вручную и не просто так. Попав в конфиг, такой сервер просит авторизацию при каждом старте агента во всех проектах, поэтому figma по умолчанию выключен. И в Codex url-серверы не добавляются автоматически: codex mcp add --url коннектится прямо при добавлении и поднимает интерактивный OAuth-промпт — в postCreate это висяк.

Не путать с e2e-раннером самого проекта, если он у скаффолда есть и тоже на Playwright: это отдельный процесс, его гоняет CI. MCP — инструмент для агента, чтобы исследовать живое приложение вручную. Если оба используют Playwright, браузеры ставятся в общий named volume и переживают rebuild.

Obsidian

Два независимых канала. Когда агенту использовать какой — скилл obsidian.

Vault-каталог — работает сразу, без настройки. В каждом проекте есть маунт obsidian-vault (~/.ai-devcontainer-dev/<проект>/obsidian на хосте):

graphify update . --obsidian --obsidian-dir /home/node/obsidian-vault

Открой ~/.ai-devcontainer-dev/<проект>/obsidian как vault в хостовом Obsidian — файлы появляются сразу, персист переживает rebuild.

MCP-сервер obsidian — живой доступ агента к тому vault'у, что реально открыт в Obsidian на хосте (не обязательно к каталогу выше). Настройка, один раз:

  1. Установи плагин Local REST API через Community Plugins в Obsidian.
  2. В его настройках включи Enable Non-encrypted (HTTP) Server (порт 27123) — так проще, чем доверять самоподписанный сертификат HTTPS-порта, а трафик и так не выходит за пределы хоста.
  3. Скопируй API Key из тех же настроек.
  4. В .agents/mcp.secrets.env проекта: OBSIDIAN_API_KEY=<ключ>.
  5. adc mcp sync, перезапусти агента.

Без ключа сервер молча не раздаётся (та же схема, что у figma). Полный список инструментов (vault_read/vault_write/search_simple/tag_list/...) — в скилле obsidian.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages