Compare commits
13
Commits
095929142f
...
5b80f305e9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b80f305e9 | ||
|
|
8599b4a058 | ||
|
|
ee248ff5a5 | ||
|
|
131b89733b | ||
|
|
dac9cad912 | ||
|
|
e869912374 | ||
|
|
03abcffb77 | ||
|
|
1c3af75642 | ||
|
|
14af50bc07 | ||
|
|
8680adf4c0 | ||
|
|
b07d54ad7a | ||
|
|
27a76692b0 | ||
|
|
db5a426416 |
No files matched your search
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "holocron",
|
||||
"description": "AI development skills for Claude Code and GitHub Copilot CLI — factory, design, implement, review, and cross-cutting workflows.",
|
||||
"version": "0.4.5",
|
||||
"version": "0.5.0",
|
||||
"owner": {
|
||||
"name": "Defame1297",
|
||||
"email": "[email protected]",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "holocron",
|
||||
"description": "AI development skills for Claude Code and GitHub Copilot CLI — factory, design, implement, review, and cross-cutting workflows.",
|
||||
"version": "0.4.5",
|
||||
"version": "0.5.0",
|
||||
"owner": {
|
||||
"name": "Defame1297",
|
||||
"email": "[email protected]",
|
||||
|
||||
@@ -36,7 +36,7 @@ Fall back to raw shell only when no skill covers it.
|
||||
- **Do not add repo-owned keys to `.claude/settings.json`.** apm treats it as its own deployed artifact and `apm audit --ci` replays the install and diffs, so anything apm would not have written is permanent drift that fails the `apm-audit-ci` pre-push hook. A hook you want here is authored in `plugins/<name>/.apm/hooks/` and deployed by apm, never hand-written into that file. The `SessionStart` entry already in it is exactly that: kyberforge authors it in `plugins/kyberforge/.apm/hooks/hooks.json` and apm merges it in, so it is apm's own output, it is what the replay expects, and it belongs in the commit — do not strip it (ADR-0019). Machine-specific settings go in the gitignored `.claude/settings.local.json`; shared enforcement goes in `.pre-commit-config.yaml`.
|
||||
- **`apm.lock.yaml` turning up modified is expected, not a bug.** kyberforge's `SessionStart` hook runs `apm outdated` at startup and `apm update --yes` when something is behind, which rewrites the lock. Commit or discard it deliberately.
|
||||
- **A `.apm/` edit is not live in this session until it is pushed.** The six dependencies resolve from the holocron remote, unpinned against the default branch. `apm install` deploys from the lock; `apm update` is what re-resolves refs.
|
||||
- **The ADR-0020 skill gates ship hot, with no baseline — and the corpus is now clean.** All 39 skills clear both FAIL tiers: no description over 400 characters, no body over 900 words (counted body-only). Issue #99 retrofitted them plugin by plugin — `kyberforge` was the last plugin wave, followed by corpus-wide passes and two rounds of independent audit fixes. Because nothing is grandfathered, the gates now bite on first commit — a new skill, or an edit that pushes a description past 400, is blocked until it complies. **No routing target dangles**, and `tests/test-adr0020-targets.sh` pins that set as empty, so a new boundary clause naming a non-existent skill fails the suite rather than joining a backlog. Two blind spots survive: `skill-size-check` does not cover the Vale half, so `Kyberforge.CompositionNote` fires nowhere today but any new description can reintroduce it; and every `references/` file is unlinted — which matters because the contract's own remedy is to move prose *into* `references/`, out of the prose gate's reach. That blind spot has **two** independent causes and closing either alone changes nothing: the `Kyberforge` style is scoped `[**/SKILL.md]`, *and* the `vale-audit-prefilter-skill` hook filters on `files: '^plugins/[^/]+/\.apm/skills/[^/]+/SKILL\.md$'`, so a reference file is never handed to Vale whatever the style says (#117). Check both gates: `pre-commit run --all-files`.
|
||||
- **The ADR-0020 skill gates ship hot, with no baseline — and the corpus is now clean.** All 39 skills clear both FAIL tiers: no description over 400 characters, no body over 900 words (counted body-only). Retrofitted plugin by plugin under #99 (see `docs/spec/gates.md`). Because nothing is grandfathered, the gates now bite on first commit — a new skill, or an edit that pushes a description past 400, is blocked until it complies. **No routing target dangles**, and `tests/test-adr0020-targets.sh` pins that set as empty, so a new boundary clause naming a non-existent skill fails the suite rather than joining a backlog. Two blind spots survive: `skill-size-check` does not cover the Vale half, so `Kyberforge.CompositionNote` fires nowhere today but any new description can reintroduce it; and every `references/` file is unlinted — which matters because the contract's own remedy is to move prose *into* `references/`, out of the prose gate's reach. That blind spot has **two** independent causes and closing either alone changes nothing: the `Kyberforge` style is scoped `[**/SKILL.md]` (the cause #117 records), *and* the `vale-audit-prefilter-skill` hook filters on `files: '^plugins/[^/]+/\.apm/skills/[^/]+/SKILL\.md$'`, so a reference file is never handed to Vale whatever the style says. Check both gates: `pre-commit run --all-files`.
|
||||
- **Run `bash tests/run-tests.sh --strict` before considering any change done.** Keep the flag: without it a suite whose dependency is missing exits 77 and is counted SKIPPED rather than failed, so the run goes green having verified less than it claims.
|
||||
- **Before pushing, rehearse the gate locally:** `pre-commit run --hook-stage pre-push --all-files`. It runs the 14 pre-push hooks this repo authors itself plus pre-commit's 2 `meta` hooks, so it prints 16; `check-release-needed` passes without checking anything, because it needs a real push to `main`. `docs/spec/gates.md` reconciles both.
|
||||
- **Pushing without a network** needs `SKIP=apm-marketplace-check,apm-pack-check-clean git push` — those two resolve a remote marketplace entry via `git ls-remote`. Skip only those two; the rest are real local checks, and adding one to `SKIP` disarms it silently.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: holocron
|
||||
version: 0.4.5
|
||||
version: 0.5.0
|
||||
description: AI development skills for Claude Code and GitHub Copilot CLI — factory, design, implement, review, and cross-cutting workflows.
|
||||
license: MIT
|
||||
|
||||
@@ -52,7 +52,7 @@ marketplace:
|
||||
# top-level apm.yml description:/version: above are NOT inherited into the
|
||||
# compiled output despite being used elsewhere (e.g. by `apm audit`).
|
||||
description: AI development skills for Claude Code and GitHub Copilot CLI — factory, design, implement, review, and cross-cutting workflows.
|
||||
version: 0.4.5
|
||||
version: 0.5.0
|
||||
owner:
|
||||
name: Defame1297
|
||||
email: [email protected]
|
||||
|
||||
+139
-17
@@ -141,7 +141,7 @@ A boundary-clause target that resolves to no skill or agent has **three** possib
|
||||
| Verdict | When |
|
||||
|---|---|
|
||||
| **SUGGESTION** — the default | the target does not resolve and neither promotion condition below holds |
|
||||
| **blocking ERROR** | the target is **terminal** (not a compound modifier) **and** either written in route notation (`/name` for any name; `-> name` only when the name is hyphenated — see the gap below) **or** corroborated by another target in the same sentence that *does* resolve |
|
||||
| **blocking ERROR** | the target is **terminal** (not a compound modifier) **and** either written in route notation (`/name` for any name; a bare `-> name` only when the name is hyphenated, a backticked `` -> `name` `` for any — see the gap below) **or** corroborated by another target in the same sentence that *does* resolve |
|
||||
| **INFO, "DID NOT RUN"** | no skill universe could be determined for the path at all — the targets are named and left unchecked, exit 0 |
|
||||
|
||||
The default is deliberately soft because a hyphenated word in a boundary clause is as likely to be a
|
||||
@@ -149,14 +149,25 @@ tool, a file format or an English compound as a route: "pre-commit hooks" is pro
|
||||
never reaches the check at all, being a compound modifier rather than a terminal name. The
|
||||
SUGGESTION text says how to opt in — write it as `/name` or `-> name` and it gets checked properly.
|
||||
|
||||
**Known gap: the arrow form only works for hyphenated names.** Target extraction is built on
|
||||
`NAME_HYPH` (`scripts/skill-size-check.sh:543`), which requires at least one hyphen, and
|
||||
`ARROW_BOUNDARY` (`:561`) inherits that. So `-> gitea-prs` is extracted and checked, while
|
||||
`-> triage` is not extracted at all — no ERROR, no SUGGESTION, exit 0. The unicode arrow `→` is not
|
||||
recognised in either case. This makes the SUGGESTION's own advice unsafe for a single-word skill:
|
||||
taking it silences the finding rather than checking it. `/name` has no such restriction and is the
|
||||
form to prefer. Tracked as a defect; `tests/test-adr0020-targets.sh` has one arrow case and its
|
||||
target happens to be hyphenated, so nothing currently covers this.
|
||||
**Known gap: a BARE arrow target must be hyphenated.** Target extraction is built on `NAME_HYPH` in
|
||||
`scripts/skill-size-check.sh`, which requires at least one hyphen, and `ARROW_BOUNDARY` inherits
|
||||
that. So `Not X -> gitea-prs` is extracted and checked, while `Not X -> triage` yields no target.
|
||||
The exclusion is deliberate, not an oversight: `research`, `triage`, `forge`, `prototype` and `tdd`
|
||||
are all real skill names *and* ordinary English, so a bare single-word rule would flag most of the
|
||||
corpus. The marked spellings carry no such restriction — `` `triage` `` and `/triage` are both
|
||||
extracted — and are the forms to prefer. **Both arrow spellings are recognised:** `ARROW_MARKED`,
|
||||
`ARROW_BOUNDARY` and `BOUNDARY_ARROW` are each built from `(?:->|→)`, so the unicode arrow `→`
|
||||
behaves exactly like `->` in every case below. Cite these constants by symbol name, never by line
|
||||
number: the script moves often enough that a pinned line lands a reader in an unrelated comment
|
||||
block and reads as plausible.
|
||||
|
||||
**The gap is no longer silent.** It used to be exactly that — no ERROR, no SUGGESTION, exit 0 — which
|
||||
made the dangling-target SUGGESTION's own advice unsafe for a single-word skill: taking it silenced
|
||||
the finding instead of checking it. `boundary_clause_status()` now separates the case out and
|
||||
reports it as `unparsed` (see below), naming the parse failure and the two spellings that fix it.
|
||||
The target is still not *resolved*; the author is now told so rather than left with a green gate.
|
||||
`tests/test-adr0020-targets.sh` covers both directions (`arrow-single-word-target` and the silent
|
||||
control `arrow-single-word-marked`).
|
||||
|
||||
Corroboration is what makes the soft default safe: a sentence whose *other* target resolves is
|
||||
demonstrably a routing sentence, so a sibling that does not resolve is a typo rather than a noun, and
|
||||
@@ -200,17 +211,109 @@ through `.claude/skills/` alone, so **the same commit measured 2 dangling target
|
||||
machine and 6 on a fresh clone**. A gate shipping hot with no baseline cannot give two answers.
|
||||
|
||||
Verified fixed: running the hook over a tree holding only `plugins/` and the root `apm.yml`, with no
|
||||
`.claude/` or `.agents/` anywhere, produces findings identical to the working tree — **26 description
|
||||
FAILs, 9 body FAILs, 2 dangling targets, 0 missing references, 58 SUGGESTIONs**.
|
||||
`.claude/` or `.agents/` anywhere, produced findings identical to the working tree. The figures that
|
||||
reproduction recorded — 26 description FAILs, 9 body FAILs, 2 dangling targets, 0 missing references
|
||||
— are the pre-retrofit corpus as it stood when the experiment was run, kept here as the evidence for
|
||||
the install-independence claim. They are not current: the retrofit under #99 took the first three to
|
||||
zero. What the experiment establishes is that the two trees agree, not what either measured.
|
||||
|
||||
### Boundary-clause detection: three outcomes, not two
|
||||
|
||||
`boundary_clause_status()` returns one of three values, and the two findings get separate messages:
|
||||
|
||||
| Status | When | Reported as |
|
||||
|---|---|---|
|
||||
| `present` | a prose marker (`do not`, `instead`, `rather than`, `not for`) or an arrow clause was found | nothing |
|
||||
| `absent` | neither was found | SUGGESTION: add a boundary clause, in either form |
|
||||
| `unparsed` | an arrow clause was found and **no target could be read out of it** | SUGGESTION: the clause is present — this is a *parse* failure, not a missing clause |
|
||||
|
||||
The third had to be split out. Collapsing it into `absent` is a **wrong** finding, not a strict one:
|
||||
it sends the author to add a clause that is already there. Three of them instead reworded a correct
|
||||
clause until the regex accepted it, one stripping the very filename that discriminates the skill
|
||||
from its neighbour (**#110**).
|
||||
|
||||
`unparsed` is narrow and certain on purpose. It fires only on the arrow form, which *always* names a
|
||||
target, so zero targets means the name is written in a shape the extractor cannot see — in practice
|
||||
a bare single-word target, per the known gap above, and the message says to write it `` `name` `` or
|
||||
`/name`. A **prose** clause yielding no target is not reported at all: "Do not use for anything else"
|
||||
is a complete and legitimate boundary clause that names nowhere to go.
|
||||
|
||||
**One arrow, one target.** An arrow clause naming two or more targets draws its own SUGGESTION,
|
||||
quoting both names and asking for a split, because only the first is ever resolved: the conjunction
|
||||
continuation (`CONT_MARKED` / `CONT_ANY`) is wired to the prose route verbs and never to arrows. So
|
||||
`Not X -> a or b` resolved `a`, left `b` resolved by nothing and reported by nothing, and then let
|
||||
the audit print "1 of 1 boundary target(s) resolve" on a clause naming two — a gate under-reporting
|
||||
its own coverage, which is the one failure mode ADR-0020 says a gate must not have (**#107**). The
|
||||
clause is **rejected rather than the arrow scan extended**: extending it would widen the resolver's
|
||||
deliberately conservative false-positive tuning across every arrow in the corpus, where splitting
|
||||
costs the author one full stop. The convention is one arrow per target — `Not X -> a. Not Y -> b.` —
|
||||
already what every retrofitted `gitea-*` skill does in practice, now stated in
|
||||
`skill-author`'s `references/contract.md` instead of being folklore.
|
||||
|
||||
**Dotted filenames in a boundary clause now parse.** `CLAUSE_BODY` — what may sit between `Not` and
|
||||
the arrow — used to be `[^.;]`, a class that cannot cross a `.`, so every clause naming a dotted
|
||||
filename between the two (`AGENTS.md`, `.vale.ini`, `.pre-commit-config.yaml`) was invisible to both
|
||||
`BOUNDARY_ARROW` and `ARROW_BOUNDARY`. The two resulting failures were different sizes (**#110**):
|
||||
|
||||
- with a **backticked** target the clause was *misdiagnosed*. The backtick sweep still extracted the
|
||||
target, so the route was checked, but the gate reported "no boundary clause" on a clause that was
|
||||
present and working. That is the misdiagnosis the three rewordings above came from.
|
||||
- with a **bare** target the clause was *unchecked*. `ARROW_BOUNDARY` is the only extractor for a
|
||||
bare arrow target, so `Not AGENTS.md -> no-such-skill` produced no target, no dangling report and
|
||||
no missing-clause SUGGESTION. Silence, not noise — the worse of the two.
|
||||
|
||||
`CLAUSE_BODY` is now `(?:[^.;]|\.(?=\S))`: a dot inside a filename is followed by a non-space, a
|
||||
sentence-ending dot by whitespace or end of string, so the class crosses `AGENTS.md` and still stops
|
||||
at a real sentence end. **Read the second bullet forward as well as back:** a bare target sitting
|
||||
after a dotted filename is now extracted, resolved, and a blocking ERROR when it dangles, where the
|
||||
same clause used to pass unchecked in silence.
|
||||
|
||||
### SUGGESTION-only checks
|
||||
|
||||
Three more, deterministic to measure but judgment to act on:
|
||||
Deterministic to measure, judgment to act on:
|
||||
|
||||
- a description with **no boundary clause at all**;
|
||||
- a description with **no boundary clause at all** (`absent`);
|
||||
- an **arrow clause whose target could not be read** (`unparsed`);
|
||||
- an **arrow clause naming more than one target**;
|
||||
- a `## Gotchas` section with **more than five entries**;
|
||||
- a `## Gotchas` section over **25% of the body**.
|
||||
|
||||
### Hand-invoked skills are exempt from the routing rules, and only those
|
||||
|
||||
A skill or agent whose frontmatter carries `disable-model-invocation: true` skips three checks:
|
||||
|
||||
- the boundary-clause check, `absent` and `unparsed` alike;
|
||||
- the multi-target arrow check;
|
||||
- the 250-character description **target** (`hand_invoked()` in `scripts/skill-size-check.sh`).
|
||||
|
||||
It keeps the 400-character description FAIL and **both** body word tiers, and if its description
|
||||
does happen to name a target, that target is still resolved and can still dangle.
|
||||
|
||||
Why the exemption is right: `disable-model-invocation: true` removes the skill from the
|
||||
model-visible listing entirely — it is not preloaded, and the Skill tool refuses to call it — so its
|
||||
description is never matched against user intent. ADR-0020 and `skill-author`'s contract therefore
|
||||
give such a skill **one plain human-facing sentence**: no trigger list, no boundary clause. No
|
||||
validator knew the field existed (**#108**), so the boundary-clause SUGGESTION fired on exactly the
|
||||
shape the contract mandates, and its remedy — "so the router knows where NOT to send this skill" —
|
||||
was addressed to a router that cannot see the skill at all. An author who followed the advice made
|
||||
the file worse. There is no router to inform.
|
||||
|
||||
The half that does **not** lift is the point. The body is still loaded on invocation and still
|
||||
competes with the caller's live conversation, so neither body tier moves. The 400-character ceiling
|
||||
stands too: a hand-invoked description is not preloaded, but it is still the one line the user reads
|
||||
when choosing from the `/` menu, and that ceiling is an outlier stop rather than a routing-quality
|
||||
budget — which is precisely why the 250-character target is the tier that lifts.
|
||||
|
||||
The field is read as a **boolean**, not as a mention of the key. PyYAML already resolves the
|
||||
unquoted YAML 1.1 booleans, so the extra handling catches a quoted `"true"`, which a host reads as
|
||||
truthy; `disable-model-invocation: false` is the model-invoked case written out longhand and buys
|
||||
nothing. A frontmatter parse failure returns false rather than raising — the flag is a *modifier* on
|
||||
other checks, and `description_value()` on the same text already reports the broken frontmatter, so
|
||||
raising here would diagnose one file twice two different ways.
|
||||
|
||||
`caveman` and `zoom-out` are the two carriers here. `tests/test-skill-size-check.sh` pins both
|
||||
halves — what the carve-out lifts, each with a flag-removed control, and what it must not.
|
||||
|
||||
### `verbose: true` is load-bearing
|
||||
|
||||
The hook is declared `verbose: true` so the SUGGESTION tier is audible. pre-commit prints nothing at
|
||||
@@ -281,8 +384,10 @@ script.** `scripts/skill-size-check.sh` applies its body gate to whatever path i
|
||||
bash scripts/skill-size-check.sh plugins/*/.apm/agents/*.agent.md
|
||||
```
|
||||
|
||||
exits 1 today with 900-word body FAILs on `git-orchestrate` (933), `gitea-orchestrate` (1,199) and
|
||||
`apm-orchestrate` (1,113). Agent files escape only because the hook definitions filter on `SKILL.md`
|
||||
exits 1 today with 900-word body FAILs on `git-orchestrate` and `gitea-orchestrate`. (Counts are
|
||||
deliberately not pinned here — agent bodies are edited like any other file, and a figure in this
|
||||
paragraph goes stale the moment one is trimmed. Run the command.) Agent files escape only because
|
||||
the hook definitions filter on `SKILL.md`
|
||||
— a file-pattern accident that happens to implement the design, not the design itself. **Do not
|
||||
"extend" that hook's `files:` pattern to cover agents** on the assumption that the script already
|
||||
knows the difference; doing so silently enforces a gate ADR-0020 declines to set.
|
||||
@@ -293,13 +398,30 @@ knows the difference; doing so silently enforces a gate ADR-0020 declines to set
|
||||
non-compliant skill's current numbers was considered and rejected in favour of hot gates.
|
||||
|
||||
**The corpus is now clean on both gates.** Issue **#99** retrofitted all 39 skills plugin by plugin;
|
||||
`kyberforge` was the last wave, followed by two corpus-wide passes.
|
||||
`kyberforge` was the last wave, after which the corpus was swept as a whole rather than per plugin.
|
||||
Each sweep is followed by an **independent review round**: a fresh agent with no memory of the
|
||||
retrofit re-measures the corpus and files what it finds, and the round repeats until one lands no
|
||||
findings. The rounds are recorded as comments on **#99** — read the current state off that thread,
|
||||
which is why no round count is pinned here.
|
||||
|
||||
| Gate | Current findings |
|
||||
|---|---|
|
||||
| `skill-size-check` | **0 of 39** descriptions and **0 of 39** bodies exceed their FAIL tier; 0 dangling targets; 31 SUGGESTIONs |
|
||||
| `skill-size-check` | **0 of 39** descriptions and **0 of 39** bodies exceed their FAIL tier; 0 dangling targets; SUGGESTIONs outstanding (count not pinned — see below) |
|
||||
| `Kyberforge.CompositionNote` (Vale) | **0 errors** — the four `gitea-*` carriers were all retrofitted |
|
||||
|
||||
**The SUGGESTION count is deliberately not recorded here.** It moves with every skill edit *and*
|
||||
with every change to the gate's own tiering, so any figure written down is stale by the next commit.
|
||||
Measure it instead:
|
||||
|
||||
```
|
||||
bash scripts/skill-size-check.sh plugins/*/.apm/skills/*/SKILL.md | grep -c '^SUGGESTION'
|
||||
pre-commit run skill-size-check --all-files # same findings, via the hook
|
||||
```
|
||||
|
||||
A non-zero count is the expected steady state, not a regression. SUGGESTIONs exit 0 and block
|
||||
nothing; only the two FAIL tiers, the dangling-target ERROR and the missing-`references/` ERROR do.
|
||||
Read the count as a work queue, and the FAIL columns above as the gate.
|
||||
|
||||
`Kyberforge.CompositionNote` is the ADR-0020 Vale rule banning composition and architecture prose
|
||||
from a description. Every Vale rule here is `level: error` with no ignorable tier, so a description
|
||||
that reintroduces one blocks the commit even though no skill carries one today.
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
# caveman
|
||||
|
||||
Ultra-compressed output mode: drop articles, filler and pleasantries, keep the technical substance exact.
|
||||
|
||||
## What it does
|
||||
|
||||
Switches the agent into a terse register — no articles, no hedging, no pleasantries, fragments allowed, arrows for causality — while leaving technical terms, code blocks and quoted error strings untouched. The mode is *sticky*: once turned on it stays on for every subsequent response until the user says "stop caveman" or "normal mode", rather than decaying back to normal prose after a few turns.
|
||||
|
||||
It carries one built-in escape hatch. Security warnings, confirmations for irreversible actions, multi-step sequences where fragment order could be misread, and any request to clarify are answered in normal prose, then the compressed register resumes.
|
||||
|
||||
## Hand-invoked only
|
||||
|
||||
`SKILL.md` sets `disable-model-invocation: true`. This is the single most important thing to know about this skill: **the model cannot route to it.** No other skill can hand off to it, and no phrasing in a user's request will cause it to be selected automatically. The only way in is the human typing `/caveman`.
|
||||
|
||||
That is deliberate — output style is the user's choice, not an inference the router should make on their behalf. It is also why the description reads as one plain human-facing sentence rather than carrying the trigger phrasing and boundary clause a routable skill needs.
|
||||
|
||||
## Usage
|
||||
|
||||
```text
|
||||
/caveman
|
||||
```
|
||||
|
||||
Then keep working normally. To leave the mode, say "stop caveman" or "normal mode".
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | The whole skill — persistence rule, compression rules, worked examples, and the auto-clarity exception |
|
||||
@@ -2,17 +2,15 @@
|
||||
name: caveman
|
||||
disable-model-invocation: true
|
||||
description: >
|
||||
Ultra-compressed output mode: drops articles, filler and pleasantries while
|
||||
keeping technical substance exact. Cuts token usage by roughly 75%. Hand-invoked
|
||||
only — type /caveman to turn it on, "stop caveman" or "normal mode" to turn it
|
||||
off. Stays active across turns until you do.
|
||||
Ultra-compressed output mode that drops articles, filler and pleasantries while
|
||||
keeping technical substance exact, cutting token usage by roughly 75%.
|
||||
---
|
||||
|
||||
Respond terse like smart caveman. All technical substance stay. Only fluff die.
|
||||
|
||||
## Persistence
|
||||
|
||||
ACTIVE EVERY RESPONSE once triggered. No revert after many turns. No filler drift. Still active if unsure. Off only when user says "stop caveman" or "normal mode".
|
||||
ACTIVE EVERY RESPONSE once user type `/caveman`. No revert after many turns. No filler drift. Still active if unsure. Off only when user says "stop caveman" or "normal mode".
|
||||
|
||||
## Rules
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
# diagnose
|
||||
|
||||
A six-phase discipline for hard bugs and performance regressions: feedback loop → reproduce → hypothesise → instrument → fix with a regression test → clean up.
|
||||
|
||||
## What it does
|
||||
|
||||
Imposes an order of operations on debugging so the agent cannot skip to guessing. The load-bearing phase is the first one: build a fast, deterministic, agent-runnable pass/fail signal for the bug. Everything downstream — bisection, hypothesis testing, instrumentation — just consumes that signal, so the skill refuses to advance to Phase 2 without one, and says so explicitly rather than hypothesising blind.
|
||||
|
||||
The remaining phases each carry a constraint worth knowing about: hypotheses are generated 3–5 at a time and must be falsifiable, so the first plausible idea cannot anchor the whole investigation; every debug log is tagged with a unique prefix (`[DEBUG-a4f2]`) so cleanup is a single grep; the regression test is written before the fix and only at a seam that exercises the real bug pattern; and the run closes by asking what would have prevented the bug, handing off to `improve-codebase-architecture` when the answer is architectural.
|
||||
|
||||
Performance regressions take a branch of their own inside Phase 4 — baseline measurement and bisection, not logs.
|
||||
|
||||
## Conditional reading
|
||||
|
||||
Neither reference file is read on every run; `SKILL.md` names the condition for each.
|
||||
|
||||
- `references/feedback-loops.md` is read when Phase 1 has no signal yet, or when the loop you have is slow or intermittent.
|
||||
- `references/regression-seams.md` is read when Phase 5 leaves you unsure whether the available seam is deep enough — or whether one exists at all.
|
||||
|
||||
## Usage
|
||||
|
||||
```text
|
||||
/diagnose
|
||||
```
|
||||
|
||||
Describe the bug or the regression. For filing and triaging a reported bug rather than diagnosing it, use `triage`; for test-first feature work, use `tdd`.
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | The six phases and their gates — what must be true before each one ends |
|
||||
| `references/feedback-loops.md` | Loaded when Phase 1 has no loop or the loop is too weak: ten ways to construct one ordered by cost, how to sharpen an existing loop, handling intermittent bugs, and what to ask the user for when the bug resists reproduction |
|
||||
| `references/regression-seams.md` | Loaded when Phase 5 is unsure about the seam: what makes a seam correct, the four shapes of a too-shallow seam, and what to do when no correct seam exists |
|
||||
| `assets/hitl-loop.template.sh` | Copy-and-edit bash template for the last-resort human-in-the-loop feedback loop, cited by `references/feedback-loops.md`. Provides `step` and `capture` helpers and prints captured values as `KEY=VALUE` for the agent to parse |
|
||||
@@ -18,7 +18,9 @@ When exploring the codebase, use the project's domain glossary to get a clear me
|
||||
|
||||
Spend disproportionate effort here. **Be aggressive. Be creative. Refuse to give up.**
|
||||
|
||||
Read `references/feedback-loops.md` — even if you already have a signal. Ten ways to build a loop ordered by cost, how to sharpen the one you have, and what to do when the bug resists reproduction. An unsharpened loop is usually not good enough yet.
|
||||
**If you do not yet have such a signal, read `references/feedback-loops.md`** — ten ways to build one ordered by cost, and what to ask the user for when the bug resists reproduction entirely.
|
||||
|
||||
**If you do have one, it is probably not sharp enough yet.** Make it faster and more deterministic, and make it assert on the exact symptom rather than "didn't crash" — a 30-second flaky loop is barely better than no loop. If it stays slow or intermittent after that, read that file's "Iterate on the loop itself" and "Intermittent bugs" sections.
|
||||
|
||||
Do not proceed to Phase 2 until you have a loop you believe in. If you cannot build one, stop and say so explicitly, listing what you tried — never hypothesise without a signal.
|
||||
|
||||
@@ -62,13 +64,11 @@ Tool preference:
|
||||
|
||||
## Phase 5 — Fix + regression test
|
||||
|
||||
Write the regression test **before the fix** — but only if there is a **correct seam** for it.
|
||||
Write the regression test **before the fix** — but only at a **correct seam**: one where the test exercises the real bug pattern as it occurs at the call site. If the available seam looks too shallow, or you cannot tell whether it is, read `references/regression-seams.md`.
|
||||
|
||||
A correct seam is one where the test exercises the **real bug pattern** as it occurs at the call site. If the only available seam is too shallow (single-caller test when the bug needs multiple callers, unit test that can't replicate the chain that triggered the bug), a regression test there gives false confidence.
|
||||
**If no correct seam exists, that itself is the finding.** Note it and carry it into Phase 6 — the architecture is preventing the bug from being locked down.
|
||||
|
||||
**If no correct seam exists, that itself is the finding.** Note it. The codebase architecture is preventing the bug from being locked down. Flag this for the next phase.
|
||||
|
||||
If a correct seam exists:
|
||||
At a correct seam:
|
||||
|
||||
1. Turn the Phase 1 loop into a failing test at that seam, narrowed to the symptom captured in Phase 2.
|
||||
2. Watch it fail.
|
||||
|
||||
File renamed without changes.
@@ -13,7 +13,7 @@ A feedback loop is a fast, deterministic, agent-runnable pass/fail signal for th
|
||||
7. **Property / fuzz loop.** If the bug is "sometimes wrong output", run 1000 random inputs and look for the failure mode.
|
||||
8. **Bisection harness.** If the bug appeared between two known states (commit, dataset, version), automate "boot at state X, check, repeat" so you can `git bisect run` it.
|
||||
9. **Differential loop.** Run the same input through old-version vs new-version (or two configs) and diff outputs.
|
||||
10. **HITL bash script.** Last resort. If a human must click, drive _them_ with `scripts/hitl-loop.template.sh` so the loop is still structured. Captured output feeds back to you.
|
||||
10. **HITL bash script.** Last resort. If a human must click, drive _them_ with `assets/hitl-loop.template.sh` so the loop is still structured. Captured output feeds back to you.
|
||||
|
||||
## Iterate on the loop itself
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# Judging a regression-test seam
|
||||
|
||||
Read this when Phase 5 leaves you unsure whether the seam available for the regression test is the correct one — either because the obvious seam looks shallow, or because there appears to be no seam at all.
|
||||
|
||||
## What makes a seam correct
|
||||
|
||||
A correct seam is one where the test exercises the **real bug pattern** as it occurs at the call site: the same entry point, the same participants, the same ordering, and the same state the real caller holds when it goes wrong.
|
||||
|
||||
## Seams that are too shallow
|
||||
|
||||
- A single-caller test when the bug only appears with multiple callers.
|
||||
- A unit test that cannot replicate the chain of calls that triggered the bug.
|
||||
- A test that reproduces the symptom by construction — asserting on a value the test itself set — rather than by driving the code path that produces it.
|
||||
- A test that mocks out the collaborator the bug actually lives in.
|
||||
|
||||
A regression test at a shallow seam gives false confidence. It passes forever, including after a change reintroduces the bug at the real call site, and it will be read by the next maintainer as proof the bug is locked down.
|
||||
|
||||
## When there is no correct seam
|
||||
|
||||
Do not force one, and do not settle for a shallow seam to have something green. Instead:
|
||||
|
||||
1. Apply the fix and verify it against the Phase 1 loop directly.
|
||||
2. Write down which seams you considered and why each was too shallow.
|
||||
3. Carry that into Phase 6's "what would have prevented this bug" question. A missing seam is an architecture finding — tangled callers, hidden coupling, or a module with no testable boundary — and the handoff is the `improve-codebase-architecture` skill, with those specifics attached.
|
||||
@@ -0,0 +1,27 @@
|
||||
# grill-me
|
||||
|
||||
Interview the user relentlessly about a plan or design until the decision tree is fully resolved.
|
||||
|
||||
## What it does
|
||||
|
||||
Turns the agent into an interviewer rather than an implementer. It walks the design tree branch by branch, resolving dependencies between decisions one at a time, and offers its own recommended answer alongside each question so the user has something concrete to push against. Two rules give it its shape: **one question at a time**, and **never ask what the codebase can answer** — if a question is settleable by reading the code, the agent goes and reads the code instead of spending the user's attention on it.
|
||||
|
||||
## Composition
|
||||
|
||||
This is the plain grilling loop, with no documentation side effects. The sibling `grill-with-docs` skill runs the same interview but additionally challenges answers against the project's `CONTEXT.md` glossary and existing ADRs, and writes decisions back into those files as they crystallise. Reach for that one when the project has a domain model worth defending; reach for this one when it does not, or when nothing should be written down yet.
|
||||
|
||||
`triage` composes the documented variant, not this one, when an issue needs fleshing out.
|
||||
|
||||
## Usage
|
||||
|
||||
```text
|
||||
/grill-me
|
||||
```
|
||||
|
||||
Describe the plan or design to be stress-tested. Expect questions one at a time, each with a recommended answer.
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | The whole skill — the interview instruction, the one-question-at-a-time rule, and the explore-instead-of-asking rule |
|
||||
@@ -0,0 +1,36 @@
|
||||
# grill-with-docs
|
||||
|
||||
The grilling interview, run against the project's domain model — and writing decisions back into `CONTEXT.md` and ADRs as they land.
|
||||
|
||||
## What it does
|
||||
|
||||
Runs the same relentless one-question-at-a-time interview as `grill-me`, with the project's own documentation as an active participant. During codebase exploration it also locates the domain documentation — a root `CONTEXT.md` and `docs/adr/`, or a `CONTEXT-MAP.md` pointing at per-context glossaries and ADR directories in a multi-context repo — and then uses it four ways:
|
||||
|
||||
- **Challenges terms against the glossary.** When the user's usage conflicts with what `CONTEXT.md` already defines, that is raised immediately rather than absorbed.
|
||||
- **Sharpens fuzzy language** by proposing a precise canonical term ("you're saying 'account' — do you mean the Customer or the User?").
|
||||
- **Cross-references claims against the code**, and surfaces contradictions between what the user says happens and what the code does.
|
||||
- **Updates `CONTEXT.md` inline**, the moment a term is resolved, rather than batching changes to the end of the session where they get lost.
|
||||
|
||||
Files are created lazily — only when there is something real to write.
|
||||
|
||||
ADRs are offered *sparingly*, and only when all three tests pass: the decision is hard to reverse, it would surprise a future reader without the context, and it was a genuine trade-off with real alternatives. Missing any one of the three means no ADR.
|
||||
|
||||
## Composition
|
||||
|
||||
`grill-me` is the same interview without the documentation side effects — use it when there is no domain model to defend or nothing should be written down yet. `triage` composes this skill (not `grill-me`) at step 4 when an issue needs fleshing out. `improve-codebase-architecture` runs its own grilling loop and borrows this skill's `CONTEXT.md` and ADR discipline for the decisions that come out of it.
|
||||
|
||||
## Usage
|
||||
|
||||
```text
|
||||
/grill-with-docs
|
||||
```
|
||||
|
||||
Describe the plan or design. Expect questions one at a time, each with a recommended answer, and expect `CONTEXT.md` to be edited during the session rather than after it.
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | The interview instruction plus the domain-awareness rules: file layout discovery, the four during-session behaviours, and the three-part ADR test |
|
||||
| `CONTEXT-FORMAT.md` | Skill-root document, cited when a term is resolved: the structure of a `CONTEXT.md` and how to write a Language entry |
|
||||
| `ADR-FORMAT.md` | Skill-root document, cited when an ADR is offered: `docs/adr/` naming, sequential numbering, and the ADR template |
|
||||
@@ -0,0 +1,36 @@
|
||||
# improve-codebase-architecture
|
||||
|
||||
Surface architectural friction and propose deepening opportunities — refactors that turn shallow modules into deep ones.
|
||||
|
||||
## What it does
|
||||
|
||||
Looks for places where a codebase is hard to understand, hard to test, or hard for an agent to navigate, and proposes refactors that concentrate behaviour behind smaller interfaces. It runs in three stages:
|
||||
|
||||
1. **Explore.** Reads the domain glossary and any ADRs in the area first, then walks the codebase with an `Explore` sub-agent — organically, noting friction rather than applying fixed heuristics. The **deletion test** is the filter: imagine deleting the module; if complexity vanishes it was a pass-through, if complexity reappears across N callers it was earning its keep.
|
||||
2. **Present candidates.** A numbered list, each with files, problem, solution and benefits — benefits stated in terms of *locality* and *leverage* and of how tests would improve. No interfaces are proposed yet; the user picks one.
|
||||
3. **Grilling loop.** Walks the design tree for the chosen candidate, with documentation side effects landing inline as decisions crystallise.
|
||||
|
||||
The skill is opinionated about vocabulary, and that is the point: **module, interface, implementation, depth, seam, adapter, leverage, locality**, used exactly, with no drift into "component", "service", "API" or "boundary". Domain nouns come from `CONTEXT.md`, architecture nouns from `LANGUAGE.md` — so a proposal reads as "the Order intake module", never "the FooBarHandler".
|
||||
|
||||
ADRs are treated as decisions not to be re-litigated. A candidate that contradicts one is surfaced only when the friction is real enough to warrant reopening it, and is marked as such.
|
||||
|
||||
## Composition
|
||||
|
||||
`diagnose` hands off here when a bug's post-mortem concludes that no correct test seam exists, or that callers are tangled — the recommendation is made after the fix is in, not before. The grilling loop follows `grill-with-docs`'s discipline for `CONTEXT.md` entries and ADR offers, and `SKILL.md` names that skill's format documents directly.
|
||||
|
||||
## Usage
|
||||
|
||||
```text
|
||||
/improve-codebase-architecture
|
||||
```
|
||||
|
||||
Point at a codebase or an area of one. Expect a numbered candidate list and a "which of these would you like to explore?" before any interface design happens.
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | Condensed glossary, key principles, and the three-stage process |
|
||||
| `LANGUAGE.md` | Skill-root document, cited throughout `SKILL.md`: full definitions of every term, the words each one replaces, and the full principle list |
|
||||
| `INTERFACE-DESIGN.md` | Skill-root document, read at stage 3 when the user wants alternative interfaces explored: the parallel sub-agent "Design It Twice" pattern, framing the problem space, and the per-agent design constraints |
|
||||
| `DEEPENING.md` | Skill-root document, cited from `INTERFACE-DESIGN.md`: how to deepen a cluster of shallow modules safely, the four dependency categories (in-process, local-substitutable, remote-but-owned, true external), seam discipline, and the replace-don't-layer testing strategy |
|
||||
@@ -65,7 +65,7 @@ Once the user picks a candidate, drop into a grilling conversation. Walk the des
|
||||
|
||||
Side effects happen inline as decisions crystallize:
|
||||
|
||||
- **Naming a deepened module after a concept not in `CONTEXT.md`?** Add the term to `CONTEXT.md` — same discipline as `/grill-with-docs` (see [CONTEXT-FORMAT.md](../grill-with-docs/CONTEXT-FORMAT.md)). Create the file lazily if it doesn't exist.
|
||||
- **Naming a deepened module after a concept not in `CONTEXT.md`?** Add the term to `CONTEXT.md` — same discipline as `grill-with-docs`, in the format `grill-with-docs`'s `CONTEXT-FORMAT.md` defines. Create the file lazily if it doesn't exist.
|
||||
- **Sharpening a fuzzy term during the conversation?** Update `CONTEXT.md` right there.
|
||||
- **User rejects the candidate with a load-bearing reason?** Offer an ADR, framed as: _"Want me to record this as an ADR so future architecture reviews don't re-suggest it?"_ Only offer when the reason would actually be needed by a future explorer to avoid re-suggesting the same thing — skip ephemeral reasons ("not worth it right now") and self-evident ones. See [ADR-FORMAT.md](../grill-with-docs/ADR-FORMAT.md).
|
||||
- **User rejects the candidate with a load-bearing reason?** Offer an ADR, framed as: _"Want me to record this as an ADR so future architecture reviews don't re-suggest it?"_ Only offer when the reason would actually be needed by a future explorer to avoid re-suggesting the same thing — skip ephemeral reasons ("not worth it right now") and self-evident ones. See `grill-with-docs`'s `ADR-FORMAT.md`.
|
||||
- **Want to explore alternative interfaces for the deepened module?** See [INTERFACE-DESIGN.md](INTERFACE-DESIGN.md).
|
||||
@@ -0,0 +1,32 @@
|
||||
# prototype
|
||||
|
||||
Build a throwaway prototype that answers one design question — either a runnable terminal app or several UI variations.
|
||||
|
||||
## What it does
|
||||
|
||||
Treats a prototype as **throwaway code that answers a question**, and lets the question decide the artifact. `SKILL.md` opens with a two-row dispatch table and the run resolves exactly one row before doing anything else:
|
||||
|
||||
- *"Does this logic / state model feel right?"* → a tiny interactive terminal app that pushes the state machine through the cases that are hard to reason about on paper.
|
||||
- *"What should this look like?"* → several radically different UI variations on one route, switchable from a floating bottom bar via a URL search param.
|
||||
|
||||
The two branches produce fundamentally different artifacts, so picking wrong wastes the whole prototype. When the question is genuinely ambiguous and the user is unreachable, the skill defaults on the shape of the surrounding code (backend module → logic, page or component → UI) and states the assumption at the top of the prototype rather than silently choosing.
|
||||
|
||||
Six rules apply to both branches: throwaway and visibly named as such, one command to run, no persistence by default, no polish, surface the full state after every action or variant switch, and delete or absorb the prototype when it is done. The *answer* is the only durable output — the skill captures it in a commit message, ADR, issue or `NOTES.md` before the code is deleted.
|
||||
|
||||
## Usage
|
||||
|
||||
```text
|
||||
/prototype
|
||||
```
|
||||
|
||||
State the design question. For production code, use `tdd`; for talking a design through without building anything, use `grill-me`.
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | The branch dispatch table and the rules that apply to both branches |
|
||||
| `references/logic.md` | The logic branch, read only when that row is selected: when it is the right shape, and how to build the interactive terminal app |
|
||||
| `references/ui.md` | The UI branch, read only when that row is selected: when it is the right shape, and how to build and switch between the variations |
|
||||
|
||||
Each reference is self-contained — a run reads one of the two, never both.
|
||||
@@ -3,8 +3,8 @@ name: prototype
|
||||
description: >
|
||||
Use when the user wants a throwaway prototype to answer a design question about
|
||||
a data model, state machine or business logic, or to mock up a UI in several
|
||||
variations, as in "try a few designs". Not production code -> `tdd`. Not
|
||||
talking a design through without building -> `grill-me`.
|
||||
variations. Not production code -> `tdd`. Not talking a design through ->
|
||||
`grill-me`.
|
||||
---
|
||||
|
||||
# Prototype
|
||||
@@ -13,10 +13,12 @@ A prototype is **throwaway code that answers a question**. The question decides
|
||||
|
||||
## Pick a branch
|
||||
|
||||
Identify which question is being answered — from the user's prompt, the surrounding code, or by asking if the user is around:
|
||||
| Question being answered | Build | Reference |
|
||||
|---|---|---|
|
||||
| "Does this logic / state model feel right?" | A tiny interactive terminal app that pushes the state machine through cases that are hard to reason about on paper | `references/logic.md` |
|
||||
| "What should this look like?" | Several radically different UI variations on one route, switchable via a URL search param and a floating bottom bar | `references/ui.md` |
|
||||
|
||||
- **"Does this logic / state model feel right?"** → [LOGIC.md](LOGIC.md). Build a tiny interactive terminal app that pushes the state machine through cases that are hard to reason about on paper.
|
||||
- **"What should this look like?"** → [UI.md](UI.md). Generate several radically different UI variations on a single route, switchable via a URL search param and a floating bottom bar.
|
||||
Resolve the row from the user's prompt, the surrounding code, or by asking if the user is around, then read only that reference — each is self-contained.
|
||||
|
||||
The two branches produce fundamentally different artifacts — getting this wrong wastes the whole prototype. If the question is genuinely ambiguous and the user isn't reachable, default to whichever branch better matches the surrounding code (a backend module → logic; a page or component → UI) and state the assumption at the top of the prototype.
|
||||
|
||||
|
||||
+1
-4
@@ -9,7 +9,7 @@ A tiny interactive terminal app that lets the user drive a state model by hand.
|
||||
- "I want to feel out what the API should look like before writing it."
|
||||
- Anything where the user wants to **press buttons and watch state change**.
|
||||
|
||||
If the question is "what should this look like" — wrong branch. Use [UI.md](UI.md).
|
||||
If the question is "what should this look like" — wrong branch. Read `references/ui.md`.
|
||||
|
||||
## Process
|
||||
|
||||
@@ -72,8 +72,5 @@ When the prototype has done its job, the answer to the question is the only thin
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- **Don't add tests.** A prototype that needs tests is no longer a prototype.
|
||||
- **Don't wire it to the real database.** Use an in-memory store unless the question is specifically about persistence.
|
||||
- **Don't generalise.** No "what if we wanted to support X later." The prototype answers one question.
|
||||
- **Don't blur the logic and the TUI together.** If the reducer / state machine references `console.log`, prompts, or terminal escape codes, it's no longer portable. Keep the TUI as a thin shell over a pure module.
|
||||
- **Don't ship the TUI shell into production.** The shell is optimised for being driven by hand from a terminal. The logic module behind it is the bit worth keeping.
|
||||
+1
-2
@@ -2,7 +2,7 @@
|
||||
|
||||
Generate **several radically different UI variations** on a single route, switchable from a floating bottom bar. The user flips between variants in the browser, picks one (or steals bits from each), then throws the rest away.
|
||||
|
||||
If the question is about logic/state rather than what something looks like — wrong branch. Use [LOGIC.md](LOGIC.md).
|
||||
If the question is about logic/state rather than what something looks like — wrong branch. Read `references/logic.md`.
|
||||
|
||||
## When this is the right shape
|
||||
|
||||
@@ -109,4 +109,3 @@ Don't leave variant components or the switcher lying around. They rot fast and c
|
||||
- **Variants that differ only in colour or copy.** That's a tweak, not a prototype. Real variants disagree about structure.
|
||||
- **Sharing too much code between variants.** A shared `<Header>` is fine; a shared `<Layout>` defeats the point. Each variant should be free to throw out the layout.
|
||||
- **Wiring variants to real mutations.** Read-only prototypes are fine. If a variant needs to mutate, point it at a stub — the question is "what should this look like", not "does the backend work".
|
||||
- **Promoting the prototype directly to production.** The variant code was written under prototype constraints (no tests, minimal error handling). Rewrite it properly when you fold it in.
|
||||
@@ -0,0 +1,31 @@
|
||||
# research
|
||||
|
||||
Research a tool, library or API from canonical documentation into a directory of structured per-topic reference files.
|
||||
|
||||
## What it does
|
||||
|
||||
Runs a six-step pipeline: scope against the working directory (what version is actually in use, what is already documented), resolve the topic through Context7, websearch for canonical docs covering whatever Context7 missed, read those sources, deepen one level into the links worth following, then write one markdown file per topic area plus a `sources.md` provenance record.
|
||||
|
||||
Four gotchas at the top of `SKILL.md` shape the whole run, and each exists because of a specific failure: the output path is never inferred (a guessed destination scatters a directory's worth of files through someone's source tree); nothing is written outside that path; no empty topic file is ever written (a stub `troubleshooting.md` reads downstream as researched and closed); and a Context7 "no results", redirect or header-only response does not count as coverage. If no topic area has content, the run writes nothing at all — `sources.md` included — and reports what it searched.
|
||||
|
||||
The frontmatter pins `model: sonnet` and a closed `allowed-tools` list. Notably it grants no subagent tool, so every `WebFetch` is serial and each fetched page lands in the run's own context — which is why steps 4 and 5 insist on reducing each page to notes before fetching the next, and cap deepening at roughly ten extra pages.
|
||||
|
||||
## Composition
|
||||
|
||||
`references/file-format.md` is not optional reading before the write step: the `sources.md` field names it defines are matched literally by the downstream provenance validator. Prose written in their place parses as nothing and the check passes having verified nothing.
|
||||
|
||||
## Usage
|
||||
|
||||
```text
|
||||
/research
|
||||
```
|
||||
|
||||
Name the topic and the output path — the skill will stop and ask if the path is missing. Supplying starting URLs is treated as a deliberate source choice and skips Context7 resolution and discovery. For documentation derived from existing code or specs, use `write-docs`; for a bug or incident, use `diagnose`.
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | The four gotchas and the six research steps |
|
||||
| `references/topics.md` | Read at Step 1 before narrowing scope: the default topic list (`overview`, `installation`, `configuration`, `cli-reference`, `api-reference`, `examples`, and more) and what each file covers |
|
||||
| `references/file-format.md` | Read at Step 6 before writing: the frontmatter schema for a topic file and the exact `sources.md` field names the provenance validator matches |
|
||||
@@ -8,10 +8,12 @@ description: >-
|
||||
metadata:
|
||||
category: research
|
||||
allowed-tools:
|
||||
- WebSearch
|
||||
- WebFetch
|
||||
- Grep
|
||||
- Glob
|
||||
- Read
|
||||
- Write
|
||||
- WebSearch
|
||||
- WebFetch
|
||||
- mcp__context7__resolve-library-id
|
||||
- mcp__context7__query-docs
|
||||
model: sonnet
|
||||
@@ -61,4 +63,4 @@ Merge every set of notes, Context7 and web alike, by topic area. Read `reference
|
||||
|
||||
Spell the `sources.md` field names exactly as `references/file-format.md` gives them. The downstream provenance validator matches them literally; prose in their place parses as nothing, and the check passes having verified nothing.
|
||||
|
||||
If no topic area has content, write nothing at all, `sources.md` included, and report what was searched. A directory of empty files is worse than an honest miss.
|
||||
If no topic area has content, write nothing at all, `sources.md` included, and report what was searched.
|
||||
@@ -0,0 +1,32 @@
|
||||
# tdd
|
||||
|
||||
Test-driven development as a strict red-green-refactor loop, one behaviour at a time.
|
||||
|
||||
## What it does
|
||||
|
||||
Two convictions drive this skill. The first is about what a test is for: tests verify behaviour through public interfaces, not implementation details. A good test reads like a specification ("user can checkout with valid cart") and survives refactors because it does not care about internal structure. The warning sign for a bad one is precise — the test breaks when you refactor but behaviour has not changed.
|
||||
|
||||
The second is an explicit anti-pattern: **do not write all the tests first, then all the implementation.** Horizontal slicing treats RED as "write every test" and GREEN as "write every implementation", and it produces tests of *imagined* behaviour — tests of the shape of things, insensitive to real change, committed to before the implementation was understood. The correct shape is vertical: one test → one implementation → repeat, each cycle informed by what the last one taught you.
|
||||
|
||||
The workflow is four stages: plan (confirm the interface and which behaviours matter, with the user — you cannot test everything), fire a tracer bullet (one test proving the path works end to end), loop incrementally one behaviour at a time, then refactor once everything is green. Refactoring while RED is forbidden.
|
||||
|
||||
Codebase exploration uses the project's domain glossary, so test names and interface vocabulary match the project's language, and ADRs in the area are respected.
|
||||
|
||||
## Usage
|
||||
|
||||
```text
|
||||
/tdd
|
||||
```
|
||||
|
||||
Describe the feature or bug. Expect the skill to ask what the public interface should look like and which behaviours matter most before any code is written. For diagnosing an existing bug rather than building test-first, use `diagnose`; for throwaway exploratory code, use `prototype`.
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | Philosophy, the horizontal-slicing anti-pattern, the four-stage workflow, and the per-cycle checklist |
|
||||
| `tests.md` | Skill-root document, cited from Philosophy: worked good and bad test examples |
|
||||
| `mocking.md` | Skill-root document, cited from Philosophy: mock at system boundaries only, and what not to mock |
|
||||
| `deep-modules.md` | Skill-root document, cited from stage 1: what a deep module is (small interface, large implementation) and why it is the design to aim for |
|
||||
| `interface-design.md` | Skill-root document, cited from stage 1: designing interfaces for testability, starting with accepting dependencies rather than creating them |
|
||||
| `refactoring.md` | Skill-root document, cited from stage 4: the refactor-candidate checklist — duplication, long methods, shallow modules, feature envy, primitive obsession |
|
||||
@@ -1,6 +1,6 @@
|
||||
# Writing Agent Briefs
|
||||
|
||||
An agent brief is a structured comment posted on a GitHub issue when it moves to `ready-for-agent`. It is the authoritative specification that an AFK agent will work from. The original issue body and discussion are context — the agent brief is the contract.
|
||||
An agent brief is a structured comment posted on an issue in the issue tracker when it moves to `ready-for-agent`. It is the authoritative specification that an AFK agent will work from. The original issue body and discussion are context — the agent brief is the contract.
|
||||
|
||||
## Principles
|
||||
|
||||
@@ -27,7 +27,7 @@ Describe **what** the system should do, not **how** to implement it. The agent w
|
||||
|
||||
The agent needs to know when it's done. Every agent brief must have concrete, testable acceptance criteria. Each criterion should be independently verifiable.
|
||||
|
||||
- **Good:** "Running `gh issue list --label needs-triage` returns issues that have been through initial classification"
|
||||
- **Good:** "Querying the issue tracker for the `needs-triage` label returns issues that have been through initial classification"
|
||||
- **Bad:** "Triage should work correctly"
|
||||
|
||||
### Explicit scope boundaries
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
# triage
|
||||
|
||||
Move issues on the project issue tracker through a small state machine of triage roles.
|
||||
|
||||
## What it does
|
||||
|
||||
Gives issue triage an explicit state model and a fixed set of moves. Every issue carries exactly one **category** role (`bug`, `enhancement`) and one **state** role (`needs-triage`, `needs-info`, `ready-for-agent`, `ready-for-human`, `wontfix`); conflicting state roles are flagged to the maintainer before anything else happens. Unlabeled issues normally enter at `needs-triage`; `needs-info` returns there once the reporter replies. The maintainer can override at any point, and unusual transitions are questioned rather than executed silently.
|
||||
|
||||
A run does one of three things depending on what the maintainer asks for:
|
||||
|
||||
- **Show what needs attention** — three buckets, oldest first: unlabeled, `needs-triage`, and `needs-info` with reporter activity since the last triage notes.
|
||||
- **Triage a specific issue** — gather context (including prior triage notes, so resolved questions are not re-asked, and `.out-of-scope/` records that resemble the issue), recommend a category and state with reasoning, attempt reproduction for bugs *before* any grilling, run a `grill-with-docs` session if the issue needs fleshing out, then apply the outcome.
|
||||
- **Quick state override** — "move #42 to ready-for-agent" is trusted and applied directly, skipping grilling, after confirming the exact changes.
|
||||
|
||||
Two hard rules: every comment or issue the skill posts during triage must open with the AI-generated disclaimer, and the canonical role names above are *not* necessarily the label strings in the tracker — the mapping has to be supplied to the run.
|
||||
|
||||
## Composition
|
||||
|
||||
`grill-with-docs` is invoked at step 4 when an issue needs fleshing out; whatever that session establishes is carried into the triage notes so the work is not lost. The reverse direction also exists: `diagnose` names this skill as the place to send a *reported* bug that needs filing rather than debugging.
|
||||
|
||||
## Usage
|
||||
|
||||
```text
|
||||
/triage
|
||||
```
|
||||
|
||||
Then describe what you want in natural language — "show me anything that needs my attention", "let's look at #42", "move #42 to ready-for-agent", "what's ready for agents to pick up?".
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | The roles and state machine, the three invocation modes, the needs-info template, and how to resume a prior session |
|
||||
| `AGENT-BRIEF.md` | Skill-root document, cited when an issue moves to `ready-for-agent` (and reused for `ready-for-human`): how to write a brief that stays durable for weeks while the codebase moves under it — describe interfaces and behavioural contracts, not line numbers |
|
||||
| `OUT-OF-SCOPE.md` | Skill-root document, cited when an enhancement is closed `wontfix` and when checking for prior rejections: how the `.out-of-scope/` knowledge base is laid out and what it is for — institutional memory, and deduplication against re-litigated requests |
|
||||
@@ -35,7 +35,7 @@ Five **state** roles:
|
||||
|
||||
Every triaged issue should carry exactly one category role and one state role. If state roles conflict, flag it and ask the maintainer before doing anything else.
|
||||
|
||||
These are canonical role names — the actual label strings used in the issue tracker may differ. The mapping should have been provided to you - run `/setup-matt-pocock-skills` if not.
|
||||
These are canonical role names — the actual label strings used in the issue tracker may differ. Resolve each canonical name against the tracker's live label set before applying it, using whichever tracker skill this install provides. If a name has no counterpart there, report the gap and ask the maintainer for the mapping — never substitute a guess.
|
||||
|
||||
State transitions: an unlabeled issue normally goes to `needs-triage` first; from there it moves to `needs-info`, `ready-for-agent`, `ready-for-human`, or `wontfix`. `needs-info` returns to `needs-triage` once the reporter replies. The maintainer can override at any time — flag transitions that look unusual and ask before proceeding.
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
# write-docs
|
||||
|
||||
Produce technical documentation derived from code and spec, one section at a time, with a confirmation gate on every section.
|
||||
|
||||
## What it does
|
||||
|
||||
Casts the agent as a technical writer with one non-negotiable constraint: **every claim must be traceable to a source file line, a spec section, or an explicit user statement.** Nothing is invented, and behaviour that genuinely cannot be documented from the available sources is marked out-of-scope rather than explained away.
|
||||
|
||||
The process is eight steps — identify scope, read and extract, gap check, draft section by section, confirmation gate, delta summary, reader testing, finalise — and several of them are deliberately gated on the human:
|
||||
|
||||
- Files are read only after the user approves them by name. The skill may propose candidates; it waits.
|
||||
- The **gap check** presents what the code does say and asks the user to fill only what it does not: caller intent, error-handling rationale, non-obvious side effects.
|
||||
- No section is finalised until the full revised text has been shown. The skill never gates on output the user has not seen, and never reprints the whole document — all edits are surgical.
|
||||
- **Reader testing** predicts 5–10 questions a target reader would ask, then spawns a sub-agent that receives only the finished doc and the questions — no source files. If the doc cannot answer them, neither can the sub-agent, and the run loops back to drafting.
|
||||
|
||||
Summary and overview sections are written last, once the detail sections are stable.
|
||||
|
||||
## Usage
|
||||
|
||||
```text
|
||||
/write-docs
|
||||
```
|
||||
|
||||
Name the files or modules to document, the target audience (developer / user / contributor / internal), and the documentation type (reference, guide, README section, inline comment, changelog entry). For a PRD, ADR or decision doc, use `grill-me` or `grill-with-docs` instead — those have dedicated handling.
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | The whole skill — role, use/do-not-use boundaries, required inputs, constraints, the eight-step process, output format, failure handling, and a nine-item self-check |
|
||||
@@ -35,7 +35,7 @@ You are a technical writer that produces documentation by reading code and spec
|
||||
- User says "write docs for X", "document this", "create docs for this feature", "write a README for this"
|
||||
|
||||
**Do not use when:**
|
||||
- User wants a PRD, decision doc, or architecture proposal → `to-prd` or `grill-me`
|
||||
- User wants a PRD, decision doc, or architecture proposal → `grill-me` or `grill-with-docs`
|
||||
- User wants to document a skill file (skill files are self-describing)
|
||||
- User wants marketing or blog copy
|
||||
- Documentation requires tacit organisational knowledge that cannot be read from code or spec
|
||||
@@ -88,7 +88,7 @@ You are a technical writer that produces documentation by reading code and spec
|
||||
- Stage skipped without a logged reason → flag and require the one-sentence log before continuing
|
||||
- Code behaviour is undocumentable (internal implementation detail, no public spec) → note as out-of-scope in the doc; do not invent an explanation
|
||||
- Reader Testing sub-agent fails on multiple questions → surface the failures, return to step 4; do not mark complete
|
||||
- Requested output is a PRD, decision doc, or architecture proposal → redirect to `to-prd`, `grill-me`, or `grill-with-docs`
|
||||
- Requested output is a PRD, decision doc, or architecture proposal → redirect to `grill-me` or `grill-with-docs`
|
||||
|
||||
## Self-check
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# zoom-out
|
||||
|
||||
Ask the agent to go up a layer of abstraction and map the modules and callers around unfamiliar code.
|
||||
|
||||
## What it does
|
||||
|
||||
A single-purpose prompt for the moment you land in a part of the codebase you do not know. Instead of answering at the level of the file in front of it, the agent climbs one layer and produces a map of the relevant modules and their callers — and names them using the project's own domain glossary vocabulary, so the map lines up with the language the rest of the repo already uses.
|
||||
|
||||
## Hand-invoked only
|
||||
|
||||
`SKILL.md` sets `disable-model-invocation: true`, so the router never selects this skill on its own and no other skill can hand off to it. It runs when the human asks for it. That also means its description is written as one plain human-facing sentence — it carries no trigger phrasing or boundary clause, because nothing routes on it.
|
||||
|
||||
## Usage
|
||||
|
||||
```text
|
||||
/zoom-out
|
||||
```
|
||||
|
||||
Best used with the unfamiliar code already in context — the skill widens the view around what you are looking at rather than picking a starting point for you.
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | The whole skill — a single instruction, no supporting files |
|
||||
@@ -0,0 +1,29 @@
|
||||
# caveman
|
||||
|
||||
Ultra-compressed output mode: drop articles, filler and pleasantries, keep the technical substance exact.
|
||||
|
||||
## What it does
|
||||
|
||||
Switches the agent into a terse register — no articles, no hedging, no pleasantries, fragments allowed, arrows for causality — while leaving technical terms, code blocks and quoted error strings untouched. The mode is *sticky*: once turned on it stays on for every subsequent response until the user says "stop caveman" or "normal mode", rather than decaying back to normal prose after a few turns.
|
||||
|
||||
It carries one built-in escape hatch. Security warnings, confirmations for irreversible actions, multi-step sequences where fragment order could be misread, and any request to clarify are answered in normal prose, then the compressed register resumes.
|
||||
|
||||
## Hand-invoked only
|
||||
|
||||
`SKILL.md` sets `disable-model-invocation: true`. This is the single most important thing to know about this skill: **the model cannot route to it.** No other skill can hand off to it, and no phrasing in a user's request will cause it to be selected automatically. The only way in is the human typing `/caveman`.
|
||||
|
||||
That is deliberate — output style is the user's choice, not an inference the router should make on their behalf. It is also why the description reads as one plain human-facing sentence rather than carrying the trigger phrasing and boundary clause a routable skill needs.
|
||||
|
||||
## Usage
|
||||
|
||||
```text
|
||||
/caveman
|
||||
```
|
||||
|
||||
Then keep working normally. To leave the mode, say "stop caveman" or "normal mode".
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | The whole skill — persistence rule, compression rules, worked examples, and the auto-clarity exception |
|
||||
@@ -2,17 +2,15 @@
|
||||
name: caveman
|
||||
disable-model-invocation: true
|
||||
description: >
|
||||
Ultra-compressed output mode: drops articles, filler and pleasantries while
|
||||
keeping technical substance exact. Cuts token usage by roughly 75%. Hand-invoked
|
||||
only — type /caveman to turn it on, "stop caveman" or "normal mode" to turn it
|
||||
off. Stays active across turns until you do.
|
||||
Ultra-compressed output mode that drops articles, filler and pleasantries while
|
||||
keeping technical substance exact, cutting token usage by roughly 75%.
|
||||
---
|
||||
|
||||
Respond terse like smart caveman. All technical substance stay. Only fluff die.
|
||||
|
||||
## Persistence
|
||||
|
||||
ACTIVE EVERY RESPONSE once triggered. No revert after many turns. No filler drift. Still active if unsure. Off only when user says "stop caveman" or "normal mode".
|
||||
ACTIVE EVERY RESPONSE once user type `/caveman`. No revert after many turns. No filler drift. Still active if unsure. Off only when user says "stop caveman" or "normal mode".
|
||||
|
||||
## Rules
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
# diagnose
|
||||
|
||||
A six-phase discipline for hard bugs and performance regressions: feedback loop → reproduce → hypothesise → instrument → fix with a regression test → clean up.
|
||||
|
||||
## What it does
|
||||
|
||||
Imposes an order of operations on debugging so the agent cannot skip to guessing. The load-bearing phase is the first one: build a fast, deterministic, agent-runnable pass/fail signal for the bug. Everything downstream — bisection, hypothesis testing, instrumentation — just consumes that signal, so the skill refuses to advance to Phase 2 without one, and says so explicitly rather than hypothesising blind.
|
||||
|
||||
The remaining phases each carry a constraint worth knowing about: hypotheses are generated 3–5 at a time and must be falsifiable, so the first plausible idea cannot anchor the whole investigation; every debug log is tagged with a unique prefix (`[DEBUG-a4f2]`) so cleanup is a single grep; the regression test is written before the fix and only at a seam that exercises the real bug pattern; and the run closes by asking what would have prevented the bug, handing off to `improve-codebase-architecture` when the answer is architectural.
|
||||
|
||||
Performance regressions take a branch of their own inside Phase 4 — baseline measurement and bisection, not logs.
|
||||
|
||||
## Conditional reading
|
||||
|
||||
Neither reference file is read on every run; `SKILL.md` names the condition for each.
|
||||
|
||||
- `references/feedback-loops.md` is read when Phase 1 has no signal yet, or when the loop you have is slow or intermittent.
|
||||
- `references/regression-seams.md` is read when Phase 5 leaves you unsure whether the available seam is deep enough — or whether one exists at all.
|
||||
|
||||
## Usage
|
||||
|
||||
```text
|
||||
/diagnose
|
||||
```
|
||||
|
||||
Describe the bug or the regression. For filing and triaging a reported bug rather than diagnosing it, use `triage`; for test-first feature work, use `tdd`.
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | The six phases and their gates — what must be true before each one ends |
|
||||
| `references/feedback-loops.md` | Loaded when Phase 1 has no loop or the loop is too weak: ten ways to construct one ordered by cost, how to sharpen an existing loop, handling intermittent bugs, and what to ask the user for when the bug resists reproduction |
|
||||
| `references/regression-seams.md` | Loaded when Phase 5 is unsure about the seam: what makes a seam correct, the four shapes of a too-shallow seam, and what to do when no correct seam exists |
|
||||
| `assets/hitl-loop.template.sh` | Copy-and-edit bash template for the last-resort human-in-the-loop feedback loop, cited by `references/feedback-loops.md`. Provides `step` and `capture` helpers and prints captured values as `KEY=VALUE` for the agent to parse |
|
||||
@@ -18,7 +18,9 @@ When exploring the codebase, use the project's domain glossary to get a clear me
|
||||
|
||||
Spend disproportionate effort here. **Be aggressive. Be creative. Refuse to give up.**
|
||||
|
||||
Read `references/feedback-loops.md` — even if you already have a signal. Ten ways to build a loop ordered by cost, how to sharpen the one you have, and what to do when the bug resists reproduction. An unsharpened loop is usually not good enough yet.
|
||||
**If you do not yet have such a signal, read `references/feedback-loops.md`** — ten ways to build one ordered by cost, and what to ask the user for when the bug resists reproduction entirely.
|
||||
|
||||
**If you do have one, it is probably not sharp enough yet.** Make it faster and more deterministic, and make it assert on the exact symptom rather than "didn't crash" — a 30-second flaky loop is barely better than no loop. If it stays slow or intermittent after that, read that file's "Iterate on the loop itself" and "Intermittent bugs" sections.
|
||||
|
||||
Do not proceed to Phase 2 until you have a loop you believe in. If you cannot build one, stop and say so explicitly, listing what you tried — never hypothesise without a signal.
|
||||
|
||||
@@ -62,13 +64,11 @@ Tool preference:
|
||||
|
||||
## Phase 5 — Fix + regression test
|
||||
|
||||
Write the regression test **before the fix** — but only if there is a **correct seam** for it.
|
||||
Write the regression test **before the fix** — but only at a **correct seam**: one where the test exercises the real bug pattern as it occurs at the call site. If the available seam looks too shallow, or you cannot tell whether it is, read `references/regression-seams.md`.
|
||||
|
||||
A correct seam is one where the test exercises the **real bug pattern** as it occurs at the call site. If the only available seam is too shallow (single-caller test when the bug needs multiple callers, unit test that can't replicate the chain that triggered the bug), a regression test there gives false confidence.
|
||||
**If no correct seam exists, that itself is the finding.** Note it and carry it into Phase 6 — the architecture is preventing the bug from being locked down.
|
||||
|
||||
**If no correct seam exists, that itself is the finding.** Note it. The codebase architecture is preventing the bug from being locked down. Flag this for the next phase.
|
||||
|
||||
If a correct seam exists:
|
||||
At a correct seam:
|
||||
|
||||
1. Turn the Phase 1 loop into a failing test at that seam, narrowed to the symptom captured in Phase 2.
|
||||
2. Watch it fail.
|
||||
|
||||
File renamed without changes.
@@ -13,7 +13,7 @@ A feedback loop is a fast, deterministic, agent-runnable pass/fail signal for th
|
||||
7. **Property / fuzz loop.** If the bug is "sometimes wrong output", run 1000 random inputs and look for the failure mode.
|
||||
8. **Bisection harness.** If the bug appeared between two known states (commit, dataset, version), automate "boot at state X, check, repeat" so you can `git bisect run` it.
|
||||
9. **Differential loop.** Run the same input through old-version vs new-version (or two configs) and diff outputs.
|
||||
10. **HITL bash script.** Last resort. If a human must click, drive _them_ with `scripts/hitl-loop.template.sh` so the loop is still structured. Captured output feeds back to you.
|
||||
10. **HITL bash script.** Last resort. If a human must click, drive _them_ with `assets/hitl-loop.template.sh` so the loop is still structured. Captured output feeds back to you.
|
||||
|
||||
## Iterate on the loop itself
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# Judging a regression-test seam
|
||||
|
||||
Read this when Phase 5 leaves you unsure whether the seam available for the regression test is the correct one — either because the obvious seam looks shallow, or because there appears to be no seam at all.
|
||||
|
||||
## What makes a seam correct
|
||||
|
||||
A correct seam is one where the test exercises the **real bug pattern** as it occurs at the call site: the same entry point, the same participants, the same ordering, and the same state the real caller holds when it goes wrong.
|
||||
|
||||
## Seams that are too shallow
|
||||
|
||||
- A single-caller test when the bug only appears with multiple callers.
|
||||
- A unit test that cannot replicate the chain of calls that triggered the bug.
|
||||
- A test that reproduces the symptom by construction — asserting on a value the test itself set — rather than by driving the code path that produces it.
|
||||
- A test that mocks out the collaborator the bug actually lives in.
|
||||
|
||||
A regression test at a shallow seam gives false confidence. It passes forever, including after a change reintroduces the bug at the real call site, and it will be read by the next maintainer as proof the bug is locked down.
|
||||
|
||||
## When there is no correct seam
|
||||
|
||||
Do not force one, and do not settle for a shallow seam to have something green. Instead:
|
||||
|
||||
1. Apply the fix and verify it against the Phase 1 loop directly.
|
||||
2. Write down which seams you considered and why each was too shallow.
|
||||
3. Carry that into Phase 6's "what would have prevented this bug" question. A missing seam is an architecture finding — tangled callers, hidden coupling, or a module with no testable boundary — and the handoff is the `improve-codebase-architecture` skill, with those specifics attached.
|
||||
@@ -0,0 +1,27 @@
|
||||
# grill-me
|
||||
|
||||
Interview the user relentlessly about a plan or design until the decision tree is fully resolved.
|
||||
|
||||
## What it does
|
||||
|
||||
Turns the agent into an interviewer rather than an implementer. It walks the design tree branch by branch, resolving dependencies between decisions one at a time, and offers its own recommended answer alongside each question so the user has something concrete to push against. Two rules give it its shape: **one question at a time**, and **never ask what the codebase can answer** — if a question is settleable by reading the code, the agent goes and reads the code instead of spending the user's attention on it.
|
||||
|
||||
## Composition
|
||||
|
||||
This is the plain grilling loop, with no documentation side effects. The sibling `grill-with-docs` skill runs the same interview but additionally challenges answers against the project's `CONTEXT.md` glossary and existing ADRs, and writes decisions back into those files as they crystallise. Reach for that one when the project has a domain model worth defending; reach for this one when it does not, or when nothing should be written down yet.
|
||||
|
||||
`triage` composes the documented variant, not this one, when an issue needs fleshing out.
|
||||
|
||||
## Usage
|
||||
|
||||
```text
|
||||
/grill-me
|
||||
```
|
||||
|
||||
Describe the plan or design to be stress-tested. Expect questions one at a time, each with a recommended answer.
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | The whole skill — the interview instruction, the one-question-at-a-time rule, and the explore-instead-of-asking rule |
|
||||
@@ -0,0 +1,36 @@
|
||||
# grill-with-docs
|
||||
|
||||
The grilling interview, run against the project's domain model — and writing decisions back into `CONTEXT.md` and ADRs as they land.
|
||||
|
||||
## What it does
|
||||
|
||||
Runs the same relentless one-question-at-a-time interview as `grill-me`, with the project's own documentation as an active participant. During codebase exploration it also locates the domain documentation — a root `CONTEXT.md` and `docs/adr/`, or a `CONTEXT-MAP.md` pointing at per-context glossaries and ADR directories in a multi-context repo — and then uses it four ways:
|
||||
|
||||
- **Challenges terms against the glossary.** When the user's usage conflicts with what `CONTEXT.md` already defines, that is raised immediately rather than absorbed.
|
||||
- **Sharpens fuzzy language** by proposing a precise canonical term ("you're saying 'account' — do you mean the Customer or the User?").
|
||||
- **Cross-references claims against the code**, and surfaces contradictions between what the user says happens and what the code does.
|
||||
- **Updates `CONTEXT.md` inline**, the moment a term is resolved, rather than batching changes to the end of the session where they get lost.
|
||||
|
||||
Files are created lazily — only when there is something real to write.
|
||||
|
||||
ADRs are offered *sparingly*, and only when all three tests pass: the decision is hard to reverse, it would surprise a future reader without the context, and it was a genuine trade-off with real alternatives. Missing any one of the three means no ADR.
|
||||
|
||||
## Composition
|
||||
|
||||
`grill-me` is the same interview without the documentation side effects — use it when there is no domain model to defend or nothing should be written down yet. `triage` composes this skill (not `grill-me`) at step 4 when an issue needs fleshing out. `improve-codebase-architecture` runs its own grilling loop and borrows this skill's `CONTEXT.md` and ADR discipline for the decisions that come out of it.
|
||||
|
||||
## Usage
|
||||
|
||||
```text
|
||||
/grill-with-docs
|
||||
```
|
||||
|
||||
Describe the plan or design. Expect questions one at a time, each with a recommended answer, and expect `CONTEXT.md` to be edited during the session rather than after it.
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | The interview instruction plus the domain-awareness rules: file layout discovery, the four during-session behaviours, and the three-part ADR test |
|
||||
| `CONTEXT-FORMAT.md` | Skill-root document, cited when a term is resolved: the structure of a `CONTEXT.md` and how to write a Language entry |
|
||||
| `ADR-FORMAT.md` | Skill-root document, cited when an ADR is offered: `docs/adr/` naming, sequential numbering, and the ADR template |
|
||||
@@ -0,0 +1,36 @@
|
||||
# improve-codebase-architecture
|
||||
|
||||
Surface architectural friction and propose deepening opportunities — refactors that turn shallow modules into deep ones.
|
||||
|
||||
## What it does
|
||||
|
||||
Looks for places where a codebase is hard to understand, hard to test, or hard for an agent to navigate, and proposes refactors that concentrate behaviour behind smaller interfaces. It runs in three stages:
|
||||
|
||||
1. **Explore.** Reads the domain glossary and any ADRs in the area first, then walks the codebase with an `Explore` sub-agent — organically, noting friction rather than applying fixed heuristics. The **deletion test** is the filter: imagine deleting the module; if complexity vanishes it was a pass-through, if complexity reappears across N callers it was earning its keep.
|
||||
2. **Present candidates.** A numbered list, each with files, problem, solution and benefits — benefits stated in terms of *locality* and *leverage* and of how tests would improve. No interfaces are proposed yet; the user picks one.
|
||||
3. **Grilling loop.** Walks the design tree for the chosen candidate, with documentation side effects landing inline as decisions crystallise.
|
||||
|
||||
The skill is opinionated about vocabulary, and that is the point: **module, interface, implementation, depth, seam, adapter, leverage, locality**, used exactly, with no drift into "component", "service", "API" or "boundary". Domain nouns come from `CONTEXT.md`, architecture nouns from `LANGUAGE.md` — so a proposal reads as "the Order intake module", never "the FooBarHandler".
|
||||
|
||||
ADRs are treated as decisions not to be re-litigated. A candidate that contradicts one is surfaced only when the friction is real enough to warrant reopening it, and is marked as such.
|
||||
|
||||
## Composition
|
||||
|
||||
`diagnose` hands off here when a bug's post-mortem concludes that no correct test seam exists, or that callers are tangled — the recommendation is made after the fix is in, not before. The grilling loop follows `grill-with-docs`'s discipline for `CONTEXT.md` entries and ADR offers, and `SKILL.md` names that skill's format documents directly.
|
||||
|
||||
## Usage
|
||||
|
||||
```text
|
||||
/improve-codebase-architecture
|
||||
```
|
||||
|
||||
Point at a codebase or an area of one. Expect a numbered candidate list and a "which of these would you like to explore?" before any interface design happens.
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | Condensed glossary, key principles, and the three-stage process |
|
||||
| `LANGUAGE.md` | Skill-root document, cited throughout `SKILL.md`: full definitions of every term, the words each one replaces, and the full principle list |
|
||||
| `INTERFACE-DESIGN.md` | Skill-root document, read at stage 3 when the user wants alternative interfaces explored: the parallel sub-agent "Design It Twice" pattern, framing the problem space, and the per-agent design constraints |
|
||||
| `DEEPENING.md` | Skill-root document, cited from `INTERFACE-DESIGN.md`: how to deepen a cluster of shallow modules safely, the four dependency categories (in-process, local-substitutable, remote-but-owned, true external), seam discipline, and the replace-don't-layer testing strategy |
|
||||
@@ -65,7 +65,7 @@ Once the user picks a candidate, drop into a grilling conversation. Walk the des
|
||||
|
||||
Side effects happen inline as decisions crystallize:
|
||||
|
||||
- **Naming a deepened module after a concept not in `CONTEXT.md`?** Add the term to `CONTEXT.md` — same discipline as `/grill-with-docs` (see [CONTEXT-FORMAT.md](../grill-with-docs/CONTEXT-FORMAT.md)). Create the file lazily if it doesn't exist.
|
||||
- **Naming a deepened module after a concept not in `CONTEXT.md`?** Add the term to `CONTEXT.md` — same discipline as `grill-with-docs`, in the format `grill-with-docs`'s `CONTEXT-FORMAT.md` defines. Create the file lazily if it doesn't exist.
|
||||
- **Sharpening a fuzzy term during the conversation?** Update `CONTEXT.md` right there.
|
||||
- **User rejects the candidate with a load-bearing reason?** Offer an ADR, framed as: _"Want me to record this as an ADR so future architecture reviews don't re-suggest it?"_ Only offer when the reason would actually be needed by a future explorer to avoid re-suggesting the same thing — skip ephemeral reasons ("not worth it right now") and self-evident ones. See [ADR-FORMAT.md](../grill-with-docs/ADR-FORMAT.md).
|
||||
- **User rejects the candidate with a load-bearing reason?** Offer an ADR, framed as: _"Want me to record this as an ADR so future architecture reviews don't re-suggest it?"_ Only offer when the reason would actually be needed by a future explorer to avoid re-suggesting the same thing — skip ephemeral reasons ("not worth it right now") and self-evident ones. See `grill-with-docs`'s `ADR-FORMAT.md`.
|
||||
- **Want to explore alternative interfaces for the deepened module?** See [INTERFACE-DESIGN.md](INTERFACE-DESIGN.md).
|
||||
@@ -0,0 +1,32 @@
|
||||
# prototype
|
||||
|
||||
Build a throwaway prototype that answers one design question — either a runnable terminal app or several UI variations.
|
||||
|
||||
## What it does
|
||||
|
||||
Treats a prototype as **throwaway code that answers a question**, and lets the question decide the artifact. `SKILL.md` opens with a two-row dispatch table and the run resolves exactly one row before doing anything else:
|
||||
|
||||
- *"Does this logic / state model feel right?"* → a tiny interactive terminal app that pushes the state machine through the cases that are hard to reason about on paper.
|
||||
- *"What should this look like?"* → several radically different UI variations on one route, switchable from a floating bottom bar via a URL search param.
|
||||
|
||||
The two branches produce fundamentally different artifacts, so picking wrong wastes the whole prototype. When the question is genuinely ambiguous and the user is unreachable, the skill defaults on the shape of the surrounding code (backend module → logic, page or component → UI) and states the assumption at the top of the prototype rather than silently choosing.
|
||||
|
||||
Six rules apply to both branches: throwaway and visibly named as such, one command to run, no persistence by default, no polish, surface the full state after every action or variant switch, and delete or absorb the prototype when it is done. The *answer* is the only durable output — the skill captures it in a commit message, ADR, issue or `NOTES.md` before the code is deleted.
|
||||
|
||||
## Usage
|
||||
|
||||
```text
|
||||
/prototype
|
||||
```
|
||||
|
||||
State the design question. For production code, use `tdd`; for talking a design through without building anything, use `grill-me`.
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | The branch dispatch table and the rules that apply to both branches |
|
||||
| `references/logic.md` | The logic branch, read only when that row is selected: when it is the right shape, and how to build the interactive terminal app |
|
||||
| `references/ui.md` | The UI branch, read only when that row is selected: when it is the right shape, and how to build and switch between the variations |
|
||||
|
||||
Each reference is self-contained — a run reads one of the two, never both.
|
||||
@@ -3,8 +3,8 @@ name: prototype
|
||||
description: >
|
||||
Use when the user wants a throwaway prototype to answer a design question about
|
||||
a data model, state machine or business logic, or to mock up a UI in several
|
||||
variations, as in "try a few designs". Not production code -> `tdd`. Not
|
||||
talking a design through without building -> `grill-me`.
|
||||
variations. Not production code -> `tdd`. Not talking a design through ->
|
||||
`grill-me`.
|
||||
---
|
||||
|
||||
# Prototype
|
||||
@@ -13,10 +13,12 @@ A prototype is **throwaway code that answers a question**. The question decides
|
||||
|
||||
## Pick a branch
|
||||
|
||||
Identify which question is being answered — from the user's prompt, the surrounding code, or by asking if the user is around:
|
||||
| Question being answered | Build | Reference |
|
||||
|---|---|---|
|
||||
| "Does this logic / state model feel right?" | A tiny interactive terminal app that pushes the state machine through cases that are hard to reason about on paper | `references/logic.md` |
|
||||
| "What should this look like?" | Several radically different UI variations on one route, switchable via a URL search param and a floating bottom bar | `references/ui.md` |
|
||||
|
||||
- **"Does this logic / state model feel right?"** → [LOGIC.md](LOGIC.md). Build a tiny interactive terminal app that pushes the state machine through cases that are hard to reason about on paper.
|
||||
- **"What should this look like?"** → [UI.md](UI.md). Generate several radically different UI variations on a single route, switchable via a URL search param and a floating bottom bar.
|
||||
Resolve the row from the user's prompt, the surrounding code, or by asking if the user is around, then read only that reference — each is self-contained.
|
||||
|
||||
The two branches produce fundamentally different artifacts — getting this wrong wastes the whole prototype. If the question is genuinely ambiguous and the user isn't reachable, default to whichever branch better matches the surrounding code (a backend module → logic; a page or component → UI) and state the assumption at the top of the prototype.
|
||||
|
||||
|
||||
+1
-4
@@ -9,7 +9,7 @@ A tiny interactive terminal app that lets the user drive a state model by hand.
|
||||
- "I want to feel out what the API should look like before writing it."
|
||||
- Anything where the user wants to **press buttons and watch state change**.
|
||||
|
||||
If the question is "what should this look like" — wrong branch. Use [UI.md](UI.md).
|
||||
If the question is "what should this look like" — wrong branch. Read `references/ui.md`.
|
||||
|
||||
## Process
|
||||
|
||||
@@ -72,8 +72,5 @@ When the prototype has done its job, the answer to the question is the only thin
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- **Don't add tests.** A prototype that needs tests is no longer a prototype.
|
||||
- **Don't wire it to the real database.** Use an in-memory store unless the question is specifically about persistence.
|
||||
- **Don't generalise.** No "what if we wanted to support X later." The prototype answers one question.
|
||||
- **Don't blur the logic and the TUI together.** If the reducer / state machine references `console.log`, prompts, or terminal escape codes, it's no longer portable. Keep the TUI as a thin shell over a pure module.
|
||||
- **Don't ship the TUI shell into production.** The shell is optimised for being driven by hand from a terminal. The logic module behind it is the bit worth keeping.
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Generate **several radically different UI variations** on a single route, switchable from a floating bottom bar. The user flips between variants in the browser, picks one (or steals bits from each), then throws the rest away.
|
||||
|
||||
If the question is about logic/state rather than what something looks like — wrong branch. Use [LOGIC.md](LOGIC.md).
|
||||
If the question is about logic/state rather than what something looks like — wrong branch. Read `references/logic.md`.
|
||||
|
||||
## When this is the right shape
|
||||
|
||||
@@ -109,4 +109,3 @@ Don't leave variant components or the switcher lying around. They rot fast and c
|
||||
- **Variants that differ only in colour or copy.** That's a tweak, not a prototype. Real variants disagree about structure.
|
||||
- **Sharing too much code between variants.** A shared `<Header>` is fine; a shared `<Layout>` defeats the point. Each variant should be free to throw out the layout.
|
||||
- **Wiring variants to real mutations.** Read-only prototypes are fine. If a variant needs to mutate, point it at a stub — the question is "what should this look like", not "does the backend work".
|
||||
- **Promoting the prototype directly to production.** The variant code was written under prototype constraints (no tests, minimal error handling). Rewrite it properly when you fold it in.
|
||||
@@ -0,0 +1,31 @@
|
||||
# research
|
||||
|
||||
Research a tool, library or API from canonical documentation into a directory of structured per-topic reference files.
|
||||
|
||||
## What it does
|
||||
|
||||
Runs a six-step pipeline: scope against the working directory (what version is actually in use, what is already documented), resolve the topic through Context7, websearch for canonical docs covering whatever Context7 missed, read those sources, deepen one level into the links worth following, then write one markdown file per topic area plus a `sources.md` provenance record.
|
||||
|
||||
Four gotchas at the top of `SKILL.md` shape the whole run, and each exists because of a specific failure: the output path is never inferred (a guessed destination scatters a directory's worth of files through someone's source tree); nothing is written outside that path; no empty topic file is ever written (a stub `troubleshooting.md` reads downstream as researched and closed); and a Context7 "no results", redirect or header-only response does not count as coverage. If no topic area has content, the run writes nothing at all — `sources.md` included — and reports what it searched.
|
||||
|
||||
The frontmatter pins `model: sonnet` and a closed `allowed-tools` list. Notably it grants no subagent tool, so every `WebFetch` is serial and each fetched page lands in the run's own context — which is why steps 4 and 5 insist on reducing each page to notes before fetching the next, and cap deepening at roughly ten extra pages.
|
||||
|
||||
## Composition
|
||||
|
||||
`references/file-format.md` is not optional reading before the write step: the `sources.md` field names it defines are matched literally by the downstream provenance validator. Prose written in their place parses as nothing and the check passes having verified nothing.
|
||||
|
||||
## Usage
|
||||
|
||||
```text
|
||||
/research
|
||||
```
|
||||
|
||||
Name the topic and the output path — the skill will stop and ask if the path is missing. Supplying starting URLs is treated as a deliberate source choice and skips Context7 resolution and discovery. For documentation derived from existing code or specs, use `write-docs`; for a bug or incident, use `diagnose`.
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | The four gotchas and the six research steps |
|
||||
| `references/topics.md` | Read at Step 1 before narrowing scope: the default topic list (`overview`, `installation`, `configuration`, `cli-reference`, `api-reference`, `examples`, and more) and what each file covers |
|
||||
| `references/file-format.md` | Read at Step 6 before writing: the frontmatter schema for a topic file and the exact `sources.md` field names the provenance validator matches |
|
||||
@@ -8,10 +8,12 @@ description: >-
|
||||
metadata:
|
||||
category: research
|
||||
allowed-tools:
|
||||
- WebSearch
|
||||
- WebFetch
|
||||
- Grep
|
||||
- Glob
|
||||
- Read
|
||||
- Write
|
||||
- WebSearch
|
||||
- WebFetch
|
||||
- mcp__context7__resolve-library-id
|
||||
- mcp__context7__query-docs
|
||||
model: sonnet
|
||||
@@ -61,4 +63,4 @@ Merge every set of notes, Context7 and web alike, by topic area. Read `reference
|
||||
|
||||
Spell the `sources.md` field names exactly as `references/file-format.md` gives them. The downstream provenance validator matches them literally; prose in their place parses as nothing, and the check passes having verified nothing.
|
||||
|
||||
If no topic area has content, write nothing at all, `sources.md` included, and report what was searched. A directory of empty files is worse than an honest miss.
|
||||
If no topic area has content, write nothing at all, `sources.md` included, and report what was searched.
|
||||
@@ -0,0 +1,32 @@
|
||||
# tdd
|
||||
|
||||
Test-driven development as a strict red-green-refactor loop, one behaviour at a time.
|
||||
|
||||
## What it does
|
||||
|
||||
Two convictions drive this skill. The first is about what a test is for: tests verify behaviour through public interfaces, not implementation details. A good test reads like a specification ("user can checkout with valid cart") and survives refactors because it does not care about internal structure. The warning sign for a bad one is precise — the test breaks when you refactor but behaviour has not changed.
|
||||
|
||||
The second is an explicit anti-pattern: **do not write all the tests first, then all the implementation.** Horizontal slicing treats RED as "write every test" and GREEN as "write every implementation", and it produces tests of *imagined* behaviour — tests of the shape of things, insensitive to real change, committed to before the implementation was understood. The correct shape is vertical: one test → one implementation → repeat, each cycle informed by what the last one taught you.
|
||||
|
||||
The workflow is four stages: plan (confirm the interface and which behaviours matter, with the user — you cannot test everything), fire a tracer bullet (one test proving the path works end to end), loop incrementally one behaviour at a time, then refactor once everything is green. Refactoring while RED is forbidden.
|
||||
|
||||
Codebase exploration uses the project's domain glossary, so test names and interface vocabulary match the project's language, and ADRs in the area are respected.
|
||||
|
||||
## Usage
|
||||
|
||||
```text
|
||||
/tdd
|
||||
```
|
||||
|
||||
Describe the feature or bug. Expect the skill to ask what the public interface should look like and which behaviours matter most before any code is written. For diagnosing an existing bug rather than building test-first, use `diagnose`; for throwaway exploratory code, use `prototype`.
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | Philosophy, the horizontal-slicing anti-pattern, the four-stage workflow, and the per-cycle checklist |
|
||||
| `tests.md` | Skill-root document, cited from Philosophy: worked good and bad test examples |
|
||||
| `mocking.md` | Skill-root document, cited from Philosophy: mock at system boundaries only, and what not to mock |
|
||||
| `deep-modules.md` | Skill-root document, cited from stage 1: what a deep module is (small interface, large implementation) and why it is the design to aim for |
|
||||
| `interface-design.md` | Skill-root document, cited from stage 1: designing interfaces for testability, starting with accepting dependencies rather than creating them |
|
||||
| `refactoring.md` | Skill-root document, cited from stage 4: the refactor-candidate checklist — duplication, long methods, shallow modules, feature envy, primitive obsession |
|
||||
@@ -1,6 +1,6 @@
|
||||
# Writing Agent Briefs
|
||||
|
||||
An agent brief is a structured comment posted on a GitHub issue when it moves to `ready-for-agent`. It is the authoritative specification that an AFK agent will work from. The original issue body and discussion are context — the agent brief is the contract.
|
||||
An agent brief is a structured comment posted on an issue in the issue tracker when it moves to `ready-for-agent`. It is the authoritative specification that an AFK agent will work from. The original issue body and discussion are context — the agent brief is the contract.
|
||||
|
||||
## Principles
|
||||
|
||||
@@ -27,7 +27,7 @@ Describe **what** the system should do, not **how** to implement it. The agent w
|
||||
|
||||
The agent needs to know when it's done. Every agent brief must have concrete, testable acceptance criteria. Each criterion should be independently verifiable.
|
||||
|
||||
- **Good:** "Running `gh issue list --label needs-triage` returns issues that have been through initial classification"
|
||||
- **Good:** "Querying the issue tracker for the `needs-triage` label returns issues that have been through initial classification"
|
||||
- **Bad:** "Triage should work correctly"
|
||||
|
||||
### Explicit scope boundaries
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
# triage
|
||||
|
||||
Move issues on the project issue tracker through a small state machine of triage roles.
|
||||
|
||||
## What it does
|
||||
|
||||
Gives issue triage an explicit state model and a fixed set of moves. Every issue carries exactly one **category** role (`bug`, `enhancement`) and one **state** role (`needs-triage`, `needs-info`, `ready-for-agent`, `ready-for-human`, `wontfix`); conflicting state roles are flagged to the maintainer before anything else happens. Unlabeled issues normally enter at `needs-triage`; `needs-info` returns there once the reporter replies. The maintainer can override at any point, and unusual transitions are questioned rather than executed silently.
|
||||
|
||||
A run does one of three things depending on what the maintainer asks for:
|
||||
|
||||
- **Show what needs attention** — three buckets, oldest first: unlabeled, `needs-triage`, and `needs-info` with reporter activity since the last triage notes.
|
||||
- **Triage a specific issue** — gather context (including prior triage notes, so resolved questions are not re-asked, and `.out-of-scope/` records that resemble the issue), recommend a category and state with reasoning, attempt reproduction for bugs *before* any grilling, run a `grill-with-docs` session if the issue needs fleshing out, then apply the outcome.
|
||||
- **Quick state override** — "move #42 to ready-for-agent" is trusted and applied directly, skipping grilling, after confirming the exact changes.
|
||||
|
||||
Two hard rules: every comment or issue the skill posts during triage must open with the AI-generated disclaimer, and the canonical role names above are *not* necessarily the label strings in the tracker — the mapping has to be supplied to the run.
|
||||
|
||||
## Composition
|
||||
|
||||
`grill-with-docs` is invoked at step 4 when an issue needs fleshing out; whatever that session establishes is carried into the triage notes so the work is not lost. The reverse direction also exists: `diagnose` names this skill as the place to send a *reported* bug that needs filing rather than debugging.
|
||||
|
||||
## Usage
|
||||
|
||||
```text
|
||||
/triage
|
||||
```
|
||||
|
||||
Then describe what you want in natural language — "show me anything that needs my attention", "let's look at #42", "move #42 to ready-for-agent", "what's ready for agents to pick up?".
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | The roles and state machine, the three invocation modes, the needs-info template, and how to resume a prior session |
|
||||
| `AGENT-BRIEF.md` | Skill-root document, cited when an issue moves to `ready-for-agent` (and reused for `ready-for-human`): how to write a brief that stays durable for weeks while the codebase moves under it — describe interfaces and behavioural contracts, not line numbers |
|
||||
| `OUT-OF-SCOPE.md` | Skill-root document, cited when an enhancement is closed `wontfix` and when checking for prior rejections: how the `.out-of-scope/` knowledge base is laid out and what it is for — institutional memory, and deduplication against re-litigated requests |
|
||||
@@ -35,7 +35,7 @@ Five **state** roles:
|
||||
|
||||
Every triaged issue should carry exactly one category role and one state role. If state roles conflict, flag it and ask the maintainer before doing anything else.
|
||||
|
||||
These are canonical role names — the actual label strings used in the issue tracker may differ. The mapping should have been provided to you - run `/setup-matt-pocock-skills` if not.
|
||||
These are canonical role names — the actual label strings used in the issue tracker may differ. Resolve each canonical name against the tracker's live label set before applying it, using whichever tracker skill this install provides. If a name has no counterpart there, report the gap and ask the maintainer for the mapping — never substitute a guess.
|
||||
|
||||
State transitions: an unlabeled issue normally goes to `needs-triage` first; from there it moves to `needs-info`, `ready-for-agent`, `ready-for-human`, or `wontfix`. `needs-info` returns to `needs-triage` once the reporter replies. The maintainer can override at any time — flag transitions that look unusual and ask before proceeding.
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
# write-docs
|
||||
|
||||
Produce technical documentation derived from code and spec, one section at a time, with a confirmation gate on every section.
|
||||
|
||||
## What it does
|
||||
|
||||
Casts the agent as a technical writer with one non-negotiable constraint: **every claim must be traceable to a source file line, a spec section, or an explicit user statement.** Nothing is invented, and behaviour that genuinely cannot be documented from the available sources is marked out-of-scope rather than explained away.
|
||||
|
||||
The process is eight steps — identify scope, read and extract, gap check, draft section by section, confirmation gate, delta summary, reader testing, finalise — and several of them are deliberately gated on the human:
|
||||
|
||||
- Files are read only after the user approves them by name. The skill may propose candidates; it waits.
|
||||
- The **gap check** presents what the code does say and asks the user to fill only what it does not: caller intent, error-handling rationale, non-obvious side effects.
|
||||
- No section is finalised until the full revised text has been shown. The skill never gates on output the user has not seen, and never reprints the whole document — all edits are surgical.
|
||||
- **Reader testing** predicts 5–10 questions a target reader would ask, then spawns a sub-agent that receives only the finished doc and the questions — no source files. If the doc cannot answer them, neither can the sub-agent, and the run loops back to drafting.
|
||||
|
||||
Summary and overview sections are written last, once the detail sections are stable.
|
||||
|
||||
## Usage
|
||||
|
||||
```text
|
||||
/write-docs
|
||||
```
|
||||
|
||||
Name the files or modules to document, the target audience (developer / user / contributor / internal), and the documentation type (reference, guide, README section, inline comment, changelog entry). For a PRD, ADR or decision doc, use `grill-me` or `grill-with-docs` instead — those have dedicated handling.
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | The whole skill — role, use/do-not-use boundaries, required inputs, constraints, the eight-step process, output format, failure handling, and a nine-item self-check |
|
||||
@@ -35,7 +35,7 @@ You are a technical writer that produces documentation by reading code and spec
|
||||
- User says "write docs for X", "document this", "create docs for this feature", "write a README for this"
|
||||
|
||||
**Do not use when:**
|
||||
- User wants a PRD, decision doc, or architecture proposal → `to-prd` or `grill-me`
|
||||
- User wants a PRD, decision doc, or architecture proposal → `grill-me` or `grill-with-docs`
|
||||
- User wants to document a skill file (skill files are self-describing)
|
||||
- User wants marketing or blog copy
|
||||
- Documentation requires tacit organisational knowledge that cannot be read from code or spec
|
||||
@@ -88,7 +88,7 @@ You are a technical writer that produces documentation by reading code and spec
|
||||
- Stage skipped without a logged reason → flag and require the one-sentence log before continuing
|
||||
- Code behaviour is undocumentable (internal implementation detail, no public spec) → note as out-of-scope in the doc; do not invent an explanation
|
||||
- Reader Testing sub-agent fails on multiple questions → surface the failures, return to step 4; do not mark complete
|
||||
- Requested output is a PRD, decision doc, or architecture proposal → redirect to `to-prd`, `grill-me`, or `grill-with-docs`
|
||||
- Requested output is a PRD, decision doc, or architecture proposal → redirect to `grill-me` or `grill-with-docs`
|
||||
|
||||
## Self-check
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# zoom-out
|
||||
|
||||
Ask the agent to go up a layer of abstraction and map the modules and callers around unfamiliar code.
|
||||
|
||||
## What it does
|
||||
|
||||
A single-purpose prompt for the moment you land in a part of the codebase you do not know. Instead of answering at the level of the file in front of it, the agent climbs one layer and produces a map of the relevant modules and their callers — and names them using the project's own domain glossary vocabulary, so the map lines up with the language the rest of the repo already uses.
|
||||
|
||||
## Hand-invoked only
|
||||
|
||||
`SKILL.md` sets `disable-model-invocation: true`, so the router never selects this skill on its own and no other skill can hand off to it. It runs when the human asks for it. That also means its description is written as one plain human-facing sentence — it carries no trigger phrasing or boundary clause, because nothing routes on it.
|
||||
|
||||
## Usage
|
||||
|
||||
```text
|
||||
/zoom-out
|
||||
```
|
||||
|
||||
Best used with the unfamiliar code already in context — the skill widens the view around what you are looking at rather than picking a starting point for you.
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | The whole skill — a single instruction, no supporting files |
|
||||
@@ -33,6 +33,6 @@ hand-edit made outside `agentsmd-author` — the audit is what confirms the resu
|
||||
| `tests/validate-drift.bats` | (source-only) Bats test suite for `scripts/validate-drift.sh` |
|
||||
|
||||
Rows marked **(source-only)** exist in the authoring source (`.apm/skills/agentsmd-audit/`) but are
|
||||
not present in an installed plugin: `scripts/sync-plugin-content.sh` strips `<category>/<name>/tests`
|
||||
when it generates the flat mirror, because these are dev-time fixtures no plugin host needs to
|
||||
discover (ADR-0017). Run them from a repo checkout, not from an install.
|
||||
not present in an installed plugin: the repo's `scripts/sync-plugin-content.sh` strips
|
||||
`<category>/<name>/tests` when it generates the flat mirror, because these are dev-time fixtures no
|
||||
plugin host needs to discover (ADR-0017). Run them from a repo checkout, not from an install.
|
||||
@@ -1,10 +1,10 @@
|
||||
---
|
||||
name: agentsmd-audit
|
||||
description: >
|
||||
Use when the user wants a repo's AGENTS.md audited — "audit this AGENTS.md",
|
||||
"is this AGENTS.md safe to commit" — or after a hand-edit outside
|
||||
`agentsmd-author`. Reports secrets, structure and drift; never edits.
|
||||
Not for CLAUDE.md or provider files -> `provider-adapter-author`.
|
||||
Use when the user wants a repo's AGENTS.md audited for secrets, structure
|
||||
and drift — "is this AGENTS.md safe to commit" — or after a hand-edit
|
||||
outside `agentsmd-author`.
|
||||
Not converting a provider file -> `provider-adapter-author`.
|
||||
Not writing AGENTS.md -> `agentsmd-author`.
|
||||
allowed-tools: Bash Read
|
||||
metadata:
|
||||
@@ -31,7 +31,7 @@ bash scripts/validate-structure.sh <repo-root>
|
||||
bash scripts/validate-drift.sh <repo-root>
|
||||
```
|
||||
|
||||
Each script walks the repo for every `AGENTS.md` file (root and nested, excluding `.git`, `node_modules`, `vendor`, and similar) and prints `FAIL`/`INFO`/`SUGGESTION` lines with `Why`/`Fix` (or `Note`) per finding. A nonzero exit means at least one FAIL was found in that dimension. If a script cannot execute (`python3` unavailable, Bash denied), fall back to manual review: scan for real-looking credentials, check common sections are present, and spot-check a few referenced commands/paths by hand. Grade a manual finding the way the scripts grade theirs: a missing common section (e.g. no "Security" heading) is informational, not a failure — not every repo needs every section from the checklist. Only flag a FAIL when the file is empty, entirely unfilled placeholder text, or contains a real embedded secret/stale reference.
|
||||
Each script walks the repo for every `AGENTS.md` file (root and nested, excluding `.git`, `node_modules`, `vendor`, and similar) and prints `FAIL` lines, plus `INFO`/`SUGGESTION` where applicable, with `Why`/`Fix` (or `Note`) per finding. A nonzero exit means at least one FAIL was found in that dimension. If a script cannot execute (`python3` unavailable, Bash denied), fall back to manual review: scan for real-looking credentials, check common sections are present, and spot-check a few referenced commands/paths by hand. Grade a manual finding the way the scripts grade theirs: a missing common section (e.g. no "Security" heading) is informational, not a failure — not every repo needs every section from the checklist. Only flag a FAIL when the file is empty, entirely unfilled placeholder text, or contains a real embedded secret/stale reference.
|
||||
|
||||
## Step 2 — Report
|
||||
|
||||
@@ -43,16 +43,4 @@ Checked: secrets · structure · drift
|
||||
|
||||
Then output only findings that were found, in this order within a repo: `### Secrets`, `### Structure`, `### Drift`. Omit a dimension heading entirely if it produced nothing — its absence confirms it passed. Report each finding verbatim as emitted by the scripts (they already carry file:line, Why/Fix or Note).
|
||||
|
||||
Close with a result block:
|
||||
|
||||
```text
|
||||
## Result
|
||||
|
||||
PASS
|
||||
PASS · P info
|
||||
PASS (N suggestions) · P info
|
||||
FAIL (N fails)
|
||||
FAIL (N fails) · P info
|
||||
```
|
||||
|
||||
INFO and SUGGESTION findings are observational — they never flip PASS to FAIL. Do not fix anything — this skill reports and proposes only. Point the user to `agentsmd-author` to apply fixes.
|
||||
Close with a `## Result` block holding one line: `PASS`, `PASS (N suggestions)`, or `FAIL (N fails · M suggestions)`, each optionally followed by ` · P info`. Omit the suggestion count when there are none, and omit `· P info` when there are none. INFO and SUGGESTION findings are observational — they never flip PASS to FAIL. Do not fix anything — this skill reports and proposes only. Point the user to `agentsmd-author` to apply fixes.
|
||||
@@ -3,7 +3,7 @@ name: agentsmd-author
|
||||
description: >
|
||||
Use when the user wants a repo's AGENTS.md written or updated, root or
|
||||
nested, including "document this for AI coding tools". Writes only verified
|
||||
conventions. Not review-only -> `agentsmd-audit`. Not for CLAUDE.md ->
|
||||
conventions. Not review-only -> `agentsmd-audit`. Not converting CLAUDE.md ->
|
||||
`provider-adapter-author`.
|
||||
allowed-tools: Bash Read Write Edit
|
||||
metadata:
|
||||
@@ -36,8 +36,8 @@ AGENTS.md has no required schema. Use only sections that reflect something real
|
||||
|
||||
## Step 4 — Check for an existing provider file
|
||||
|
||||
Look for `CLAUDE.md`, `.cursor/rules/*.mdc`, `.github/copilot-instructions.md`, or similar in the target repo. If one exists and now duplicates content the AGENTS.md you just wrote/updated already owns, invoke the `provider-adapter-author` skill on it to reconcile.
|
||||
Look for `CLAUDE.md`, `.cursor/rules/*.mdc`, `.github/copilot-instructions.md`, or similar in the target repo. If one exists, invoke the `provider-adapter-author` skill on it to reconcile — whether it duplicates content the AGENTS.md you just wrote/updated now owns, or is merely stale or missing a pointer to it. Never edit it yourself in either case.
|
||||
|
||||
## Step 5 — Audit and report
|
||||
|
||||
Invoke the `agentsmd-audit` skill directly on the AGENTS.md file(s) you just wrote or updated. This closeout is mandatory, not optional, even when the change looks trivial — never sign the work off on your own judgment. Resolve any FAIL findings before considering the work done — re-invoke this skill's own writing steps to fix them, then re-run the audit, same as any other close-the-loop check. Report what was created/changed, whether a provider file was reconciled, and the audit's final result.
|
||||
Invoke the `agentsmd-audit` skill on the target repo root — its validators take a `<repo-root>` and walk the tree for every AGENTS.md themselves; there is no per-file entry point. This closeout is mandatory, not optional, even when the change looks trivial — never sign the work off on your own judgment. Resolve any FAIL findings before considering the work done — re-invoke this skill's own writing steps to fix them, then re-run the audit, same as any other close-the-loop check. Report what was created/changed, whether a provider file was reconciled, and the audit's final result.
|
||||
@@ -31,6 +31,6 @@ Provide the path to the provider-specific file to convert (and the target repo r
|
||||
| `tests/validate-adapter.bats` | (source-only) Bats test suite for `scripts/validate-adapter.sh` |
|
||||
|
||||
Rows marked **(source-only)** exist in the authoring source (`.apm/skills/provider-adapter-author/`)
|
||||
but are not present in an installed plugin: `scripts/sync-plugin-content.sh` strips
|
||||
but are not present in an installed plugin: the repo's `scripts/sync-plugin-content.sh` strips
|
||||
`<category>/<name>/tests` when it generates the flat mirror, because these are dev-time fixtures no
|
||||
plugin host needs to discover (ADR-0017). Run them from a repo checkout, not from an install.
|
||||
@@ -2,7 +2,8 @@
|
||||
name: provider-adapter-author
|
||||
description: >
|
||||
Use when a provider file (CLAUDE.md, .cursor rules, copilot-instructions)
|
||||
duplicating the repo's AGENTS.md should be cut to a thin adapter.
|
||||
duplicating the repo's AGENTS.md should be cut to a thin adapter — "make
|
||||
CLAUDE.md just import AGENTS.md".
|
||||
Not writing the AGENTS file -> `agentsmd-author`.
|
||||
Not auditing the AGENTS file -> `agentsmd-audit`.
|
||||
allowed-tools: Bash Read Edit Write
|
||||
@@ -16,7 +17,6 @@ metadata:
|
||||
## Gotchas
|
||||
|
||||
- Assume a provider has no cross-file import mechanism until you have confirmed it has one. Claude Code is the exception, not the rule: a `CLAUDE.md` may consist of nothing but `@path` lines, while the same `@AGENTS.md` line in a Cursor rule or a Copilot instructions file is inert text no tool resolves. Pass `--no-import-syntax` to `scripts/validate-adapter.sh` for those providers.
|
||||
- Works standalone or composed-into by `agentsmd-author` — behave identically either way; don't assume a caller skill exists.
|
||||
|
||||
## Step 1 — Detect
|
||||
|
||||
@@ -43,7 +43,7 @@ Run the bundled check before finishing — this is the skill's own closeout gate
|
||||
bash scripts/validate-adapter.sh [--no-import-syntax] [--max-lines N] <adapter-file> <agents-md-file>
|
||||
```
|
||||
|
||||
Fix any `FAIL` by editing the provider file, and re-run until it exits `0`. The size `FAIL` advises moving provider-agnostic content into `AGENTS.md`; disregard that half of its wording and delete the redundant lines instead.
|
||||
Fix any `FAIL` by editing the provider file, and re-run until it exits `0`.
|
||||
|
||||
## Step 4 — Report
|
||||
|
||||
|
||||
@@ -16,10 +16,15 @@ Arguments:
|
||||
|
||||
Options:
|
||||
--no-import-syntax The target provider has no native cross-file import
|
||||
mechanism. Accept a plain-text pointer mention of
|
||||
"AGENTS.md" instead of requiring an @import-style line.
|
||||
mechanism. Require a plain-text pointer line naming
|
||||
"AGENTS.md" instead of an @import-style line; an
|
||||
@AGENTS.md line alone does not satisfy it, because
|
||||
such a provider never resolves it. Without this flag
|
||||
an actual @import line is required, and naming
|
||||
AGENTS.md in prose alone does not satisfy it.
|
||||
--max-lines N Max non-blank lines allowed in the adapter file before
|
||||
it's considered no longer "thin". Default: 60.
|
||||
it's considered no longer "thin". Must be a
|
||||
non-negative integer. Default: 60.
|
||||
--help, -h Show this help and exit 0.
|
||||
|
||||
Exit codes:
|
||||
@@ -44,7 +49,15 @@ while [[ $# -gt 0 ]]; do
|
||||
shift
|
||||
;;
|
||||
--max-lines)
|
||||
MAX_LINES="${2:-}"
|
||||
if [[ $# -lt 2 ]]; then
|
||||
echo "Error: --max-lines requires a value (a non-negative integer)." >&2
|
||||
exit 1
|
||||
fi
|
||||
MAX_LINES="$2"
|
||||
if [[ ! "$MAX_LINES" =~ ^[0-9]+$ ]]; then
|
||||
echo "Error: --max-lines expects a non-negative integer, got '$MAX_LINES'." >&2
|
||||
exit 1
|
||||
fi
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
@@ -94,21 +107,25 @@ if not adapter_content.strip():
|
||||
IMPORT_RE = re.compile(r'(?m)^\s*@\S*AGENTS\.md\s*$')
|
||||
lines = adapter_content.splitlines()
|
||||
import_lines = [ln for ln in lines if IMPORT_RE.match(ln)]
|
||||
# A prose pointer is any line naming AGENTS.md that is not itself an import
|
||||
# line — an inert `@AGENTS.md` in a provider that resolves no imports points
|
||||
# a reader at nothing.
|
||||
pointer_lines = [ln for ln in lines if not IMPORT_RE.match(ln) and "AGENTS.md" in ln]
|
||||
|
||||
if no_import_syntax:
|
||||
has_reference = "AGENTS.md" in adapter_content
|
||||
has_reference = bool(pointer_lines)
|
||||
else:
|
||||
has_reference = bool(import_lines) or "AGENTS.md" in adapter_content
|
||||
has_reference = bool(import_lines)
|
||||
|
||||
if not has_reference:
|
||||
has_fail = True
|
||||
print(f"FAIL Adapter has no reference to AGENTS.md — {adapter_path}")
|
||||
if no_import_syntax:
|
||||
print(" Why: This provider has no import syntax, so the adapter must at least mention AGENTS.md as a text pointer.")
|
||||
print(" Why: This provider resolves no cross-file import, so the adapter must point at AGENTS.md in prose; an `@AGENTS.md` line here is inert text.")
|
||||
print(" Fix: Add a sentence like \"See AGENTS.md at the repo root for shared conventions.\"")
|
||||
else:
|
||||
print(" Why: A thin adapter must import AGENTS.md (e.g. `@AGENTS.md`) rather than silently omitting it.")
|
||||
print(" Fix: Add an `@AGENTS.md` (or equivalent relative path) import line.")
|
||||
print(" Why: A thin adapter must import AGENTS.md with an `@AGENTS.md` line; merely naming the file in prose defers nothing.")
|
||||
print(" Fix: Add an `@AGENTS.md` (or equivalent relative path) import line, or pass --no-import-syntax if this provider resolves no imports.")
|
||||
print()
|
||||
|
||||
# --- Duplication check ---
|
||||
@@ -132,7 +149,7 @@ if non_blank_count > max_lines:
|
||||
has_fail = True
|
||||
print(f"FAIL Adapter is not thin — {adapter_path}")
|
||||
print(f" Why: {non_blank_count} non-blank lines exceeds the {max_lines}-line threshold for a thin adapter.")
|
||||
print(" Fix: Move provider-agnostic content into AGENTS.md; keep only genuinely provider-specific additions here.")
|
||||
print(" Fix: Delete the lines already covered by AGENTS.md; keep only genuinely provider-specific additions here.")
|
||||
print()
|
||||
|
||||
if has_fail:
|
||||
|
||||
@@ -115,6 +115,51 @@ EOF
|
||||
assert_output --partial "no reference"
|
||||
}
|
||||
|
||||
@test "the two --no-import-syntax branches disagree: a text-pointer-only adapter fails in default mode" {
|
||||
ADAPTER="$TMPDIR/copilot-instructions.md"
|
||||
cat > "$ADAPTER" <<'EOF'
|
||||
See AGENTS.md at the repo root for setup, style, and testing conventions.
|
||||
|
||||
## Copilot-specific
|
||||
Prefer inline suggestions over chat for one-line edits.
|
||||
EOF
|
||||
run bash "$SCRIPT" "$ADAPTER" "$AGENTS_MD"
|
||||
assert_failure
|
||||
assert_output --partial "no reference"
|
||||
|
||||
run bash "$SCRIPT" --no-import-syntax "$ADAPTER" "$AGENTS_MD"
|
||||
assert_success
|
||||
}
|
||||
|
||||
@test "with --no-import-syntax, an inert @AGENTS.md line alone is not a prose pointer" {
|
||||
ADAPTER="$TMPDIR/copilot-instructions.md"
|
||||
cat > "$ADAPTER" <<'EOF'
|
||||
@AGENTS.md
|
||||
|
||||
## Copilot-specific
|
||||
Prefer inline suggestions over chat for one-line edits.
|
||||
EOF
|
||||
run bash "$SCRIPT" --no-import-syntax "$ADAPTER" "$AGENTS_MD"
|
||||
assert_failure
|
||||
assert_output --partial "no reference"
|
||||
}
|
||||
|
||||
@test "--max-lines as the final argument reports a real error instead of failing silently" {
|
||||
ADAPTER="$TMPDIR/CLAUDE.md"
|
||||
echo "@AGENTS.md" > "$ADAPTER"
|
||||
run bash "$SCRIPT" "$ADAPTER" "$AGENTS_MD" --max-lines
|
||||
assert_failure
|
||||
assert_output --partial "--max-lines requires a value"
|
||||
}
|
||||
|
||||
@test "--max-lines rejects a non-numeric value with a real error" {
|
||||
ADAPTER="$TMPDIR/CLAUDE.md"
|
||||
echo "@AGENTS.md" > "$ADAPTER"
|
||||
run bash "$SCRIPT" --max-lines abc "$ADAPTER" "$AGENTS_MD"
|
||||
assert_failure
|
||||
assert_output --partial "non-negative integer"
|
||||
}
|
||||
|
||||
@test "--help exits 0 and documents usage" {
|
||||
run bash "$SCRIPT" --help
|
||||
assert_success
|
||||
|
||||
@@ -33,6 +33,6 @@ hand-edit made outside `agentsmd-author` — the audit is what confirms the resu
|
||||
| `tests/validate-drift.bats` | (source-only) Bats test suite for `scripts/validate-drift.sh` |
|
||||
|
||||
Rows marked **(source-only)** exist in the authoring source (`.apm/skills/agentsmd-audit/`) but are
|
||||
not present in an installed plugin: `scripts/sync-plugin-content.sh` strips `<category>/<name>/tests`
|
||||
when it generates the flat mirror, because these are dev-time fixtures no plugin host needs to
|
||||
discover (ADR-0017). Run them from a repo checkout, not from an install.
|
||||
not present in an installed plugin: the repo's `scripts/sync-plugin-content.sh` strips
|
||||
`<category>/<name>/tests` when it generates the flat mirror, because these are dev-time fixtures no
|
||||
plugin host needs to discover (ADR-0017). Run them from a repo checkout, not from an install.
|
||||
@@ -1,10 +1,10 @@
|
||||
---
|
||||
name: agentsmd-audit
|
||||
description: >
|
||||
Use when the user wants a repo's AGENTS.md audited — "audit this AGENTS.md",
|
||||
"is this AGENTS.md safe to commit" — or after a hand-edit outside
|
||||
`agentsmd-author`. Reports secrets, structure and drift; never edits.
|
||||
Not for CLAUDE.md or provider files -> `provider-adapter-author`.
|
||||
Use when the user wants a repo's AGENTS.md audited for secrets, structure
|
||||
and drift — "is this AGENTS.md safe to commit" — or after a hand-edit
|
||||
outside `agentsmd-author`.
|
||||
Not converting a provider file -> `provider-adapter-author`.
|
||||
Not writing AGENTS.md -> `agentsmd-author`.
|
||||
allowed-tools: Bash Read
|
||||
metadata:
|
||||
@@ -31,7 +31,7 @@ bash scripts/validate-structure.sh <repo-root>
|
||||
bash scripts/validate-drift.sh <repo-root>
|
||||
```
|
||||
|
||||
Each script walks the repo for every `AGENTS.md` file (root and nested, excluding `.git`, `node_modules`, `vendor`, and similar) and prints `FAIL`/`INFO`/`SUGGESTION` lines with `Why`/`Fix` (or `Note`) per finding. A nonzero exit means at least one FAIL was found in that dimension. If a script cannot execute (`python3` unavailable, Bash denied), fall back to manual review: scan for real-looking credentials, check common sections are present, and spot-check a few referenced commands/paths by hand. Grade a manual finding the way the scripts grade theirs: a missing common section (e.g. no "Security" heading) is informational, not a failure — not every repo needs every section from the checklist. Only flag a FAIL when the file is empty, entirely unfilled placeholder text, or contains a real embedded secret/stale reference.
|
||||
Each script walks the repo for every `AGENTS.md` file (root and nested, excluding `.git`, `node_modules`, `vendor`, and similar) and prints `FAIL` lines, plus `INFO`/`SUGGESTION` where applicable, with `Why`/`Fix` (or `Note`) per finding. A nonzero exit means at least one FAIL was found in that dimension. If a script cannot execute (`python3` unavailable, Bash denied), fall back to manual review: scan for real-looking credentials, check common sections are present, and spot-check a few referenced commands/paths by hand. Grade a manual finding the way the scripts grade theirs: a missing common section (e.g. no "Security" heading) is informational, not a failure — not every repo needs every section from the checklist. Only flag a FAIL when the file is empty, entirely unfilled placeholder text, or contains a real embedded secret/stale reference.
|
||||
|
||||
## Step 2 — Report
|
||||
|
||||
@@ -43,16 +43,4 @@ Checked: secrets · structure · drift
|
||||
|
||||
Then output only findings that were found, in this order within a repo: `### Secrets`, `### Structure`, `### Drift`. Omit a dimension heading entirely if it produced nothing — its absence confirms it passed. Report each finding verbatim as emitted by the scripts (they already carry file:line, Why/Fix or Note).
|
||||
|
||||
Close with a result block:
|
||||
|
||||
```text
|
||||
## Result
|
||||
|
||||
PASS
|
||||
PASS · P info
|
||||
PASS (N suggestions) · P info
|
||||
FAIL (N fails)
|
||||
FAIL (N fails) · P info
|
||||
```
|
||||
|
||||
INFO and SUGGESTION findings are observational — they never flip PASS to FAIL. Do not fix anything — this skill reports and proposes only. Point the user to `agentsmd-author` to apply fixes.
|
||||
Close with a `## Result` block holding one line: `PASS`, `PASS (N suggestions)`, or `FAIL (N fails · M suggestions)`, each optionally followed by ` · P info`. Omit the suggestion count when there are none, and omit `· P info` when there are none. INFO and SUGGESTION findings are observational — they never flip PASS to FAIL. Do not fix anything — this skill reports and proposes only. Point the user to `agentsmd-author` to apply fixes.
|
||||
@@ -3,7 +3,7 @@ name: agentsmd-author
|
||||
description: >
|
||||
Use when the user wants a repo's AGENTS.md written or updated, root or
|
||||
nested, including "document this for AI coding tools". Writes only verified
|
||||
conventions. Not review-only -> `agentsmd-audit`. Not for CLAUDE.md ->
|
||||
conventions. Not review-only -> `agentsmd-audit`. Not converting CLAUDE.md ->
|
||||
`provider-adapter-author`.
|
||||
allowed-tools: Bash Read Write Edit
|
||||
metadata:
|
||||
@@ -36,8 +36,8 @@ AGENTS.md has no required schema. Use only sections that reflect something real
|
||||
|
||||
## Step 4 — Check for an existing provider file
|
||||
|
||||
Look for `CLAUDE.md`, `.cursor/rules/*.mdc`, `.github/copilot-instructions.md`, or similar in the target repo. If one exists and now duplicates content the AGENTS.md you just wrote/updated already owns, invoke the `provider-adapter-author` skill on it to reconcile.
|
||||
Look for `CLAUDE.md`, `.cursor/rules/*.mdc`, `.github/copilot-instructions.md`, or similar in the target repo. If one exists, invoke the `provider-adapter-author` skill on it to reconcile — whether it duplicates content the AGENTS.md you just wrote/updated now owns, or is merely stale or missing a pointer to it. Never edit it yourself in either case.
|
||||
|
||||
## Step 5 — Audit and report
|
||||
|
||||
Invoke the `agentsmd-audit` skill directly on the AGENTS.md file(s) you just wrote or updated. This closeout is mandatory, not optional, even when the change looks trivial — never sign the work off on your own judgment. Resolve any FAIL findings before considering the work done — re-invoke this skill's own writing steps to fix them, then re-run the audit, same as any other close-the-loop check. Report what was created/changed, whether a provider file was reconciled, and the audit's final result.
|
||||
Invoke the `agentsmd-audit` skill on the target repo root — its validators take a `<repo-root>` and walk the tree for every AGENTS.md themselves; there is no per-file entry point. This closeout is mandatory, not optional, even when the change looks trivial — never sign the work off on your own judgment. Resolve any FAIL findings before considering the work done — re-invoke this skill's own writing steps to fix them, then re-run the audit, same as any other close-the-loop check. Report what was created/changed, whether a provider file was reconciled, and the audit's final result.
|
||||
@@ -31,6 +31,6 @@ Provide the path to the provider-specific file to convert (and the target repo r
|
||||
| `tests/validate-adapter.bats` | (source-only) Bats test suite for `scripts/validate-adapter.sh` |
|
||||
|
||||
Rows marked **(source-only)** exist in the authoring source (`.apm/skills/provider-adapter-author/`)
|
||||
but are not present in an installed plugin: `scripts/sync-plugin-content.sh` strips
|
||||
but are not present in an installed plugin: the repo's `scripts/sync-plugin-content.sh` strips
|
||||
`<category>/<name>/tests` when it generates the flat mirror, because these are dev-time fixtures no
|
||||
plugin host needs to discover (ADR-0017). Run them from a repo checkout, not from an install.
|
||||
@@ -2,7 +2,8 @@
|
||||
name: provider-adapter-author
|
||||
description: >
|
||||
Use when a provider file (CLAUDE.md, .cursor rules, copilot-instructions)
|
||||
duplicating the repo's AGENTS.md should be cut to a thin adapter.
|
||||
duplicating the repo's AGENTS.md should be cut to a thin adapter — "make
|
||||
CLAUDE.md just import AGENTS.md".
|
||||
Not writing the AGENTS file -> `agentsmd-author`.
|
||||
Not auditing the AGENTS file -> `agentsmd-audit`.
|
||||
allowed-tools: Bash Read Edit Write
|
||||
@@ -16,7 +17,6 @@ metadata:
|
||||
## Gotchas
|
||||
|
||||
- Assume a provider has no cross-file import mechanism until you have confirmed it has one. Claude Code is the exception, not the rule: a `CLAUDE.md` may consist of nothing but `@path` lines, while the same `@AGENTS.md` line in a Cursor rule or a Copilot instructions file is inert text no tool resolves. Pass `--no-import-syntax` to `scripts/validate-adapter.sh` for those providers.
|
||||
- Works standalone or composed-into by `agentsmd-author` — behave identically either way; don't assume a caller skill exists.
|
||||
|
||||
## Step 1 — Detect
|
||||
|
||||
@@ -43,7 +43,7 @@ Run the bundled check before finishing — this is the skill's own closeout gate
|
||||
bash scripts/validate-adapter.sh [--no-import-syntax] [--max-lines N] <adapter-file> <agents-md-file>
|
||||
```
|
||||
|
||||
Fix any `FAIL` by editing the provider file, and re-run until it exits `0`. The size `FAIL` advises moving provider-agnostic content into `AGENTS.md`; disregard that half of its wording and delete the redundant lines instead.
|
||||
Fix any `FAIL` by editing the provider file, and re-run until it exits `0`.
|
||||
|
||||
## Step 4 — Report
|
||||
|
||||
|
||||
@@ -16,10 +16,15 @@ Arguments:
|
||||
|
||||
Options:
|
||||
--no-import-syntax The target provider has no native cross-file import
|
||||
mechanism. Accept a plain-text pointer mention of
|
||||
"AGENTS.md" instead of requiring an @import-style line.
|
||||
mechanism. Require a plain-text pointer line naming
|
||||
"AGENTS.md" instead of an @import-style line; an
|
||||
@AGENTS.md line alone does not satisfy it, because
|
||||
such a provider never resolves it. Without this flag
|
||||
an actual @import line is required, and naming
|
||||
AGENTS.md in prose alone does not satisfy it.
|
||||
--max-lines N Max non-blank lines allowed in the adapter file before
|
||||
it's considered no longer "thin". Default: 60.
|
||||
it's considered no longer "thin". Must be a
|
||||
non-negative integer. Default: 60.
|
||||
--help, -h Show this help and exit 0.
|
||||
|
||||
Exit codes:
|
||||
@@ -44,7 +49,15 @@ while [[ $# -gt 0 ]]; do
|
||||
shift
|
||||
;;
|
||||
--max-lines)
|
||||
MAX_LINES="${2:-}"
|
||||
if [[ $# -lt 2 ]]; then
|
||||
echo "Error: --max-lines requires a value (a non-negative integer)." >&2
|
||||
exit 1
|
||||
fi
|
||||
MAX_LINES="$2"
|
||||
if [[ ! "$MAX_LINES" =~ ^[0-9]+$ ]]; then
|
||||
echo "Error: --max-lines expects a non-negative integer, got '$MAX_LINES'." >&2
|
||||
exit 1
|
||||
fi
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
@@ -94,21 +107,25 @@ if not adapter_content.strip():
|
||||
IMPORT_RE = re.compile(r'(?m)^\s*@\S*AGENTS\.md\s*$')
|
||||
lines = adapter_content.splitlines()
|
||||
import_lines = [ln for ln in lines if IMPORT_RE.match(ln)]
|
||||
# A prose pointer is any line naming AGENTS.md that is not itself an import
|
||||
# line — an inert `@AGENTS.md` in a provider that resolves no imports points
|
||||
# a reader at nothing.
|
||||
pointer_lines = [ln for ln in lines if not IMPORT_RE.match(ln) and "AGENTS.md" in ln]
|
||||
|
||||
if no_import_syntax:
|
||||
has_reference = "AGENTS.md" in adapter_content
|
||||
has_reference = bool(pointer_lines)
|
||||
else:
|
||||
has_reference = bool(import_lines) or "AGENTS.md" in adapter_content
|
||||
has_reference = bool(import_lines)
|
||||
|
||||
if not has_reference:
|
||||
has_fail = True
|
||||
print(f"FAIL Adapter has no reference to AGENTS.md — {adapter_path}")
|
||||
if no_import_syntax:
|
||||
print(" Why: This provider has no import syntax, so the adapter must at least mention AGENTS.md as a text pointer.")
|
||||
print(" Why: This provider resolves no cross-file import, so the adapter must point at AGENTS.md in prose; an `@AGENTS.md` line here is inert text.")
|
||||
print(" Fix: Add a sentence like \"See AGENTS.md at the repo root for shared conventions.\"")
|
||||
else:
|
||||
print(" Why: A thin adapter must import AGENTS.md (e.g. `@AGENTS.md`) rather than silently omitting it.")
|
||||
print(" Fix: Add an `@AGENTS.md` (or equivalent relative path) import line.")
|
||||
print(" Why: A thin adapter must import AGENTS.md with an `@AGENTS.md` line; merely naming the file in prose defers nothing.")
|
||||
print(" Fix: Add an `@AGENTS.md` (or equivalent relative path) import line, or pass --no-import-syntax if this provider resolves no imports.")
|
||||
print()
|
||||
|
||||
# --- Duplication check ---
|
||||
@@ -132,7 +149,7 @@ if non_blank_count > max_lines:
|
||||
has_fail = True
|
||||
print(f"FAIL Adapter is not thin — {adapter_path}")
|
||||
print(f" Why: {non_blank_count} non-blank lines exceeds the {max_lines}-line threshold for a thin adapter.")
|
||||
print(" Fix: Move provider-agnostic content into AGENTS.md; keep only genuinely provider-specific additions here.")
|
||||
print(" Fix: Delete the lines already covered by AGENTS.md; keep only genuinely provider-specific additions here.")
|
||||
print()
|
||||
|
||||
if has_fail:
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
source_keys: []
|
||||
---
|
||||
|
||||
# Orchestrator request contract
|
||||
|
||||
`git-orchestrate` and other calling agents send this shape. The result shape they parse back is in
|
||||
|
||||
@@ -8,7 +8,6 @@ description: >
|
||||
Not branch lifecycle -> `git-branches`.
|
||||
|
||||
metadata:
|
||||
version: "0.1.3"
|
||||
category: git
|
||||
source_keys:
|
||||
- conventional-commits-spec
|
||||
|
||||
@@ -9,21 +9,20 @@ description: >
|
||||
Not submodule pointers -> `git-submodules`.
|
||||
|
||||
metadata:
|
||||
category: git-workflow
|
||||
category: git
|
||||
source_keys:
|
||||
- git-scm-remote-docs
|
||||
- git-scm-fetch-docs
|
||||
- git-scm-push-docs
|
||||
- git-scm-pull-docs
|
||||
- context7-git-htmldocs
|
||||
|
||||
---
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **`--force-with-lease` alone is not safe** — background processes (IDE plugins, cron jobs) running `git fetch` silently defeat the protection. Combine it with `--force-if-includes`, or pin the explicit `--force-with-lease=<ref>:<sha>` form.
|
||||
- **Prune does not touch tags by default** — `git fetch --prune` leaves orphaned tags behind. Use `--prune --prune-tags`, or set `fetch.pruneTags true`.
|
||||
- **Pull defaults shift between Git versions** — older ones default to merge, newer to `--ff-only`. Set `pull.ff only` explicitly rather than trusting the installed default.
|
||||
- **Set `pull.ff only` explicitly** — do not trust the installed default.
|
||||
|
||||
## Step 1 — Clear the force-push gate
|
||||
|
||||
|
||||
@@ -23,6 +23,10 @@ A pull that diverges with no strategy configured fails, and that failure is the
|
||||
|
||||
## Config precedence
|
||||
|
||||
The installed default varies by Git version — older versions merge on divergence, newer ones
|
||||
default to `--ff-only` — so an unset `pull.ff` means the same pull behaves differently on different
|
||||
machines. Set it explicitly.
|
||||
|
||||
Highest wins:
|
||||
|
||||
1. Command-line flag (`--ff-only` / `--rebase` / `--no-rebase`)
|
||||
|
||||
@@ -51,7 +51,7 @@ executing.
|
||||
|
||||
## Output format
|
||||
|
||||
```
|
||||
```yaml
|
||||
operation: <clone|add|init|update|status|sync|set-url|set-branch|absorbgitdirs|deinit|remove>
|
||||
status: <success|error|partial>
|
||||
message: <one line; include git's own output on error>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
metadata:
|
||||
source_keys:
|
||||
- git-scm-submodule-docs
|
||||
source_keys:
|
||||
- git-scm-submodule-docs
|
||||
---
|
||||
|
||||
# References
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
name: git-workflow
|
||||
|
||||
description: >
|
||||
Use when a human wants to work through local git interactively — commits, branches, history,
|
||||
submodules, worktrees, or remotes. Not an agent caller needing deterministic execution ->
|
||||
`git-orchestrate`. Not server-side Gitea work -> `gitea-workflow`.
|
||||
Use when a human's local git request is general or ambiguous — it routes to the owning
|
||||
domain skill. Not an unambiguous commit -> `git-commits`. Not an unambiguous branch ->
|
||||
`git-branches`. Not an agent caller -> `git-orchestrate`. Not Gitea -> `gitea-workflow`.
|
||||
|
||||
metadata:
|
||||
category: git
|
||||
|
||||
@@ -28,7 +28,7 @@ metadata:
|
||||
| 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** when `<branch>` has no local copy (gate below) |
|
||||
| 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 |
|
||||
@@ -40,15 +40,14 @@ metadata:
|
||||
|
||||
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, worktree config keys, or the worked
|
||||
emergency-fix and PR-review patterns — read `references/worktrees.md`.
|
||||
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`.
|
||||
|
||||
Gates:
|
||||
|
||||
- **`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.
|
||||
- **`lock`, `move`, `remove`, `repair` — identify a worktree by full path, unique basename, or unique partial path.** An ambiguous name errors rather than picking; `git worktree list` shows the usable identifiers.
|
||||
- **`add` — the bare-name tracking shortcut needs exactly one remote.** `git worktree add <path> <branch>` sets up tracking only when `<branch>` is absent locally, no `-b`/`-B`/`-d` is given, and exactly one remote carries the name. With several, it fires only if `checkout.defaultRemote` names one. When the remote is ambiguous or unknown, use `--track -b`.
|
||||
- **`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.
|
||||
|
||||
## Step 2 — Report
|
||||
|
||||
@@ -4,6 +4,8 @@ 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
|
||||
@@ -12,6 +14,12 @@ its own `HEAD`, index, and per-worktree metadata (`ORIG_HEAD`, `MERGE_HEAD`, `re
|
||||
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
|
||||
@@ -85,10 +93,11 @@ git worktree unlock <path> # when reconnected
|
||||
git worktree add --track -b <branch> <path> <remote>/<branch> # explicit: no guessing at all
|
||||
git worktree add <path> <branch> # shortcut: needs one clear remote
|
||||
```
|
||||
The shortcut 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.
|
||||
**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
|
||||
|
||||
@@ -20,7 +20,7 @@ allowed-tools: Bash Read
|
||||
|
||||
- The `SKIP` env var takes exact hook `id` values, comma-separated with no spaces: `SKIP=check-yaml,gitleaks git commit -m "msg"`. A space after a comma silently skips nothing instead of erroring.
|
||||
- Never bypass a failing hook with `git commit --no-verify` (or `-n`). Hooks are the automated QA gate, so a bypassed commit pushes the failure downstream where it costs more — diagnose it instead.
|
||||
- `- files were modified by this hook` is not a bug. A fixer hook (`trailing-whitespace`, `end-of-file-fixer`, `pretty-format-json --autofix`) rewrote a staged file, so the staged snapshot is stale and the commit is blocked on purpose. The fix is to re-stage and re-run the same commit: `git add -u && git commit`. Do NOT reach for `pre-commit install -f` here — that flag overwrites hook files in `.git/hooks/` and has nothing to do with re-staging.
|
||||
- `- files were modified by this hook` is not a bug. A fixer hook rewrote a staged file, so the staged snapshot is stale and the commit is blocked on purpose. Re-stage and re-run the same commit: `git add -u && git commit`. Do NOT reach for `pre-commit install -f` here — it overwrites `.git/hooks/` and has nothing to do with re-staging.
|
||||
|
||||
## Gate — `pre-commit clean`
|
||||
|
||||
@@ -47,8 +47,6 @@ Determine intent from the user's request, then execute the matching operation. W
|
||||
| "clean", "wipe cache", "rebuild from scratch" | `pre-commit clean` — read `references/clean.md` |
|
||||
| "hooks aren't running", "hook never fires", "why did a hook fail", a hook failure whose cause is unclear | Diagnose — read `references/failure-patterns.md` |
|
||||
|
||||
If the intent is ambiguous, default to `pre-commit run --all-files`.
|
||||
|
||||
## Run
|
||||
|
||||
Default to `pre-commit run --all-files`; never silently narrow to staged files. Run `pre-commit run` (staged only) or `pre-commit run <hook-id>` (one named hook) when the user asks for it.
|
||||
|
||||
@@ -6,16 +6,12 @@ source_keys:
|
||||
|
||||
# Wiping the pre-commit cache
|
||||
|
||||
Reached from `SKILL.md`'s Route table when the user asks to clean the cache or rebuild environments from scratch. Self-contained.
|
||||
Reached from `SKILL.md`'s Route table when the user asks to clean the cache or rebuild environments from scratch. The confirmation gate on `pre-commit clean` stays in `SKILL.md`, because it must fire on every path that reaches this command, not only this one.
|
||||
|
||||
## Gate — confirm first
|
||||
## Gate
|
||||
|
||||
`pre-commit clean` wipes the whole cache at `~/.cache/pre-commit`, forcing every hook environment to be re-downloaded on the next run. Require explicit confirmation before executing it:
|
||||
|
||||
> "This will wipe the entire pre-commit cache. All hook environments will be re-downloaded on next run. Proceed?"
|
||||
`pre-commit clean` runs only after the confirmation gate in `SKILL.md` clears — that gate, its exact wording, and the `pre-commit gc` alternative live there and are not restated here.
|
||||
|
||||
```bash
|
||||
pre-commit clean
|
||||
```
|
||||
|
||||
Prefer `pre-commit gc` when the goal is only to reclaim disk — it drops unused environments and leaves the ones in use intact, so it needs no confirmation.
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
source_keys: []
|
||||
---
|
||||
|
||||
# Orchestrator request contract
|
||||
|
||||
`git-orchestrate` and other calling agents send this shape. The result shape they parse back is in
|
||||
|
||||
@@ -8,7 +8,6 @@ description: >
|
||||
Not branch lifecycle -> `git-branches`.
|
||||
|
||||
metadata:
|
||||
version: "0.1.3"
|
||||
category: git
|
||||
source_keys:
|
||||
- conventional-commits-spec
|
||||
|
||||
@@ -9,21 +9,20 @@ description: >
|
||||
Not submodule pointers -> `git-submodules`.
|
||||
|
||||
metadata:
|
||||
category: git-workflow
|
||||
category: git
|
||||
source_keys:
|
||||
- git-scm-remote-docs
|
||||
- git-scm-fetch-docs
|
||||
- git-scm-push-docs
|
||||
- git-scm-pull-docs
|
||||
- context7-git-htmldocs
|
||||
|
||||
---
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **`--force-with-lease` alone is not safe** — background processes (IDE plugins, cron jobs) running `git fetch` silently defeat the protection. Combine it with `--force-if-includes`, or pin the explicit `--force-with-lease=<ref>:<sha>` form.
|
||||
- **Prune does not touch tags by default** — `git fetch --prune` leaves orphaned tags behind. Use `--prune --prune-tags`, or set `fetch.pruneTags true`.
|
||||
- **Pull defaults shift between Git versions** — older ones default to merge, newer to `--ff-only`. Set `pull.ff only` explicitly rather than trusting the installed default.
|
||||
- **Set `pull.ff only` explicitly** — do not trust the installed default.
|
||||
|
||||
## Step 1 — Clear the force-push gate
|
||||
|
||||
|
||||
@@ -23,6 +23,10 @@ A pull that diverges with no strategy configured fails, and that failure is the
|
||||
|
||||
## Config precedence
|
||||
|
||||
The installed default varies by Git version — older versions merge on divergence, newer ones
|
||||
default to `--ff-only` — so an unset `pull.ff` means the same pull behaves differently on different
|
||||
machines. Set it explicitly.
|
||||
|
||||
Highest wins:
|
||||
|
||||
1. Command-line flag (`--ff-only` / `--rebase` / `--no-rebase`)
|
||||
|
||||
@@ -51,7 +51,7 @@ executing.
|
||||
|
||||
## Output format
|
||||
|
||||
```
|
||||
```yaml
|
||||
operation: <clone|add|init|update|status|sync|set-url|set-branch|absorbgitdirs|deinit|remove>
|
||||
status: <success|error|partial>
|
||||
message: <one line; include git's own output on error>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
metadata:
|
||||
source_keys:
|
||||
- git-scm-submodule-docs
|
||||
source_keys:
|
||||
- git-scm-submodule-docs
|
||||
---
|
||||
|
||||
# References
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
name: git-workflow
|
||||
|
||||
description: >
|
||||
Use when a human wants to work through local git interactively — commits, branches, history,
|
||||
submodules, worktrees, or remotes. Not an agent caller needing deterministic execution ->
|
||||
`git-orchestrate`. Not server-side Gitea work -> `gitea-workflow`.
|
||||
Use when a human's local git request is general or ambiguous — it routes to the owning
|
||||
domain skill. Not an unambiguous commit -> `git-commits`. Not an unambiguous branch ->
|
||||
`git-branches`. Not an agent caller -> `git-orchestrate`. Not Gitea -> `gitea-workflow`.
|
||||
|
||||
metadata:
|
||||
category: git
|
||||
|
||||
@@ -28,7 +28,7 @@ metadata:
|
||||
| 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** when `<branch>` has no local copy (gate below) |
|
||||
| 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 |
|
||||
@@ -40,15 +40,14 @@ metadata:
|
||||
|
||||
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, worktree config keys, or the worked
|
||||
emergency-fix and PR-review patterns — read `references/worktrees.md`.
|
||||
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`.
|
||||
|
||||
Gates:
|
||||
|
||||
- **`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.
|
||||
- **`lock`, `move`, `remove`, `repair` — identify a worktree by full path, unique basename, or unique partial path.** An ambiguous name errors rather than picking; `git worktree list` shows the usable identifiers.
|
||||
- **`add` — the bare-name tracking shortcut needs exactly one remote.** `git worktree add <path> <branch>` sets up tracking only when `<branch>` is absent locally, no `-b`/`-B`/`-d` is given, and exactly one remote carries the name. With several, it fires only if `checkout.defaultRemote` names one. When the remote is ambiguous or unknown, use `--track -b`.
|
||||
- **`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.
|
||||
|
||||
## Step 2 — Report
|
||||
|
||||
@@ -4,6 +4,8 @@ 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
|
||||
@@ -12,6 +14,12 @@ its own `HEAD`, index, and per-worktree metadata (`ORIG_HEAD`, `MERGE_HEAD`, `re
|
||||
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
|
||||
@@ -85,10 +93,11 @@ git worktree unlock <path> # when reconnected
|
||||
git worktree add --track -b <branch> <path> <remote>/<branch> # explicit: no guessing at all
|
||||
git worktree add <path> <branch> # shortcut: needs one clear remote
|
||||
```
|
||||
The shortcut 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.
|
||||
**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
|
||||
|
||||
@@ -20,7 +20,7 @@ allowed-tools: Bash Read
|
||||
|
||||
- The `SKIP` env var takes exact hook `id` values, comma-separated with no spaces: `SKIP=check-yaml,gitleaks git commit -m "msg"`. A space after a comma silently skips nothing instead of erroring.
|
||||
- Never bypass a failing hook with `git commit --no-verify` (or `-n`). Hooks are the automated QA gate, so a bypassed commit pushes the failure downstream where it costs more — diagnose it instead.
|
||||
- `- files were modified by this hook` is not a bug. A fixer hook (`trailing-whitespace`, `end-of-file-fixer`, `pretty-format-json --autofix`) rewrote a staged file, so the staged snapshot is stale and the commit is blocked on purpose. The fix is to re-stage and re-run the same commit: `git add -u && git commit`. Do NOT reach for `pre-commit install -f` here — that flag overwrites hook files in `.git/hooks/` and has nothing to do with re-staging.
|
||||
- `- files were modified by this hook` is not a bug. A fixer hook rewrote a staged file, so the staged snapshot is stale and the commit is blocked on purpose. Re-stage and re-run the same commit: `git add -u && git commit`. Do NOT reach for `pre-commit install -f` here — it overwrites `.git/hooks/` and has nothing to do with re-staging.
|
||||
|
||||
## Gate — `pre-commit clean`
|
||||
|
||||
@@ -47,8 +47,6 @@ Determine intent from the user's request, then execute the matching operation. W
|
||||
| "clean", "wipe cache", "rebuild from scratch" | `pre-commit clean` — read `references/clean.md` |
|
||||
| "hooks aren't running", "hook never fires", "why did a hook fail", a hook failure whose cause is unclear | Diagnose — read `references/failure-patterns.md` |
|
||||
|
||||
If the intent is ambiguous, default to `pre-commit run --all-files`.
|
||||
|
||||
## Run
|
||||
|
||||
Default to `pre-commit run --all-files`; never silently narrow to staged files. Run `pre-commit run` (staged only) or `pre-commit run <hook-id>` (one named hook) when the user asks for it.
|
||||
|
||||
@@ -6,16 +6,12 @@ source_keys:
|
||||
|
||||
# Wiping the pre-commit cache
|
||||
|
||||
Reached from `SKILL.md`'s Route table when the user asks to clean the cache or rebuild environments from scratch. Self-contained.
|
||||
Reached from `SKILL.md`'s Route table when the user asks to clean the cache or rebuild environments from scratch. The confirmation gate on `pre-commit clean` stays in `SKILL.md`, because it must fire on every path that reaches this command, not only this one.
|
||||
|
||||
## Gate — confirm first
|
||||
## Gate
|
||||
|
||||
`pre-commit clean` wipes the whole cache at `~/.cache/pre-commit`, forcing every hook environment to be re-downloaded on the next run. Require explicit confirmation before executing it:
|
||||
|
||||
> "This will wipe the entire pre-commit cache. All hook environments will be re-downloaded on next run. Proceed?"
|
||||
`pre-commit clean` runs only after the confirmation gate in `SKILL.md` clears — that gate, its exact wording, and the `pre-commit gc` alternative live there and are not restated here.
|
||||
|
||||
```bash
|
||||
pre-commit clean
|
||||
```
|
||||
|
||||
Prefer `pre-commit gc` when the goal is only to reclaim disk — it drops unused environments and leaves the ones in use intact, so it needs no confirmation.
|
||||
@@ -4,7 +4,7 @@ Manage Gitea repository branches and inspect commit history via the Gitea MCP se
|
||||
|
||||
## What it does
|
||||
|
||||
This skill handles branch lifecycle operations (list, create, delete) and read-only commit
|
||||
This skill handles branch lifecycle operations (list, create, rename, delete) and read-only commit
|
||||
history (list commits, get a single commit's full detail) against a Gitea repository. It resolves
|
||||
`owner`/`repo` from the git remote, dispatches to the right MCP tool, and applies safety and
|
||||
pagination conventions specific to Gitea's API (e.g. refusing to delete a protected branch without
|
||||
@@ -18,25 +18,26 @@ Branch references that only exist relative to a pull request — a PR's head or
|
||||
cross-repo fork PR heads in particular — belong to `gitea-prs`; `list_branches` cannot see a fork's
|
||||
head at all.
|
||||
|
||||
The skill triggers on phrasings like "list branches", "create a branch", "delete a branch",
|
||||
The skill triggers on phrasings like "list branches", "create a branch", "rename a branch", "delete a branch",
|
||||
"what commits are on this branch", "show commit <sha>", and "what changed in that commit", even
|
||||
when the user does not say "Gitea", as long as the repo's remote is a Gitea instance.
|
||||
|
||||
## Before you start
|
||||
|
||||
Requires a Gitea MCP server configured with a token that has `write:repository` scope. This is
|
||||
confirmed for `list_branches`, `create_branch`, and `delete_branch` (Gitea gates reads behind write
|
||||
confirmed for `list_branches`, `create_branch`, and `delete_branch` (and inferred for
|
||||
`rename_branch`) (Gitea gates reads behind write
|
||||
scope for repo-scoped operations); `list_commits` and `get_commit` are inferred to need the same
|
||||
scope by analogy, not explicitly confirmed — see `references/commits.md`. Requires a git remote
|
||||
named `origin` pointing at the Gitea instance.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
```text
|
||||
/gitea-branches
|
||||
```
|
||||
|
||||
Describe your task: list/create/delete a branch, or list/inspect commits. See `SKILL.md`'s
|
||||
Describe your task: list/create/rename/delete a branch, or list/inspect commits. See `SKILL.md`'s
|
||||
dispatch table for the full set of recognized invocations.
|
||||
|
||||
## Files
|
||||
@@ -44,6 +45,6 @@ dispatch table for the full set of recognized invocations.
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | Skill instructions for agents — dispatch table, gotchas |
|
||||
| `references/branches.md` | Verified call signatures and mechanics for list/create/delete branch |
|
||||
| `references/branches.md` | Verified call signatures and mechanics for list/create/rename/delete branch |
|
||||
| `references/commits.md` | Verified call signatures and mechanics for list/get commit |
|
||||
| `references/sources.md` | Research sources backing the branch/commit guidance |
|
||||
@@ -2,10 +2,10 @@
|
||||
name: gitea-branches
|
||||
|
||||
description: >
|
||||
Use when listing, creating, or deleting branches in a Gitea repository, or
|
||||
reading its commit history — even when the user does not say "Gitea". Not a
|
||||
local working copy's branches -> `git-branches`. Not local history ->
|
||||
`git-history`. Not a PR's head or base branch -> `gitea-prs`.
|
||||
Use when listing, creating, renaming, or deleting branches in a Gitea repository,
|
||||
or reading its commit history — even when the user does not say "Gitea". Not a
|
||||
local checkout's branches -> `git-branches`. Not local history ->
|
||||
`git-history`. Not a PR's head or base -> `gitea-prs`.
|
||||
|
||||
compatibility: Requires Gitea MCP server configured with a token with write:repository scope; this is confirmed to gate list_branches, create_branch, and delete_branch (Gitea gates reads behind write scope for repo-scoped operations), and is inferred by analogy (not explicitly confirmed by source docs) to also gate list_commits and get_commit. Requires git remote "origin" pointing to the Gitea instance.
|
||||
|
||||
@@ -17,7 +17,7 @@ metadata:
|
||||
- gitea-mcp-slim-go
|
||||
- context7-websites-gitea
|
||||
|
||||
allowed-tools: Bash mcp__gitea__list_branches mcp__gitea__create_branch mcp__gitea__delete_branch mcp__gitea__list_commits mcp__gitea__get_commit
|
||||
allowed-tools: Bash mcp__gitea__list_branches mcp__gitea__create_branch mcp__gitea__rename_branch mcp__gitea__delete_branch mcp__gitea__list_commits mcp__gitea__get_commit
|
||||
---
|
||||
|
||||
## Gotchas
|
||||
@@ -42,17 +42,18 @@ git remote get-url origin
|
||||
|---|---|
|
||||
| `/gitea-branches` or `/gitea-branches list` | List branches |
|
||||
| `/gitea-branches create <name> [from <base>]` | Create branch |
|
||||
| `/gitea-branches rename <name> to <new-name>` | Rename branch |
|
||||
| `/gitea-branches delete <name>` | Delete branch |
|
||||
| `/gitea-branches commits [on <branch>] [touching <path>]` | List commit history |
|
||||
| `/gitea-branches commit <sha>` | Get full detail for one commit |
|
||||
|
||||
For branch operations (list/create/delete), read `references/branches.md` — it carries the call signatures, the `old_branch` source rule, and the protected-branch refusal in full.
|
||||
For branch operations (list/create/rename/delete), read `references/branches.md` — it carries the call signatures, the `old_branch` source rule, and the protected-branch refusal in full.
|
||||
For commit operations (list/get), read `references/commits.md`.
|
||||
|
||||
## Step 3 — Report
|
||||
|
||||
For reads: display branches as name + protected flag; display commits as SHA (short), message summary, author, date.
|
||||
|
||||
For writes (create/delete): confirm the action taken, the branch name, and (for create) the base it forked from.
|
||||
For writes (create/rename/delete): confirm the action taken, the branch name, and (for create) the base it forked from or (for rename) the name it had before.
|
||||
|
||||
For errors: surface the HTTP code and message, applying the 404 gotcha above before reporting "not found" to the user.
|
||||
@@ -7,10 +7,11 @@ source_keys:
|
||||
|
||||
# Branch operations
|
||||
|
||||
Call signatures below were verified live against the deployed `gitea-mcp` server via `ToolSearch`
|
||||
at authoring time, not copied from research docs — this is deliberate: research docs are generated
|
||||
from source code at a point in time and can drift from the server actually deployed. Re-verify
|
||||
against the live schema if these tools appear to behave differently than documented here.
|
||||
Call signatures below were verified live against the deployed `gitea-mcp` server via `ToolSearch`,
|
||||
not copied from research docs — this is deliberate: research docs are generated from source code at
|
||||
a point in time and can drift from the server actually deployed. **Last verified against gitea-mcp
|
||||
v1.7.0**, as reported by `get_gitea_mcp_server_version`. Re-verify against the live schema if the
|
||||
deployed version differs or these tools behave differently than documented here.
|
||||
|
||||
## `list_branches`
|
||||
|
||||
@@ -21,7 +22,7 @@ against the live schema if these tools appear to behave differently than documen
|
||||
- `per_page` (number, optional, default: `30`)
|
||||
|
||||
**Call:**
|
||||
```
|
||||
```text
|
||||
list_branches owner: <owner> repo: <repo>
|
||||
```
|
||||
|
||||
@@ -41,7 +42,7 @@ count is less than `per_page`.
|
||||
branch server-side (not necessarily your current local checkout)
|
||||
|
||||
**Call:**
|
||||
```
|
||||
```text
|
||||
create_branch owner: <owner> repo: <repo> branch: <new-name> old_branch: <source-branch>
|
||||
```
|
||||
|
||||
@@ -53,6 +54,29 @@ top-level request with no working branch context), omit `old_branch` and let it
|
||||
|
||||
A branch name collision returns `409 Conflict`.
|
||||
|
||||
## `rename_branch`
|
||||
|
||||
**Parameters:**
|
||||
- `owner` (string, required)
|
||||
- `repo` (string, required)
|
||||
- `branch` (string, required) — the branch's current name
|
||||
- `new_name` (string, required) — the name to move it to
|
||||
|
||||
**Call:**
|
||||
```text
|
||||
rename_branch owner: <owner> repo: <repo> branch: <current-name> new_name: <new-name>
|
||||
```
|
||||
|
||||
A rename moves the ref server-side; it is not a delete-plus-create, and no commit history is
|
||||
rewritten. What it does to things *pointing at* the old name — open pull requests using it as head or
|
||||
base, a branch protection rule matching it, CI config, and tracking branches on every other clone —
|
||||
is **not confirmed** by this skill's sources: the deployed tool describes itself only as "Rename an
|
||||
existing branch in a repository". Treat a rename of a branch with open PRs or a protection rule as a
|
||||
change needing verification afterward (`list_branches`, plus `gitea-prs` for the PR side), and
|
||||
confirm with the user first, exactly as for `delete_branch` below. A collision with an existing
|
||||
branch name is expected to return `409 Conflict` by analogy with `create_branch`, not separately
|
||||
confirmed.
|
||||
|
||||
## `delete_branch`
|
||||
|
||||
**Parameters:**
|
||||
@@ -61,7 +85,7 @@ A branch name collision returns `409 Conflict`.
|
||||
- `branch` (string, required)
|
||||
|
||||
**Call:**
|
||||
```
|
||||
```text
|
||||
delete_branch owner: <owner> repo: <repo> branch: <name>
|
||||
```
|
||||
|
||||
@@ -73,9 +97,12 @@ protected, every time, regardless of how the request is phrased.
|
||||
|
||||
## Token scope
|
||||
|
||||
All three — `list_branches`, `create_branch`, `delete_branch` — require `write:repository`. Gitea
|
||||
`list_branches`, `create_branch` and `delete_branch` all require `write:repository`. Gitea
|
||||
gates reads behind write scope for repo-scoped operations, so `list_branches` needs the same scope
|
||||
as the write operations, not `write:issue` alone. An earlier version of this doc claimed
|
||||
`write:issue` alone was sufficient for `list_branches`, based on empirical testing under a token
|
||||
that held both `write:issue` and `write:repository` simultaneously — that test didn't isolate the
|
||||
variable, so it couldn't actually establish `write:issue` alone as sufficient.
|
||||
|
||||
`rename_branch` is a write on the same repo-scoped surface and is inferred to need `write:repository`
|
||||
too — inferred by analogy, not separately confirmed.
|
||||
@@ -8,8 +8,9 @@ source_keys:
|
||||
# Commit operations
|
||||
|
||||
Read-only commit history, scoped to a repo (optionally to one branch or one path). Call signatures
|
||||
below were verified live against the deployed `gitea-mcp` server via `ToolSearch` at authoring time,
|
||||
not copied from research docs, for the same drift-avoidance reason noted in `references/branches.md`.
|
||||
below were verified live against the deployed `gitea-mcp` server via `ToolSearch`, not copied from
|
||||
research docs, for the same drift-avoidance reason noted in `references/branches.md`. **Last verified
|
||||
against gitea-mcp v1.7.0**, as reported by `get_gitea_mcp_server_version`.
|
||||
|
||||
This domain has no prior skill precedent — it's new coverage added alongside branches because commit
|
||||
history is naturally scoped to a branch (a "what happened on this branch" question), not because it
|
||||
@@ -27,7 +28,7 @@ shares any tool family with branch create/delete.
|
||||
- `per_page` (number, optional, default: `30`, minimum: `1`)
|
||||
|
||||
**Call:**
|
||||
```
|
||||
```text
|
||||
list_commits owner: <owner> repo: <repo> sha: <branch-or-sha> path: <optional-path>
|
||||
```
|
||||
|
||||
@@ -52,7 +53,7 @@ Paginate per the pagination Gotcha in SKILL.md if you need more than one page of
|
||||
- `sha` (string, required)
|
||||
|
||||
**Call:**
|
||||
```
|
||||
```text
|
||||
get_commit owner: <owner> repo: <repo> sha: <commit-sha>
|
||||
```
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
**Note on call signatures:** per `docs/adr/0011-gitea-skill-deep-modules.md`, the tool parameter
|
||||
signatures in `references/branches.md` and `references/commits.md` were re-verified live via
|
||||
`ToolSearch` against the deployed `gitea-mcp` server at authoring time — they are not copied
|
||||
verbatim from `api-reference.md` below. This resolves issue #6 comment #849's root-cause finding
|
||||
`ToolSearch` against the deployed `gitea-mcp` server — **last verified against v1.7.0**, as reported
|
||||
by `get_gitea_mcp_server_version` — rather than copied verbatim from `api-reference.md` below. This resolves issue #6 comment #849's root-cause finding
|
||||
that a prior skill was authored from API docs that had drifted from the actual MCP tool schema.
|
||||
The research docs cited here informed gotchas, response shapes, and workflow context, not the
|
||||
parameter lists themselves.
|
||||
@@ -11,7 +11,7 @@ parameter lists themselves.
|
||||
## gitea-mcp-repo
|
||||
|
||||
- **URL:** https://gitea.com/gitea/gitea-mcp
|
||||
- **Description:** Official gitea-mcp repository (v1.3.0); operation/*.go source files documenting all 55 MCP tools, their parameters, and CLI flags. Informed the dispatch table and pagination / 404-may-mean-403 gotchas in SKILL.md, and the list/create/delete branch and list/get commit mechanics (including 409 conflict and default-branch fallback behavior) in references/branches.md and references/commits.md.
|
||||
- **Description:** Official gitea-mcp repository; operation/*.go source files documenting the MCP tools, their parameters, and CLI flags. Extracted at v1.3.0; the parameter lists carried into this skill are re-verified live against the deployed server, last at v1.7.0. Informed the dispatch table and pagination / 404-may-mean-403 gotchas in SKILL.md, and the list/create/delete branch and list/get commit mechanics (including 409 conflict and default-branch fallback behavior) in references/branches.md and references/commits.md.
|
||||
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
|
||||
- **Contributing files:** SKILL.md, references/branches.md, references/commits.md
|
||||
- **Status:** `extracted`
|
||||
@@ -19,7 +19,7 @@ parameter lists themselves.
|
||||
## gitea-mcp-slim-go
|
||||
|
||||
- **URL:** https://gitea.com/gitea/gitea-mcp/raw/branch/main/operation/repo/slim.go
|
||||
- **Description:** Slim response shape structs from gitea-mcp source; defines exactly which fields the MCP server returns for branches (name, protected, commit_sha) and commits (sha, html_url, created, message, author), and informed get_commit's always-populated guarantee vs. list_commits' conditional fields.
|
||||
- **Description:** Slim response shape structs from gitea-mcp source, extracted at v1.3.0; defines exactly which fields the MCP server returns for branches (name, protected, commit_sha) and commits (sha, html_url, created, message, author), and informed get_commit's always-populated guarantee vs. list_commits' conditional fields.
|
||||
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
|
||||
- **Contributing files:** references/branches.md, references/commits.md
|
||||
- **Status:** `extracted`
|
||||
|
||||
@@ -8,7 +8,7 @@ This skill handles file-domain operations within the Gitea integration suite: re
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
```text
|
||||
/gitea-files
|
||||
```
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ allowed-tools: mcp__gitea__get_file_contents mcp__gitea__get_dir_contents mcp__g
|
||||
|
||||
- **A 404 may mean an under-scoped token, not a missing path.** Every tool here gates on `write:repository`, and Gitea masks insufficient scope as 404. Check scopes first.
|
||||
- **Reads take `ref`, writes take `branch_name`.** One concept, two parameter names — chaining a read into a write drops the branch if you carry the wrong key.
|
||||
- **`content` is base64 both ways.** Encode before a write, decode after a read; `withLines: true` returns numbered lines.
|
||||
- **`content` is base64 both ways.** Encode before a write, decode after a read.
|
||||
|
||||
## Inputs
|
||||
|
||||
@@ -32,14 +32,12 @@ allowed-tools: mcp__gitea__get_file_contents mcp__gitea__get_dir_contents mcp__g
|
||||
|
||||
## Dispatch
|
||||
|
||||
Read the reference for the row you land on before making the call.
|
||||
|
||||
| Condition | Flow | Reference |
|
||||
|---|---|---|
|
||||
| Read one file, list one directory level, or walk the repository tree | Read | `references/reading.md` |
|
||||
| Create, update, or delete a file | Write | `references/writing.md` |
|
||||
|
||||
If the request only inspects repository contents, read `references/reading.md` — it carries the three read tools, their pagination behaviour, and why neither a directory listing nor a tree entry supplies the SHA a write needs.
|
||||
|
||||
If the request creates, updates or deletes a file, read `references/writing.md` — it carries the SHA-first sequence every update and delete depends on, the worked multi-call sequence, and how to triage a write that fails.
|
||||
| Read one file, list one directory level, or walk the repository tree | Read | `references/reading.md` — the three read tools, their pagination behaviour, and why neither a directory listing nor a tree entry supplies the SHA a write needs |
|
||||
| Create, update, or delete a file | Write | `references/writing.md` — the SHA-first sequence every update and delete depends on, the worked multi-call sequence, and how to triage a write that fails |
|
||||
|
||||
A request that reads and then writes runs both flows in that order: fetch the file first, then write with the SHA that call returned.
|
||||
|
||||
|
||||
@@ -29,15 +29,17 @@ commit lands on it in one call, replacing a separate branch-creation step.
|
||||
|
||||
## Delete a file
|
||||
|
||||
Same SHA-first pattern, with no create-style fallback — `delete_file` without `sha` returns
|
||||
HTTP 422.
|
||||
Same SHA-first pattern, with no create-style fallback. `sha` is schema-**required** on
|
||||
`delete_file`, unlike `create_or_update_file` where omitting it means *create* — so an omitted `sha`
|
||||
is rejected client-side by input validation and the call never reaches Gitea. The HTTP 422 that is
|
||||
actually reachable here is the stale-`sha` case.
|
||||
|
||||
1. `get_file_contents(owner, repo, ref: <branch>, path)` → read the top-level `sha`.
|
||||
2. `delete_file(owner, repo, path, message, branch_name, sha: <that value>)`.
|
||||
|
||||
## Worked sequence — new file on a new branch, then a PR
|
||||
|
||||
```
|
||||
```text
|
||||
1. create_or_update_file
|
||||
owner, repo
|
||||
path: "docs/example.md"
|
||||
@@ -58,9 +60,10 @@ when the write replaces an existing one.
|
||||
| Symptom | Cause | Action |
|
||||
|---|---|---|
|
||||
| HTTP 409 | `sha` omitted on a path that already exists | Fetch the current SHA, retry as an update |
|
||||
| HTTP 422 | `sha` missing or stale | Re-fetch the SHA immediately before the write |
|
||||
| HTTP 422 | Stale `sha` — the file changed between the read and the write | Re-fetch the SHA immediately before the write |
|
||||
| 403 or 422 with no SHA explanation | Branch protection requires signed commits | Stop and report |
|
||||
| HTTP 413 | Reverse-proxy body limit in front of Gitea | Report; retrying cannot fix it |
|
||||
| Client-side input-validation error naming `sha` | `sha` omitted on `delete_file`, where it is schema-required | Fetch the current SHA and retry — nothing was sent to Gitea |
|
||||
| HTTP 404 | Wrong path, or a token without `write:repository` | Verify the path, then the token's scopes |
|
||||
|
||||
**Signed commits.** These writes create commits server-side from a bare API token with no 2FA or
|
||||
|
||||
@@ -10,9 +10,8 @@ its state, adding/editing comments, applying labels, and searching issues/PRs ac
|
||||
The create flow closes out four enrichments deferred from issue #6 comment #848: label inference
|
||||
and milestone assignment (both by composing `gitea-labels-milestones`), an assignee workaround for
|
||||
the blocked `get_me` scope, and the "Depends on #N" dependency-linking convention. It supersedes the
|
||||
`issue`/`issue <N>`/`issue close <N>`/`issue comment <N>` dispatch in the old flat
|
||||
`plugins/bin/skills/gitea/SKILL.md`, removed per
|
||||
`docs/adr/0011-gitea-skill-deep-modules.md`.
|
||||
`issue`/`issue <N>`/`issue close <N>`/`issue comment <N>` dispatch this plugin's old single flat
|
||||
Gitea skill carried, retired when the plugin was split into per-domain deep modules.
|
||||
|
||||
## Before you start
|
||||
|
||||
@@ -34,7 +33,7 @@ issue request: local git branch or commit work belongs to `gitea-branches` (Gite
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
```text
|
||||
/gitea-issues
|
||||
```
|
||||
|
||||
|
||||
@@ -84,8 +84,8 @@ repo-scoped number space. Use the bare `#N` form for same-repo dependencies; use
|
||||
a dependency in a different repo.
|
||||
|
||||
When creating an issue that depends on another, append a line like:
|
||||
```
|
||||
```text
|
||||
Depends on #42
|
||||
```
|
||||
to the body before calling `issue_write method: "create"`. There is no separate field or follow-up
|
||||
call — the rendering happens automatically once the body is saved.
|
||||
to the body before calling `issue_write method: "create"`. No separate field or follow-up call is
|
||||
involved — the rendering happens automatically once the body is saved.
|
||||
@@ -37,7 +37,7 @@ item is the `html_url` path segment (`/issues/` vs `/pulls/`), since `is_pull` i
|
||||
list items — see the Gotchas section of SKILL.md.
|
||||
|
||||
**Call:**
|
||||
```
|
||||
```text
|
||||
list_issues owner: <owner> repo: <repo> state: "open" type: "issues"
|
||||
```
|
||||
|
||||
@@ -66,7 +66,7 @@ number is backed by a pull request — absent, not `false`, on true issues).
|
||||
to name strings, unlike the labels array on `get`).
|
||||
|
||||
**Call:**
|
||||
```
|
||||
```text
|
||||
issue_read method: "get" owner: <owner> repo: <repo> issue_number: <N>
|
||||
```
|
||||
|
||||
@@ -95,7 +95,7 @@ gotcha in SKILL.md.
|
||||
- `remove_deadline` (boolean, optional)
|
||||
|
||||
**Create:**
|
||||
```
|
||||
```text
|
||||
issue_write method: "create"
|
||||
owner: <owner> repo: <repo>
|
||||
title: <title> body: <body>
|
||||
@@ -105,19 +105,19 @@ issue_write method: "create"
|
||||
```
|
||||
|
||||
**Close:**
|
||||
```
|
||||
```text
|
||||
issue_write method: "update" owner: <owner> repo: <repo> issue_number: <N> state: "closed"
|
||||
```
|
||||
There is no `method: "close"` — using one will error.
|
||||
No `method: "close"` exists — using one errors.
|
||||
|
||||
**Comment:**
|
||||
```
|
||||
```text
|
||||
issue_write method: "add_comment" owner: <owner> repo: <repo> issue_number: <N> body: <text>
|
||||
```
|
||||
|
||||
**Apply resolved label IDs directly** (bypassing `references/enrichments.md`'s inference step, e.g.
|
||||
when the caller already named exact labels):
|
||||
```
|
||||
```text
|
||||
issue_write method: "add_labels" owner: <owner> repo: <repo> issue_number: <N> labels: [<IDs>]
|
||||
```
|
||||
To replace all labels atomically instead of adding: `method: "replace_labels"`.
|
||||
|
||||
@@ -22,12 +22,12 @@ time (see `references/sources.md`) — confirmed to match `api-reference.md`.
|
||||
- `per_page` (number, optional, default `30`)
|
||||
|
||||
**Call:**
|
||||
```
|
||||
```text
|
||||
search_issues query: <text>
|
||||
```
|
||||
|
||||
**Narrowing the search:**
|
||||
```
|
||||
```text
|
||||
search_issues query: <text> owner: <owner> state: "open" type: "pulls" labels: "bug,urgent"
|
||||
```
|
||||
|
||||
|
||||
Loaded 100 of 210 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user