The `source.type: git` blocks for interns-mcp and projects-meta-mcp pointed to repos that don't exist as standalone (interns-mcp never existed, projects-meta-mcp is archived). Both live as subdirectories of the .common repo. Remove source blocks, keep deps + target + setup_skill + health_check. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
212 lines
16 KiB
Markdown
212 lines
16 KiB
Markdown
---
|
||
date: '2026-05-06'
|
||
source: .meeting-room/.archive/2026-05-06-factory-bootstrap.md
|
||
status: promoted
|
||
type: concept
|
||
title: factory-bootstrap
|
||
ingested_at: '2026-05-06T18:22:46.484Z'
|
||
ingested_by: OpeItcLoc03@DESKTOP-NSEF0UK
|
||
source_project: .meeting-room
|
||
---
|
||
# Software factory bootstrap — design
|
||
|
||
## Контекст и диагноз
|
||
|
||
В `~/projects/` есть точечные папки-модули будущей "ERP":
|
||
|
||
| Модуль | Артефакт | Состояние (на 2026-05-06) |
|
||
|---|---|---|
|
||
| HR / org chart | `.organization/` (roster.md + personas) | частично |
|
||
| Inventory / templates | `.templates/` | частично (`project/` есть, `agent/`/`report/` пусты) |
|
||
| Knowledge (local) | `.wiki/` (Karpathy) | живой |
|
||
| Knowledge (shared) | `projects-wiki` через `mcp__projects-meta__*` | живой, 13–14 страниц |
|
||
| Tasks / PMO | `.tasks/` (local) + `mcp__projects-meta__tasks_*` (shared) | живой, 14 проектов в кэше |
|
||
| Shared services | `.common/` (lib/scripts/secrets/prompts/config) | живой |
|
||
| Tooling registry | `claude-skills/` (~21 скил) | живой |
|
||
| Bus services | `.common/lib/projects-meta-mcp/`, `.common/lib/interns-mcp/` (subdirs of .common, not standalone repos — см. `[migrate-to-common-lib]`) | живые |
|
||
| Communications | `.meeting-room/` | живой |
|
||
|
||
**Что не работало для онбординга нового сотрудника:**
|
||
|
||
1. Нет orchestrator'а — `setup-*` дёргаются по одному вручную.
|
||
2. Нет L0 entry point — пока Claude не запущен, ни один setup-* не доступен.
|
||
3. Нет manifest'а компонентов — версий, зависимостей, health-check'ов нет нигде.
|
||
4. Hardcoded `~/projects/` в путях — переезд = ручная починка.
|
||
5. Multi-vendor (Cursor / Copilot CLI / Gemini CLI): `setup-*` пишут только в `~/.claude.json`.
|
||
6. Фабрика сама не убрана.
|
||
|
||
## Решение
|
||
|
||
**Создать новую дот-папку `~/projects/.factory/` — отдельный репо, сиблинг `.common/`. Manifest-driven cross-platform installer/updater всей мета-инфраструктуры.**
|
||
|
||
Размещение выбрано потому, что factory должна работать **до того**, как `.common` склонирован. L0 кладёт `.factory/` первым, дальше уже он ставит всё остальное. Альтернативы (`.common/lib/factory/`, `claude-skills/skills/factory/`) отвергнуты — обе создают cycle dependency.
|
||
|
||
### Архитектура — три слоя
|
||
|
||
**L0 — Pre-Claude bootstrap** (нативный shell, без runtime-зависимостей). Два под-слоя:
|
||
|
||
**L0a — System bootstrap (toolchain).** Голая машина → готовая к работе.
|
||
- Системный пакет-менеджер: `winget` (Win11), `brew` (Mac), `apt`/`dnf`/`pacman` (Linux).
|
||
- `git` + `curl` через системный pkg-mgr.
|
||
- `mise` (бывш. rtx) — single-binary unified runtime manager. Через него `node@lts`, `python@latest`, `go@latest`, `rust` по требованию. Закрывает nvm/pyenv/goenv одной зависимостью.
|
||
- Опционально (yes/no/skip): Claude Code, Cursor, VS Code, Ollama, Docker Desktop.
|
||
|
||
**L0b — Factory bootstrap.** После L0a.
|
||
- `bootstrap.ps1` + `bootstrap.sh` — запуск через `iwr … | iex` / `curl … | bash`.
|
||
- Делает только: detect platform → спросить `$PROJECTS_DIR` → clone `.factory/` (gitea) → передать управление в L1.
|
||
- Единое состояние машины: `~/.config/factory/home.toml`:
|
||
```toml
|
||
projects_dir = "C:/Users/vitya/projects"
|
||
client = "claude-code" # | "copilot-cli" | "gemini-cli"
|
||
installed_at = "2026-05-06T..."
|
||
```
|
||
- Если несколько `projects_dir` — `home.toml` хранит активный, флаг `--projects-dir <path>` переключает.
|
||
|
||
**L1 — `factory.yaml` + `factory` CLI** (один скомпилированный Go-бинарь — см. Q1).
|
||
- Manifest-схема (черновик):
|
||
```yaml
|
||
components:
|
||
- name: dot-common
|
||
source: { type: git, url: "{gitea}/.common" }
|
||
target: "{projects_dir}/.common"
|
||
health_check: "test -f {target}/scripts/claude-switch.ps1"
|
||
|
||
- name: projects-meta-mcp
|
||
# Subdirectory of .common repo — no standalone git source
|
||
target: "{projects_dir}/.common/lib/projects-meta-mcp"
|
||
deps: [dot-common]
|
||
setup_skill: setup-projects-meta
|
||
health_check: "mcp_tool_available mcp__projects-meta__meta_status"
|
||
|
||
- name: dot-wiki
|
||
target: "{projects_dir}/.wiki"
|
||
deps: [projects-meta-mcp]
|
||
setup_skill: setup-wiki
|
||
health_check: "test -f {target}/CLAUDE.md && test -f {target}/index.md"
|
||
|
||
- name: claude-skills
|
||
source: { type: git, url: "{gitea}/claude-skills" }
|
||
target: "{projects_dir}/claude-skills"
|
||
post_install: "bash {target}/scripts/install.sh"
|
||
health_check: "test -d ~/.claude/skills/project-bootstrap"
|
||
```
|
||
- Команды: `factory install`, `factory update`, `factory status`, `factory diagnose <name>`.
|
||
- Идемпотентность по health-check'у — re-run = no-op.
|
||
|
||
**L2 — `setup-*` skills остаются.** Factory триггерит через печать инструкции пользователю до тех пор, пока не появится программный slash-command-bridge (см. Q3).
|
||
|
||
### Что закрывает каждое требование
|
||
|
||
| Требование | Решение |
|
||
|---|---|
|
||
| `~/projects` в произвольном месте | `{projects_dir}` substitution в manifest, источник — `home.toml` |
|
||
| Произвольное имя папки | То же; manifest нигде не хардкодит "projects" |
|
||
| Несколько папок на одной машине | Профили в `home.toml`; флаг `--profile` |
|
||
| Cross-platform | L0 — два нативных скрипта; L1 — single-file бинарь под Win/Mac/Linux; L2 — уже работает |
|
||
| Частичные / устаревшие установки | health_check на каждый компонент; `factory status` показывает дельту; `factory update` чинит |
|
||
| Multi-vendor | `client` в `home.toml`; manifest-компоненты помечены `clients: [claude-code, copilot-cli]` |
|
||
|
||
### Anti-recommendations
|
||
|
||
- Один монолитный bash/ps скрипт без manifest'а — за год превратится в legacy.
|
||
- Python-orchestrator с pip-зависимостями — сам требует bootstrap'а python (chicken-and-egg).
|
||
- Повторять логику установки в L0 и L2. health_check — single source of truth.
|
||
- Складывать `factory` в `claude-skills/` — фабрика > tooling; claude-skills должен быть **компонентом** manifest'а.
|
||
|
||
## Решённые вопросы
|
||
|
||
### Q1 — runtime для L1: Go
|
||
|
||
Главные аргументы: размер бинаря (5–10 МБ vs 80–100 МБ Deno), старт ~5 мс, тривиальная кросс-компиляция (включая Win/macOS ARM), `go-git/go-git` снимает зависимость от системного git, cobra даёт shell-completion из коробки.
|
||
|
||
Стек: Go 1.23+, `go-git/go-git`, `goccy/go-yaml`, `spf13/cobra`, опционально `charmbracelet/lipgloss`. Поставка — pre-built бинари в `.factory/dist/`, скачиваются L0b.
|
||
|
||
Контраргументы (Deno/Rust/Bun) отброшены: Deno слишком жирный для curl-pipe, Rust learning curve не оправдывает экономию 5 МБ, Bun на Windows ARM ещё не дозрел.
|
||
|
||
### Q6 — toolchain layer в L0: `mise` поверх системного pkg-mgr
|
||
|
||
L0a: системный pkg-mgr (winget/brew/apt) → ставит git + curl + mise → mise ставит node/python/go/rust.
|
||
|
||
Опциональный интерактивный слой: Claude Code, Cursor, VS Code, Ollama, Docker Desktop.
|
||
|
||
Не отдельные nvm + pyenv + goenv — у каждого свой bootstrap, mise унифицирует. Не свой пакет-менеджер — winget/brew/apt уже стоят на любой целевой ОС.
|
||
|
||
### Q8 — fresh-enterprise bootstrap (greenfield-mode)
|
||
|
||
`factory` должен уметь поднимать **пустое предприятие** — не только клонировать существующие гитеа-репы (clone-mode), но и **скаффолдить шесть мета-репо из встроенных templates**. Use case: новый юзер хочет повторить эту ERP-архитектуру в своём gitea/github namespace.
|
||
|
||
Что уже покрыто greenfield'ом (повторно использовать): `setup-wiki`, `setup-tasks`, `project-bootstrap`.
|
||
|
||
Что не покрыто (нужны новые скаффолды):
|
||
1. **Корневые мета-репо** — `.common/`, `.meeting-room/`, `.organization/`, `.templates/`, claude-skills-fork.
|
||
2. `setup-projects-meta` и `setup-interns` ждут готовый source-tree в gitea — нужен **`init`-mode**.
|
||
|
||
Архитектурное предложение — добавить в `factory.yaml` per-component `clone-or-init`-источник:
|
||
```yaml
|
||
components:
|
||
- name: dot-common
|
||
source:
|
||
type: clone-or-init
|
||
url: "{gitea}/common" # сперва пробуем clone
|
||
template: "{factory}/templates/enterprise/common" # fallback — scaffold + init+push
|
||
```
|
||
И команда `factory init <enterprise-name> --git-host <url>`.
|
||
|
||
**Anti-recommendation:** не пытаться bootstrap'ить сам git-host (gitea/forgejo/github). Factory ожидает, что писательский git-сервер уже существует.
|
||
|
||
Цена: +1 папка `templates/enterprise/<repo>/` (6 скелетов) + per-component поле `source.template:`. ~неделя на скелеты + ~3 дня на `clone-or-init` логику.
|
||
|
||
Не блокирует v0; реализуется параллельно после v0 production-deploy.
|
||
|
||
## Открытые вопросы (deferred за v0)
|
||
|
||
- **Q2 — где живёт каноничный manifest в production:** в `.factory/factory.yaml` (один на машину) или в shared Gitea с per-machine override? Склонение: "default в `.factory/` репе, override через `~/.config/factory/home.toml#overrides`".
|
||
- **Q3 — slash-command-bridge для L2:** ждать программное API от вендоров, или поднять свой через MCP-сервер `factory-mcp` (`factory_install`, `factory_status`)?
|
||
- **Q4 — версионирование manifest'а:** semver на `factory.yaml` сам? Или per-component pinned `name@v1.2.3` (npm/cargo style)?
|
||
- **Q5 — secrets:** где хранятся токены в multi-machine setup? Сейчас ad-hoc в `.common/secrets/` и `~/.config/projects-mcp/auth.toml`.
|
||
- **Q7 — access control / discoverability** (deferred to v2): иерархия видимости компонентов (`public` / `internal` / `secret`). В v0 — все `public`, secrets живут только в `.common/secrets/` с `.gitignore`.
|
||
- **Q9 — переименование `claude-skills` → `.skills`** (deferred): репо стилистически выпадает из dotfile-конвенции флота. Scope: только git-имя репо в gitea + cloned dir name. Local runtime path `~/.claude/skills/` остаётся (hardcoded в Claude Code). Когда поднимать: при дизайне `factory.yaml` v0.2 / `templates/enterprise/<repo>/`.
|
||
|
||
## v0 plan — live bootstrap нового ноута как field-test (выполнено 2026-05-06)
|
||
|
||
Stop-condition: не сидеть в чистом дизайне до победного — у пользователя есть свежая машина, на ней проверяем дизайн руками.
|
||
|
||
Алгоритм:
|
||
1. Узнать ОС нового ноута.
|
||
2. Бутстрапить пошагово, я директирую каждую команду.
|
||
3. Каждая команда логгируется в `.factory/L0/install-log.md` — сырьё для будущих `bootstrap.ps1` / `bootstrap.sh`.
|
||
4. После end-to-end успеха — формализуем log в скрипты.
|
||
5. Только после field-test'а — за L1 (Go-бинарь и `factory.yaml`).
|
||
|
||
## Field-test results — 2026-05-06
|
||
|
||
End-to-end на новом Win11 ноуте отработал. Полный лог — `.factory/L0/install-log.md` (этот же репо).
|
||
|
||
| Шаг | Что | Статус |
|
||
|---|---|---|
|
||
| L0a | mise + системный pkg-mgr (winget) | ✅ first-pass |
|
||
| L0b | clone `factory`, инициализация `~/.config/factory/home.toml` | ✅ |
|
||
| 11a | clone `claude-skills`, 21 скил доступен через `Skill` тул | ✅ |
|
||
| 11b | `claude login` + плагины `superpowers@claude-plugins-official` + `context7@claude-plugins-official` | ✅ (manual, browser-redirect) |
|
||
| 11c.1 | `setup-interns` — MCP-сервер, секреты в `.common/secrets/interns.env` | ✅ |
|
||
| 11c.2 | `setup-projects-meta` — repo + wiki clone + MCP entry + initial sync | ✅ idempotent re-run (всё уже было — скил детектил наличие и пошёл по path «update + verify») |
|
||
| 11c.3 | context7 sanity (`resolve-library-id "react"` → 5 matches) | ✅ |
|
||
| Фикстуры | `.organization/`, `.templates/`, `.meeting-room/` склонированы | ✅ |
|
||
|
||
**Что подтвердилось:**
|
||
|
||
1. **Q1 (Go для L1) валидно** — текущий L0 на mise+winget хорошо ложится в манифест, runtime-зависимостей сверху не нужно.
|
||
2. **Q6 (mise поверх системного pkg-mgr)** — отработало без сюрпризов. Mise успешно поставил node/python.
|
||
3. **`setup-projects-meta` idempotency-логика** — корректно различил «fresh install» vs «update+verify». В bootstrap.ps1 повторить.
|
||
4. **Plugin-route для context7** — правильное решение (legacy `setup-context7` скил не запускался, конфликта нет).
|
||
|
||
**Gap'ы / кандидаты для bootstrap-скрипта** (полный список — в `install-log.md`):
|
||
|
||
- 11b принципиально не автоматизируется (требует браузер-redirect / device-code) — bootstrap.ps1 должен **парковаться** здесь и ждать пользователя.
|
||
- Порядок 11c-скилов критичен: `interns` → `projects-meta` → плагины (или их sanity) → фикстуры. Это контракт скрипта, не выбор пользователя.
|
||
- Каждый setup-* скил уже идемпотентен — bootstrap может звать их без проверки «надо ли». Но pre-check блок самого скрипта (есть ли git, mise, claude, плагины) обязан быть.
|
||
|
||
## Источник
|
||
|
||
Промоушн брейнсторма из `.meeting-room/.archive/2026-05-06-factory-bootstrap.md`. Участники: user, claude-cso. Старт: 2026-05-06.
|