Files
factory/.wiki/concepts/factory-bootstrap.md
vitya cb9f6b033d fix(factory.yaml): v0.2.0 — interns-mcp + projects-meta-mcp as subdirs of .common, not standalone repos
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>
2026-05-07 13:52:45 +03:00

212 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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__*` | живой, 1314 страниц |
| 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
Главные аргументы: размер бинаря (510 МБ vs 80100 МБ 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.