diff --git a/.tasks/STATUS.md b/.tasks/STATUS.md index 1d9137b..142cf89 100644 --- a/.tasks/STATUS.md +++ b/.tasks/STATUS.md @@ -724,7 +724,7 @@ Pattern для починки уже отработан в `setup-projects-meta` --- -## ⚪ [meta-isolation-bootstrap-skill-update] — Обновить `project-bootstrap` skill чтобы для своих новых проектов он создавал локальный `.gitignore` с `!`-инверсиями мета-путей. Без обновления любой новый bootstrap'нутый проект ломается сразу: `.tasks/`, `.wiki/`, `.claude/` создаются, но git их не видит из-за глобального `core.excludesFile`, и в первый коммит они не попадают. +## 🟢 [meta-isolation-bootstrap-skill-update] — Обновить `project-bootstrap` skill чтобы для своих новых проектов он создавал локальный `.gitignore` с `!`-инверсиями мета-путей. Без обновления любой новый bootstrap'нутый проект ломается сразу: `.tasks/`, `.wiki/`, `.claude/` создаются, но git их не видит из-за глобального `core.excludesFile`, и в первый коммит они не попадают. **Источник:** `.workshop/.wiki/concepts/meta-out-of-repo.md` — секции «Слой 2» и «Новые проекты». @@ -761,10 +761,11 @@ Pattern для починки уже отработан в `setup-projects-meta` **Не делать:** не клади инверсии безусловно, без проверки что цель — свой репо. В чужих форках это потенциально создаст расхождение с upstream'ом (новый файл в `.gitignore`). Если bootstrap отрабатывает только для своих новых проектов — этот edge-case не релевантен; уточнить в коде скила. -**Status:** ready -**Where I stopped:** (not started) -**Next action:** Прочитать текущий `project-bootstrap` SKILL.md (`~/projects/claude-skills/skills/project-bootstrap/SKILL.md`) чтобы понять структуру шагов и где встроить запись `.gitignore`. Добавить шаг после `git init`. MINOR-bump в frontmatter version. Тестовый run на greenfield: `mkdir /tmp/test-bootstrap && cd /tmp/test-bootstrap && /project-bootstrap` (или эквивалент через агента) → проверить acceptance. Коммит: `feat(skills): project-bootstrap adds local meta-paths inversions for own projects`. -**Branch:** n/a +**Status:** done +**Where I stopped:** v1.11.0 shipped + installed. Template carries meta-isolation block; SKILL.md Step 1 documents greenfield (template) + upgrade-case marker-append. Smoke test on `%TEMP%\test-bootstrap-meta-iso` passed all 3 acceptance + negative control + idempotency. Wiki: `concepts/project-bootstrap-meta-isolation.md` + index + log entries. +**Next action:** (closed) +**Branch:** master + --- diff --git a/.wiki/concepts/project-bootstrap-meta-isolation.md b/.wiki/concepts/project-bootstrap-meta-isolation.md new file mode 100644 index 0000000..2aebaad --- /dev/null +++ b/.wiki/concepts/project-bootstrap-meta-isolation.md @@ -0,0 +1,36 @@ +--- +title: project-bootstrap meta-isolation block +type: concept +updated: 2026-05-10 +--- + +# project-bootstrap meta-isolation block + +`project-bootstrap` v1.11.0 ships a meta-isolation block in the local `.gitignore` it creates / appends. Block contains `!`-inversions for `.claude/`, `.tasks/`, `.wiki/`, `.brainstorm/`, `.archive/`, `.mcp/`, `.mcp.json`, `MEMORY.md`. + +## Why + +The global `core.excludesFile` (`~/.config/git/ignore`) hides agent meta-paths from forks of upstream open-source — see workshop wiki `concepts/meta-out-of-repo.md` (sections "Слой 2", "Новые проекты"). Without slой 2 in own repos, `setup-wiki` / `setup-tasks` / Step 5 produce `.wiki/`, `.tasks/`, `CLAUDE.md`, but git ignores them and the bootstrap commit lands empty of obvyaska. Empirically reproduced before the fix; smoke test in `assets/.gitignore.template` greenfield confirms. + +## In-skill design choices + +- **Marker comment** — `# AI обвеска — слой 2:` (case-sensitive substring) used to detect the block on upgrade-case append. Comment text matches workshop wiki concept; chosen over checking for `!.tasks/` line because users may add their own ad-hoc `!`-rules unrelated to this block. +- **Append-only on upgrade** — never rewrite or reorder existing `.gitignore`. Same discipline as Step 5's CLAUDE.md merge (idempotent, append missing). +- **Block applied unconditionally in current modes.** Bootstrap's three modes (greenfield-full, add-remote, upgrade) all assume the user owns the repo. Greenfield-full creates a fresh Gitea repo; add-remote and upgrade operate on user repos. There is no fork-of-upstream mode today — if added, the block must be omitted there (putting `!.claude/` into a fork's `.gitignore` would diverge from upstream's ignore semantics). +- **Template change is the load-bearing edit** — greenfield projects pick up the block by template copy. Upgrade-case append handles existing repos that bootstrapped before v1.11.0 (or were created without bootstrap). + +## Acceptance proven + +Smoke test on greenfield (`%TEMP%\test-bootstrap-meta-iso`): + +1. `.gitignore` from template contains the block — ✓. +2. `.tasks/_smoke.md` shows as untracked in `git status` — ✓. +3. First-commit candidate set includes `.tasks/`, `.wiki/`, `.claude/`, `.brainstorm/`, `MEMORY.md` — ✓. +4. Negative control — strip block, status hides all meta-paths (only `.gitignore` itself remains visible). Confirms global excludesFile is the cutter and slой 2 is what restores visibility — ✓. +5. Upgrade-case append idempotent — second run with marker present skips — ✓. + +## Pointers + +- Source concept: `~/projects/.workshop/.wiki/concepts/meta-out-of-repo.md` +- Sister action-item: `[meta-isolation-existing-repos-migration]` in `OpeItcLoc03/workshop` — one-off migration of existing own repos. +- Long-term: `[meta-isolation-mcp-sync-extension]` in `OpeItcLoc03/common` — extend `projects-meta-mcp` to sync `.wiki/` + `.claude/skills/` so meta-paths can leave repo entirely. diff --git a/.wiki/index.md b/.wiki/index.md index bb53d6b..3ad284f 100644 --- a/.wiki/index.md +++ b/.wiki/index.md @@ -36,6 +36,7 @@ Catalog of all wiki pages. One line per page, organized by type. Updated on ever - [interns-repo-read-design](concepts/interns-repo-read-design.md) — interns-repo-read-design - [hermes-skills-rollout-design](concepts/hermes-skills-rollout-design.md) — hermes-skills-rollout-design - [tdd-criteria-design](concepts/tdd-criteria-design.md) — tdd-criteria-design +- [project-bootstrap-meta-isolation.md](concepts/project-bootstrap-meta-isolation.md) — project-bootstrap@1.11.0 — Step 1 ships meta-isolation block in `.gitignore` (`!.claude/`, `!.tasks/`, `!.wiki/`, ...) so own greenfield/upgrade projects re-enable agent meta-paths against global `core.excludesFile` cutter. Marker-based append-only on existing files; smoke-tested with negative control ## Packages diff --git a/.wiki/log.md b/.wiki/log.md index 2ddcd23..ba19b4b 100644 --- a/.wiki/log.md +++ b/.wiki/log.md @@ -55,3 +55,5 @@ Parseable: `grep "^## \[" .wiki/log.md | tail -20`. ## [2026-05-07] ingest | concepts/tdd-criteria-design ## [2026-05-07] review | tdd-criteria v0.2.0 — 4 findings applied: trigger-loophole fix (removed session-authorship clause), composite-tasks + refactoring sections, expanded file-extension list, clarified wrapper line-count + spike-survivor fallback + foreign-schema fix; design doc synced + +## [2026-05-10] decision | project-bootstrap-meta-isolation — v1.11.0 ships meta-isolation block in `.gitignore` template + Step 1 upgrade-case append; restores agent meta-paths visibility against global `core.excludesFile`; smoke-tested greenfield + negative control + idempotency diff --git a/skills/project-bootstrap/SKILL.md b/skills/project-bootstrap/SKILL.md index c8c9fae..f4a605f 100644 --- a/skills/project-bootstrap/SKILL.md +++ b/skills/project-bootstrap/SKILL.md @@ -1,6 +1,6 @@ --- name: project-bootstrap -version: 1.10.1 +version: 1.11.0 description: > Initializes or upgrades a project in the current folder: git, .gitignore, README.md, .wiki/ using Karpathy's method, .tasks/ for task tracking, CLAUDE.md with skill triggers. @@ -61,8 +61,37 @@ If git is not initialized: git init ``` -If `.gitignore` does not exist — create from template `assets/.gitignore.template`. -If it exists — leave it untouched. +### `.gitignore` + +The template `assets/.gitignore.template` contains two parts: + +1. Standard ignore rules (deps, build, env, IDE, OS, logs). +2. **Meta-isolation block** — `!`-inversions for `.claude/`, `.tasks/`, `.wiki/`, + `.brainstorm/`, `.archive/`, `.mcp/`, `.mcp.json`, `MEMORY.md`. This block + re-enables tracking of agent meta-paths in **own** repos against the + global `core.excludesFile` rule (`~/.config/git/ignore`) that hides them + from forks of upstream open-source. Without it, the `.tasks/`, `.wiki/`, + and `.claude/` directories created by Steps 3-5 would be invisible to git + on machines where the global excludesFile is configured, and the first + commit would be empty of agent obvyaska. Full design: workshop wiki + `concepts/meta-out-of-repo.md` (sections "Слой 2" and "Новые проекты"). + +Two cases: + +- **`.gitignore` does not exist** — create from `assets/.gitignore.template` + (block included unconditionally). +- **`.gitignore` exists** — check for the marker line + `# AI обвеска — слой 2:` (substring match, case-sensitive). If absent → + append the meta-isolation block (with the marker comment) to the end of + the file, prefixed by a blank line if the file does not already end with + one. If present → leave the file untouched. + +The block is **scoped to own projects**. The bootstrap skill currently has no +fork-of-upstream mode (greenfield-full creates a brand-new Gitea repo; +add-remote and upgrade operate on the user's own repos), so the block is +applied unconditionally in all current modes. If a fork-bootstrap mode is +ever added, the block must be **omitted** there — putting `!.claude/` etc. +into a fork's `.gitignore` would diverge from upstream's ignore rules. --- diff --git a/skills/project-bootstrap/assets/.gitignore.template b/skills/project-bootstrap/assets/.gitignore.template index de37d73..7869f4f 100644 --- a/skills/project-bootstrap/assets/.gitignore.template +++ b/skills/project-bootstrap/assets/.gitignore.template @@ -27,3 +27,14 @@ Thumbs.db # Logs *.log logs/ + +# AI обвеска — слой 2: переопределяем глобальный ~/.config/git/ignore +# для своих репо (см. global wiki concept meta-out-of-repo) +!.claude/ +!.tasks/ +!.wiki/ +!.brainstorm/ +!.archive/ +!.mcp/ +!.mcp.json +!MEMORY.md