8359d61e33a285bb63cc74cdedc7bf1d888a2dd6
6
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
1d368d4b5d |
docs(skills): drop the Mode 2 routing notes, fix the contributing steps
Seven skills carried a `## Mode 2 Routing Note` citing a routing pod ("Plan 6")
that does not exist. Several admitted in their own text that nothing about the
skill changes between modes — so it was roughly ten lines of context on every
load for zero behavioural effect. The content is not worthless, just not
per-skill: it now lives as one table in README.md, with the caveat that nothing
depends on it.
The related line inside the session_log sections stays, because that one does
motivate behaviour — but it no longer cites a component that has never shipped.
It now says what is true: pass-rate is what a future routing decision would be
based on, and a skill that never logs contributes no evidence either way.
While in README: the contributing steps were stale enough to fail CI for anyone
who followed them. They said to add a row to SKILLS_INDEX.md by hand — the table
is generated now, and `task check` fails on a hand-edited diff — and listed none
of the four frontmatter keys the gates require. Step 4 now names the
pressure-test bar from #19 rather than leaving it to be discovered.
Closes #36
Bump-Type: patch
|
||
|
|
b616c51a2c |
fix(skills): document a session_log call the tool would actually accept
Nine skills documented the payload. None named `session_id`, which is the tool's only required field. So every documented call was one the tool rejects — an agent following any of them either failed the call or invented an id, and invented ids do not group, which means the pass-rate the /pass-rate endpoint computes was being assembled from entries that cannot be joined. Found by the #19 pressure test against `debug`, which invented `debug-signed-artifact-missing-2026-08-29` and said so: "my three entries are only groupable by luck of naming". The grep afterwards showed it was fleet-wide, not a `debug` bug. Also removed: `duration_ms: <wall-clock>` in eight of them. An agent does not observe a clock. The same run omitted it "rather than fabricate", which is the good outcome; the bad outcome is the run that fabricates, and a made-up number in a metrics stream is worse than a missing one. It is an optional field and is now simply absent. bin/check-session-log gates both, with tests. This is exactly the case #19 has in mind for a small tool over prose: the rule is a grep, so it should be a gate, not a note asking people to remember. Closes part of #36 Bump-Type: patch |
||
|
|
51a2d396fd |
docs(spec): EARS-lite behavioural criteria and a context snapshot
Both skills gain EARS-lite as an option alongside prose criteria: WHEN/WHILE/IF plus the unconditional form, for behaviour that a measurable threshold cannot express. feature-spec also gains a Context snapshot section — the executor of a spec routinely cannot open the architecture document it points at, so the facts it depends on get inlined with provenance. Pressure-tested per #19, and the RED phase argued against half the issue. A subagent with no skill wrote a strong spec and then explained that it had deliberately NOT inlined architecture context, "because both are owned by the existing architecture document and duplicating them here would create two drifting sources of truth". That objection is correct, so the section is built around answering it: snapshot what the implementer cannot look up, always cite source and version, and state that the source wins on disagreement. Prose criteria came out fine unaided; EARS phrasing did not appear at all, which is where the real gap was. The GREEN run then found seven defects in the first draft, all fixed here: - The example was in the same domain as the test scenario, so it got copied rather than read — the spec inherited an extraction-confidence requirement its feature request never mentioned. The example is now deliberately off-domain, with that failure written up as the reason. - EARS-lite had no unconditional form, so a genuine invariant ("no instruction above threshold ever reaches a file") had to be bent into a WHILE that a system trivially satisfies by never entering the state. Added. - "Maps 1:1 onto a test" was false for the WHILE form, which is universally quantified. Softened to say which forms map to one test and which do not. - The provenance rule had no answer for the case it was written for: an author who also cannot read the source. Now: mark the block UNVERIFIED in those words and make confirmation the implementer's first task. - "Snapshot only what this spec's decisions rest on" was narrower than the section's own purpose; a table name underpins no decision and still blocks the migration. Widened, with the omissions stated deliberately. - "Say so in the section itself" did not say what, at what granularity. Now one opening line, not a per-fact annotation. - The template had no slot for EARS lines, so their placement was a guess. Added as a subsection with a note that they are properties, not checkboxes. Closes #12 Bump-Type: minor |
||
|
|
c6787e04d7 |
feat(index): generate the skills table from frontmatter
Second half of #29. The index was hand-maintained and had already drifted once: dream and experiment-spec shipped with no row, their rows lost to a squash-merge after a directory reorg. bin/check-index caught that after the fact; generating removes the class. The curated summary and trigger move into each SKILL.md as `summary:` and `use_when:`, carried over verbatim from the existing table rather than derived from `description:` — description is a paragraph written for model selection, and truncating it would have produced a worse table than the one it replaced. Knowledge now lives once, next to the skill it describes, which is the argument that made a hand-maintained index the wrong shape to begin with. The table is written between markers, so the wiring docs, the relationships tree and the trigger table below it are untouched — those are prose, not data. Rows are alphabetical now; the conceptual grouping the old order carried lives in the relationships tree, which is the better place for it. A fourth column shows each skill's surfaces, which is what makes #29's field visible rather than merely enforced. bin/check-index and its test are deleted: a generated table cannot drift in either direction, so `generate-index --check` subsumes both of its assertions. Verified by mutation — deleting the tdd row turns `task check` red with "SKILLS_INDEX.md is out of date". Closes #29 Bump-Type: minor |
||
|
|
90a58f0b9e |
feat(skills): declare which surfaces each skill ships to
The repo distributes three ways — the Claude Code plugin, the symlinked library for Crush/Pi/OpenCode, and claude.ai, which has no fetch path at all — and treated every skill as belonging to all of them. claude.ai is not a fourth host to mirror: gitea-ci, playwright and web-shot have no shell and no cluster there, so a flat mirror installs skills that can never fire and degrades selection for the ones that can. Every SKILL.md now carries `surfaces:`, defaulting to [claude-code, library]; dream, own-the-task and grill-me add `chat`, matching what is actually installed on claude.ai today. Claude Code accepts the extra key — `claude plugin validate` passes and the skills still load. bin/check-surfaces validates values, not just presence, because the failure mode here is silent: a wrong surface removes a skill from a harness rather than erroring. install.sh links only skills whose surfaces include `library`, and a source that declares nothing at all is treated as foreign and linked as-is — Anthropic's official set has no reason to know this convention. doctor's missing-link check skips non-library skills for the same reason. Refs #29 Bump-Type: minor |
||
|
|
56a947b2a0 |
refactor(plugin)!: ship as a Claude Code plugin, one dir link per harness
Skills move to skills/<name>/SKILL.md and the repo gains both manifests, so it is now a marketplace hosting exactly one plugin whose root is the repo root (source: "."). Claude Code installs it from git; no symlinks involved. Why: install.sh wired the library into every consuming repo as an ABSOLUTE symlink to $CHECKOUT_DIR. The checkout moved three times, most recently when local-dev@1966d5a dropped the embedded .skills/ copy, and nothing migrated the links — 243 dangling links across 12 repos, hidden from git by the **/.claude/skills/ ignore rule. Worse, ~/dev spans two path roots (/Users/mathias on the iCloud-shared Macs, /home/mathias on koala), so an absolute link stored there is broken on one side by construction. Re-running the installer cannot fix that; only removing the mechanism can. install.sh keeps the harnesses with no plugin system and drops from 42 links per harness to one directory link, via the convergent ~/.agents/skills convention that Pi and OpenCode both read: ~/.agents/skills -> $CHECKOUT_DIR/skills ~/.config/crush/skills -> ~/.agents/skills ~/.config/opencode/skills -> ~/.agents/skills wire_claude_repo is deleted outright rather than gated behind a flag — on a mixed-root fleet it cannot be made correct. Antigravity and Vibe targets go too; both unused. CHECKOUT_DIR keeps its host-local default deliberately: pointing it into ~/dev would put a git working tree inside iCloud with two concurrent writers. Taskfile drops five near-identical wiring loops (they had already drifted) and delegates to install.sh. `task check` gains frontmatter validation, a stray-root-entry gate, and manifest/tag version parity — the loose secret-hygiene.md sat unloadable for months because nothing checked layout. Verified: claude plugin validate . passes clean; a probe skill loaded as skills:zzprobe through --plugin-dir; task check green at 42 skills. Refs: #23 Bump-Type: minor Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BeAp5LTscnz2W7Ubt4eJ6m |