refactor(skills): retrofit the corpus to the ADR-0020 context contract (#129)

Retrofits all 39 skills to ADR-0020's description/body context contract, then fixes what six rounds of independent review found in that retrofit — including four ways the hot gate itself failed open.

Closes #99, #107, #108, #110, #111, #114, #115, #120.

## The retrofit (waves 1-5)

| | Start | Now |
|---|---|---|
| Description FAILs (>400 chars) | 26 | **0** |
| Body FAILs (>900 words, body-only) | 9 | **0** |
| Dangling routing targets | 2 | **0** |
| `Kyberforge.CompositionNote` | 10 | **0** |
| Preload tax | 21,005 chars | **~10,500** |

Under the 12,000-char success criterion. Per-wave detail is on #99.

## The review fixes

**The gate failed open four ways, three of them found after the retrofit shipped.** An unrecognised follower token made a dangling target vanish. A skill directory with no `SKILL.md` resolved as a valid target, so a commit could be green locally and red in a fresh clone — three existing fixtures were relying on that, one of which made the install-leak A/B pass vacuously. Then the free-standing `/name` sweep turned out to be gated on the sentence carrying a boundary marker, so route notation in any other sentence was invisible — not an ERROR, not a SUGGESTION, not an INFO — which left the documented "`/name` always blocks" promise false from a second direction. All four fixed and pinned.

**Two checks were silently not running.** `validate-provenance.sh` checks 7-8 were dead across nine skills. Waking them exposed a deeper problem: they assume `Research doc:` names a source index, but 30 of 121 entries point at topic content documents, so every new check-7 INFO was a false positive and check 8 was saved from a false-FAIL flood only by an *unannounced* skip. Checks 7/8 are now scoped to source indexes and every skip announces itself (#121).

**The retrofit's own anti-goal, four times.** ADR-0020 warns that a blunt gate gets satisfied by deleting content rather than relocating it. `diagnose` and `skill-audit` relocated prose and then read it unconditionally; `prototype` and `vale-config` deleted rules outright that survived nowhere. All four addressed.

## Verification

- `bash tests/run-tests.sh --strict` — 24 suites, 0 skipped, 0 failed
- `bash tests/run-bats.sh` — 325 tests, 0 failures
- `pre-commit run --all-files` — 17/17
- `pre-commit run --hook-stage pre-push --all-files` — 16/16, with `apm marketplace check` and `apm pack --check-clean` run against the remote, not skipped
- `scripts/skill-size-check.sh` over all 39 skills — rc 0, 0 ERROR/FAIL, SUGGESTION-only
- Preload tax measured at **10,498 chars**, max description 390 — both inside budget
- Every new test proven non-vacuous by a deliberate mutation of the behaviour it covers

**Per-commit sync, stated accurately:** the ten commits from the latest review round each pass `check-plugin-content-sync` in isolation, verified by checking each out in a detached worktree with a clean between. The earlier gitea window (`dfacf05..bedbd1d`, nine commits) does **not** — its mirror was regenerated in one batch at `bbc7300`. An earlier revision of this description claimed the property held for every commit; it does not, and a bisect through that window lands on a red commit. **Squash-merge** to collapse it, or accept that this range is not bisectable.

## Version bump

Six plugins and the catalog take a **patch**, not a minor. The branch is **89 commits — 40 `fix` / 30 `refactor` / 12 `docs` / 5 `chore` / 2 `test` — zero `feat`, zero `!`, zero `BREAKING CHANGE`** — and adds no skill, agent, command or hook. (Two earlier revisions of this section cited a stale histogram, most recently 78 commits; the figures above are measured at HEAD.) Both rules this repo ships (`forge/references/version-bump.md`, landing in this PR, and `git-commits/references/conventional-commits-spec.md`) make that a patch, and the catalog set is unchanged at 7 entries.

Not settled by that: four published files were removed from the installed tree, three moved, and `caveman` gained `disable-model-invocation`, retiring its old triggers. Under a strict reading those are major-class and currently ship under `refactor:` with no marker. Whether the deployed skill surface is a public contract is written down nowhere — worth deciding, but it outlives this PR.

## Deliberately not in scope

#112 (cherry-pick ownership, now resolved in favour of `git-commits`), #113 (`rtk git` normalisation), #116 (research fan-out), #101 (audit-skill merge), #122 (non-spec skill-root files), #123 (no PRD producer) stay open. #117 is the one worth reading: the contract's remedy is to move prose into `references/`, which is exactly where neither the size gate nor Vale looks — and the blind spot is wider than #117 currently records, since there is no root `.vale.ini` at all, so every ADR, `CONTEXT.md` and `README.md` is unlinted too.

That blind spot let this branch carry two `level: error` `Kyberforge.SentenceOpenerThereIs` violations into `references/` files it created — `provider-adapter-author/references/provider-matrix.md:31` and `agent-audit/references/finding-criteria.md:95`. Both are reworded in `afadaae`, confirmed by routing each file through the audit's own `vale-wrap.sh` (1 error each before, 0 after). Five further occurrences sit in `references/` files already on `main`; those are the pre-existing corpus and stay with #117, which is the real fix.

Also unfixed and not this PR's: `apm install` appends a duplicate `SessionStart` entry to `.claude/settings.json`, so a fresh clone cannot get pre-push green without an edit AGENTS.md warns against. Reproduces identically on `main`.

Co-authored-by: Defame1297 <gitea@rkdr.net>
Reviewed-on: https://git.dev.rkdr.net/Defame1297/holocron/pulls/129
Co-authored-by: Claude Code AI - Gitea MCP <claude@noreply.git.dev.rkdr.net>
Co-committed-by: Claude Code AI - Gitea MCP <claude@noreply.git.dev.rkdr.net>
This commit was merged in pull request #129.
This commit is contained in:
Claude Code AI - Gitea MCP
2026-09-01 13:47:46 +00:00
committed by Defame1297
parent 0e91a3ae66
commit 598a7c326a
420 changed files with 15303 additions and 4740 deletions

View File

@@ -4,7 +4,7 @@ Manage git worktrees to enable multi-branch parallel development across isolated
## What it does
This skill handles worktree operations within the git workflow suite. It creates, lists, locks/unlocks, moves, removes, prunes, and repairs worktrees — letting an agent work on multiple branches simultaneously without stashing. It returns structured results (paths, branches, lock status) suitable for agent composition.
This skill handles worktree operations within the git workflow suite. It creates, lists, locks/unlocks, moves, removes, prunes, and repairs worktrees — letting an agent work on multiple branches simultaneously without stashing. It returns structured results (paths, branches, lock status) suitable for agent composition. For multi-step flows spanning branch strategy plus worktree setup, `git-workflow` handles the broader orchestration and delegates the worktree mechanics here.
## Usage
@@ -18,7 +18,7 @@ Describe your worktree task: create a worktree for a branch, list existing workt
| File | Purpose |
|------|---------|
| `SKILL.md` | Skill instructions for agents |
| `SKILL.md` | Dispatch table, per-operation gates, and the report format |
| `references/README.md` | Describes the references directory contents |
| `references/worktrees.md` | Full `add` flag table, sparse-checkout, removable-media locking, remote disambiguation, configuration |
| `references/worktrees.md` | Read when an operation needs more than the dispatch table: shared vs. per-worktree state, the `add` command forms, the full `add` flag table, orphan branches, sparse-checkout, removable-media locking, remote disambiguation, where to run `repair` from, config keys, and the emergency-fix and PR-review patterns |
| `references/sources.md` | Research sources and provenance |

View File

@@ -2,11 +2,10 @@
name: git-worktrees
description: >
Manage Git worktrees to enable multi-branch parallel development across isolated directories.
Use when the user needs to work on multiple branches simultaneously without stashing, switch between feature/hotfix/experimental work, or coordinate code reviews alongside ongoing development.
Handles creation, listing, locking, moving, removal, pruning, and repair of worktrees.
Provides structured results (paths, branches, lock status) for agent composition in git orchestration workflows.
Do not use when only inspecting a single branch or when the user needs standard checkout/stash workflows.
Use when working on several branches at once without stashing —
manages the full lifecycle of a git worktree.
Not ordinary branch switching or checkout -> `git-branches`.
Not interactive multi-step git guidance -> `git-workflow`.
metadata:
category: git
@@ -14,101 +13,45 @@ metadata:
- git-scm-worktree-docs
---
## Concept
A worktree lets you check out multiple branches simultaneously from one repository, each in its own directory. All worktrees share the same objects, config, and most refs (`refs/`). Each worktree has its own `HEAD`, index, and per-worktree metadata (`ORIG_HEAD`, `MERGE_HEAD`, `refs/bisect/`, `refs/worktree/`, `refs/rewritten/`) stored at `$GIT_DIR/worktrees/<name>/`. The **main worktree** (from `git init`/`git clone`) is exactly one per repo and cannot be removed; **linked worktrees** are the additional ones created via `git worktree add`.
## Gotchas
- **A branch can only be checked out in one worktree at a time.** Attempting `git worktree add` for an already-checked-out branch fails unless you pass `--force`. Use `--force` only when intentional.
- **Submodules are unsupported and block operations.** Repos with submodules have incomplete worktree support. Worktrees containing submodules cannot be moved and require `--force` to remove.
- **Never manually `rm -rf` a worktree directory.** This leaves stale metadata in `$GIT_DIR/worktrees/`. Always use `git worktree remove`. If already deleted, run `git worktree prune` to clean up.
- **Manual moves break bidirectional pointers.** If a worktree directory is moved outside of `git worktree move`, run `git worktree repair` to fix connections.
- **Force-flag escalation with locks.** Removing or moving a locked worktree requires `-ff` (two flags), not just `-f`.
- **Worktree identification is by full path, unique basename, or unique partial path.** Ambiguous names error. Use `git worktree list` to see available identifiers.
- **`--lock` on `add` is atomic; create-then-lock has a race window.** Use `--lock` directly on `git worktree add` when consistency matters.
- **`extensions.worktreeConfig = true` is a one-way door.** It enables per-worktree config (`git config --worktree ...`) but makes the repo refuse to open in older Git versions. Once set, `core.bare`/`core.worktree` must live in `config.worktree`, not `config`. Don't enable it unless per-worktree config is actually needed.
- **A branch can be checked out in only one worktree at a time.** `git worktree add` on an already-checked-out branch fails; `--force` is the only override, so use it only deliberately.
- **Never `rm -rf` a worktree directory.** That strands metadata in `$GIT_DIR/worktrees/`. Use `git worktree remove`, or `git worktree prune` afterwards.
- **Submodules break worktree support.** A worktree containing submodules cannot be moved at all, and needs `--force` to remove.
- **`extensions.worktreeConfig = true` is a one-way door.** Without it, `git config --worktree` errors; with it, that flag writes to the worktree's own `config.worktree` file, and `core.bare`/`core.worktree` are forced there too. It also breaks older Git. Leave it off unless per-worktree config is needed.
## Common Operations
## Step 1 — Dispatch
**Create and switch to a new worktree** — default approach:
```bash
git worktree add -b <new-branch> <path>
cd <path>
```
This creates a new branch and checks it out in a new directory. Other branches cannot be checked out elsewhere simultaneously.
| Operation | Run |
|---|---|
| Create on a branch that already exists locally | `git worktree add <path> <branch>` |
| Create on a new branch | `git worktree add -b <branch> <path>` |
| Create on the branch named after the path basename | `git worktree add <path>` — checks that branch out if it exists, else creates it from HEAD |
| Create and reset an existing branch to HEAD — discards its commits | `git worktree add -B <branch> <path>` |
| Create a local branch tracking a remote one | `git worktree add --track -b <branch> <path> <remote>/<branch>` — always correct. `git worktree add <path> <branch>` expands to exactly this, but **only** under the conditions in `references/worktrees.md` |
| Throwaway experiment, no branch | `git worktree add -d <path>` — detached HEAD |
| **Never** `git worktree add <path> <remote>/<branch>` | That ref resolves, so the shortcut never fires and you get **a detached HEAD, no branch, no upstream**. Commits there go unreachable once HEAD moves, and `git push` needs an explicit refspec. Use the tracking row above |
| List | `git worktree list -v`, or `--porcelain -z` to parse |
| Lock or unlock | `git worktree lock [--reason <str>] <path>` / `git worktree unlock <path>` |
| Move | `git worktree move <from> <to>` |
| Remove | `git worktree remove <path>` |
| Prune stale metadata | `git worktree prune --dry-run`, then without the flag |
| Repair after a manual move | `git worktree repair` — in the main worktree if *it* moved, or inside a linked worktree that moved. `git worktree repair <path>...` — from any worktree, naming each moved linked worktree's new path |
**Create-or-reset a branch**: `git worktree add -B <branch> <path>` — like `-b` but resets the branch to HEAD if it already exists.
If the operation needs anything the table does not carry — the full `add` flag
table, orphan branches, sparse-checkout, locking for removable media, remote
disambiguation across several remotes, how to name a worktree unambiguously,
worktree config keys, or the worked emergency-fix and PR-review patterns — read
`references/worktrees.md`.
**Create a worktree for an existing remote branch**:
```bash
git worktree add <path> <remote>/<branch>
```
For ambiguous names across remotes, disambiguate via `checkout.defaultRemote` config or `--guess-remote`. Full flag table and detail: `references/worktrees.md`.
Gates:
**Throwaway experiment in detached HEAD**:
```bash
git worktree add -d ../experiment # or --detach
# experiment freely, no branch created
git worktree remove ../experiment
```
- **`move`, `remove` — the main worktree cannot be moved or removed.** Only linked worktrees, the ones `git worktree add` created, are candidates.
- **`add`, `move`, `remove` — escalate force flags one step at a time.** `-f` overrides a safeguard such as an unclean tree; `move` and `remove` need `-ff` on top of that when the worktree is locked. Confirm with the user before either — both discard state.
- **`add` — lock at creation, not after.** `git worktree add --lock` is atomic, where add-then-`lock` leaves a window in which the worktree is unprotected.
**List all worktrees with state**:
```bash
git worktree list -v # human-readable with lock/prune reasons
git worktree list --porcelain -z # machine-readable, NUL-terminated
```
## Step 2 — Report
**Move a worktree to a new path**:
```bash
git worktree move <current-path> <new-path>
# Cannot move: main worktree, worktrees with submodules
# To override safeguards: -f; to override locked state too: -ff
```
**Remove a worktree**:
```bash
git worktree remove <path> # only if clean
git worktree remove -f <path> # force-remove unclean
git worktree remove -ff <path> # force-remove even if locked
```
**Prune stale metadata**:
```bash
git worktree prune --dry-run # preview what would be removed
git worktree prune # clean up orphaned metadata
```
Also triggered by `git gc`, controlled by `gc.worktreePruneExpire` config.
**Repair broken connections** (after a manual move):
```bash
git worktree repair # from main worktree or after it was moved
git worktree repair <path> # reconnect a specific linked worktree
```
Sparse-checkout worktrees, locking for removable media, the full `add` flag table, and the config key reference: `references/worktrees.md`.
## Worked Examples
**Emergency fix without disrupting current work** — no stashing needed, ongoing work in the main worktree is untouched:
```bash
git worktree add -b emergency-fix ../temp main
cd ../temp
# fix, commit
git commit -a -m "fix: critical production bug"
cd -
git worktree remove ../temp
```
**Review a PR branch alongside your current work** — no context switch, both branches stay checked out:
```bash
git worktree add ../review-pr-123 origin/feature-xyz
# open ../review-pr-123 in a second editor window or terminal
```
## Return Format for Agents
When invoking worktree operations, return structured results:
```yaml
worktrees:
- path: <directory-path>
@@ -116,10 +59,8 @@ worktrees:
commit: <short-hash>
locked: <true/false>
lock_reason: <reason or empty>
- ...
```
Derive these fields from `git worktree list --porcelain -z` — its `worktree`/`branch`/`HEAD`/`locked` lines map directly to `path`/`branch`/`commit`/`locked`+`lock_reason`.
For single operations, include the operation result (e.g., `created: true`, `removed: true`, `moved: true`).
For multi-step flows spanning branch strategy plus worktree setup, compose with the `git-workflow` skill — it handles the broader orchestration, this skill handles the worktree mechanics.
Derive those fields from `git worktree list --porcelain -z`. For a single
operation, report its outcome instead — `created: true`, `moved: true`,
`removed: true`.

View File

@@ -10,4 +10,4 @@ This directory contains provenance metadata and research sources for the `git-wo
## Files
- `sources.md` — Extracted research sources and their contributing documents
- `worktrees.md` — Full `add` flag table, sparse-checkout setup, removable-media locking, remote-branch disambiguation, and the config key reference
- `worktrees.md` — Shared vs. per-worktree state, the `add` command forms, the full `add` flag table, orphan branches, sparse-checkout setup, removable-media locking, remote-branch disambiguation, where to run `repair` from, the config key reference, and the emergency-fix and PR-review workflow patterns

View File

@@ -12,5 +12,5 @@
- **Research doc:** plugins/git/docs/research/docs/git/worktrees.md (whole-document reference — covers `## Concept Overview`, `## Key Commands`, `## Workflow Patterns`, `## Common Gotchas`, `## Configuration`)
**Contributing files:**
- SKILL.md (Concept, Gotchas, Common Operations, Worked Examples, Return Format)
- references/worktrees.md (full `add` flag table, sparse-checkout, removable media, remote disambiguation, configuration)
- SKILL.md (Gotchas, Step 1 dispatch table and per-operation gates, Step 2 report format)
- references/worktrees.md (shared vs. per-worktree state, `add` command forms, full `add` flag table, orphan branches, sparse-checkout, removable media, remote disambiguation, `repair` invocation directory, configuration, workflow patterns)

View File

@@ -4,6 +4,48 @@ source_keys:
- git-scm-worktree-docs
---
# Git worktrees
## Shared vs. per-worktree state
All worktrees share one object store, one config, and most refs under `refs/`. Each worktree keeps
its own `HEAD`, index, and per-worktree metadata (`ORIG_HEAD`, `MERGE_HEAD`, `refs/bisect/`,
`refs/worktree/`, `refs/rewritten/`) under `$GIT_DIR/worktrees/<name>/`. Exactly one **main
worktree** exists per repo — the one `git init` or `git clone` produced — and it cannot be removed
or moved. Every other worktree is a **linked worktree** created by `git worktree add`.
## Identifying a worktree
`lock`, `move`, `remove` and `repair` accept a full path, a unique basename, or a unique partial
path. An ambiguous name errors rather than picking one; `git worktree list` shows the identifiers
that are usable.
## `add` forms
```bash
git worktree add <path> <branch> # <branch> exists locally: check it out — non-destructive
git worktree add -b <branch> <path> # create a new branch; fails if it exists
git worktree add <path> # branch named after $(basename <path>): checked out
# if it exists, else created from HEAD
git worktree add -B <branch> <path> # create the branch, or reset an existing one to HEAD,
# discarding the commits it carried
git worktree add --track -b <branch> <path> <remote>/<branch>
# new local branch tracking the remote — always works
git worktree add <path> <branch> # <branch> absent locally and in exactly one remote:
# Git expands this to the --track -b form above
git worktree add -d <path> # detached HEAD, no branch
```
The same `git worktree add <path> <branch>` spelling appears twice above and does two
different things: it checks out a local branch when one exists, and only otherwise falls
through to the remote-tracking shortcut. Read the local branch list before relying on either.
**Do not write `git worktree add <path> <remote>/<branch>`.** A remote-tracking ref resolves as a
commit-ish, so the tracking shortcut never fires and the worktree lands on a **detached HEAD with
no local branch and no upstream** — commits there go unreachable once HEAD moves or the worktree is
removed, and `git push` fails without an explicit refspec. That spelling is correct only as the
final argument of the `--track -b` form.
## Full `add` flag table
| Flag | Meaning |
@@ -11,7 +53,7 @@ source_keys:
| `-b <branch>` | Create and check out a new branch; fails if it exists |
| `-B <branch>` | Like `-b` but resets the branch if it already exists |
| `-d` / `--detach` | Detach HEAD; useful for throwaway experiments |
| `--orphan` | Create empty unborn branch |
| `--orphan` | Create empty unborn branch — **Git 2.42+**; earlier versions exit 129 with `error: unknown option 'orphan'`. Fallback below |
| `--no-checkout` | Suppress initial checkout (for sparse-checkout setup) |
| `--guess-remote` | Look for a matching remote-tracking branch by path basename |
| `--lock [--reason <str>]` | Lock immediately on creation (atomic; avoids race vs. add-then-lock) |
@@ -25,7 +67,22 @@ Using `-` as `<commit-ish>` is shorthand for `@{-1}` (the branch checked out bef
```bash
git worktree add --orphan -b <branch> <path>
```
Creates an empty branch with no commits.
Creates an empty branch with no commits. **`--orphan` needs Git 2.42 or later** — it was added
upstream in 2.42, and on 2.39.5 this fails with `error: unknown option 'orphan'` and exit 129.
Check `git --version` before reaching for it.
Fallback on older Git, verified on 2.39.5 — detach first, then orphan the linked worktree in place,
which leaves the main worktree on its own branch throughout:
```bash
git worktree add -d <path> # linked worktree, detached HEAD
cd <path>
git switch --orphan <branch> # unborn branch: empty index, empty working tree
```
`git worktree list` then shows the new worktree at `0000000 [<branch>]` until its first commit.
Do not substitute `git switch --orphan` in the *main* worktree: it clears that checkout, which is
the disruption worktrees exist to avoid.
## Sparse-checkout worktree
@@ -48,9 +105,41 @@ git worktree unlock <path> # when reconnected
## Remote-branch disambiguation
```bash
git worktree add <path> <remote>/<branch>
git worktree add --track -b <branch> <path> <remote>/<branch> # explicit: no guessing at all
git worktree add <path> <branch> # shortcut: needs one clear remote
```
For ambiguous names across remotes, `checkout.defaultRemote` config disambiguates explicitly, or `--guess-remote` auto-matches by path basename (default controlled by `worktree.guessRemote` config). If a branch name matches multiple remotes during `worktree add` and neither is set, Git refuses rather than guessing.
**The bare-name shortcut needs exactly one remote.** It fires only when `<branch>` is not found
locally, none of `-b`/`-B`/`--detach` were given, and a tracking branch of that name exists in
exactly one remote. When several remotes carry the name, `checkout.defaultRemote` picks one for
disambiguation purposes; with no such setting the shortcut has no single remote to resolve against
and does not apply. When the remote is ambiguous or unknown, use the explicit `--track -b` form.
`--guess-remote` covers the *other* spelling — `git worktree add <path>` with no `<commit-ish>` at
all. It bases the new branch on the remote-tracking branch matching `$(basename <path>)` when
exactly one remote has it, and marks that branch as upstream. Its default comes from the
`worktree.guessRemote` config.
## Repair after a manual move
```bash
git worktree repair # the MAIN worktree moved: run it there to reconnect every linked
# worktree back to the main worktree
git worktree repair # a LINKED worktree moved: run it inside that recently-moved worktree
git worktree repair <path>... # reconnect a specific linked worktree — runnable from any worktree,
# naming each moved tree's new path
```
Which form applies depends on what moved:
| What moved | Remedy |
|---|---|
| The main worktree (or bare repo) | `git worktree repair` in the main worktree |
| One linked worktree | `git worktree repair` inside that worktree |
| Several linked worktrees | `git worktree repair <path>...` from any worktree, listing each new path |
| Both main and linked worktrees | `git worktree repair <path>...` in the main worktree, naming each linked worktree's new path — this restores the connections in both directions |
Only the no-argument form is tied to the current directory. The `<path>...` form is not — it
reestablishes the connection to every path you name, run from any worktree.
## Configuration
@@ -61,3 +150,29 @@ For ambiguous names across remotes, `checkout.defaultRemote` config disambiguate
| `gc.worktreePruneExpire` | How long before stale worktree metadata is pruned by `git gc` |
| `extensions.worktreeConfig` | Enable per-worktree config scope (`config.worktree` file) — see Gotchas in SKILL.md |
| `checkout.defaultRemote` | Disambiguates which remote to use when a branch name matches multiple remotes during `worktree add` |
## Workflow patterns
**Emergency fix without disrupting current work** — nothing is stashed, and the main worktree is
untouched throughout:
```bash
git worktree add -b emergency-fix ../temp main
cd ../temp
# fix, then commit
git commit -a -m "fix: critical production bug"
cd -
git worktree remove ../temp
```
**Review a PR branch alongside your own work** — both branches stay checked out, so there is no
context switch:
```bash
git worktree add ../review-pr-123 origin/feature-xyz # detached HEAD — read-only review
git worktree add --track -b feature-xyz ../review-pr-123 origin/feature-xyz # if you will commit
# open ../review-pr-123 in a second editor window or terminal
```
Pick the second form the moment you intend to push anything back: the first leaves no branch to
push and no upstream to push to.