feat(kyberforge): ADR-0020 context contract for skills and agents #103
Merged
Defame1297
merged 18 commits from 2026-08-16 21:20:02 +00:00
refactor/trim-skills-agents-context into main
18 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
| 54d7bd80ba |
docs: rule host built-ins out of the routing target universe
Closes the second open design decision on PR #103. The `/compact` finding was recorded as a false positive needing an allowlist or a suppression mechanism. It is neither: the routing universe is the apm marketplace, so a target either resolves to a skill or an agent or it does not resolve, and `/compact`, `/clear` and `/init` are Claude Code slash commands with no counterpart in Copilot CLI or Codex. `.apm/` source compiles for all three, so a vendor-neutral description routing to one is a portability defect and the hard FAIL is a true positive. An allowlist was rejected for a concrete reason, not a stylistic one: it answers a different question ("does this exist on some host?"), it cannot answer that portably from a single source file, and it goes stale the next time a host ships a command — reintroducing the same-commit-two-verdicts failure ADR-0020 already closed for deployed trees. Nothing is blocked today: zero of the 43 descriptions name a host built-in, and an author who needs to mention one writes it un-slashed, which is not route notation and carries no routing claim. Recorded in ADR-0020 and in both author-facing contract references, so the next agent reads the decision rather than "fixing" the gate. ADR: 0020 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
|||
| 75a13c82f6 |
fix(kyberforge): scope corroboration to a real sentence boundary
A prose-form routing target blocks a commit only when its own sentence names another target that resolves. That makes the sentence splitter part of the ADR-0020 contract rather than an implementation detail, and the naive "period, space, capital" rule got it wrong in both directions: - OVER-SPLIT: `e.g. "..."` is not a sentence end, but the quote looks like a start. The clause was cut in half and the corroborator stranded on the far side, so a genuinely dangling target silently demoted to SUGGESTION — a measurement taken and then discarded, the vacuous-green shape this gate exists to prevent. Seven such splits are live in the current corpus. - UNDER-SPLIT: a sentence opening with a code span or a lowercase skill name was not seen as a start, so two sentences merged and a resolving target vouched for an unresolvable one it never stood beside — a hard FAIL with no escape hatch, which is the exact failure corroboration was added to prevent. The splitter now excludes the five abbreviations that occur in routing prose and admits a backtick or lowercase letter as a sentence opener. Applied byte-identically to all three copies of the shared resolver. Verified zero-delta against the corpus: 37 ERROR / 58 SUGGESTION / 2 dangling before and after, findings byte-identical. The exposure this closes is to the descriptions #99 is about to rewrite, not to the ones already measured — which is why the deferral reason recorded on PR #103 ("can move the documented corpus counts") does not hold and the fix lands here rather than after the retrofit. Three regression tests, one per direction plus the backtick opener, each proven non-vacuous by reverting the splitter alone and watching it go red. Refs: #99 ADR: 0020 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
|||
| 79c9089122 |
docs: make the resolution contract match what the gate actually does
Both AGENTS.md and ADR-0020 said deployed .claude/.agents trees are consulted "only
when no authoring root exists". That stopped being true in
|
|||
| ede3f06689 |
fix(kyberforge): restore the authoring rules the ADR-0020 trim dropped
Diffing each retrofitted SKILL.md against its replacement references/ files found rules that existed on main and now existed nowhere — relocated in intent, deleted in fact. A trim that loses a rule is not progressive disclosure, it is data loss with a smaller word count. Three had no survivor. The least-privilege guidance for `tools` kept its mechanics and lost the "restrict to what the agent needs" half, so the remaining text read as encouragement to omit the field. The improve flow lost its regression check, so nothing compared the closing audit against the pre-edit state and a PASS quietly becoming a SUGGESTION went unnoticed — restored on both halves of the author pair, since agent-author had dropped its equivalent too. And agent bodies lost "would the agent get this wrong without it?", which mattered more than it looks: ADR-0020 deliberately sets no body word gate for agents, three of the four already sit between 933 and 1,199 words, and the delegation check only fires on procedure a skill already owns. That heuristic was the only brake left. Two more were reachable only from the wrong scope. agent-author tells the reader to load only the file for the resolved scope, but the mcp__ glob syntax for disallowedTools and the five tools no subagent ever receives had both landed in project-user-scope.md. disallowedTools is the ONLY permitted fence at plugin/APM scope, so the scope that needs the syntax most could not reach it, and a plugin-scope run could write a body telling the agent to ask the user a question. Two documents were actively wrong rather than merely thin. agent-audit told auditors that validate.sh resolves boundary targets for skills only; it runs at both scopes, so the auditor was hand-resolving what the script had already decided and could contradict it. And skill-audit routed to its script-troubleshooting reference whenever validate.sh "fails" — but it exits 1 on ordinary content FAILs, the normal outcome for the whole #99 population, so 1,302 words loaded on nearly every audit. A context-budget regression inside the skill that enforces the context budget. Finally, two illustrations taught the shape the gate ERRORs on, unfenced, while an adjacent rubric called it a hard ERROR. LESSONS.md records the reference-chain depth rule flipping from "one level deep" to "two hops, never three". ADR-0020 is silent on it and the reversal rode entirely on the diff; the looser rule is what mandatory dispatch requires. Refs: #99 ADR: 0020 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015W3iwF9ncfRZddGBxsMCYi |
|||
| b0d6d08239 |
test: pin the nine ADR-0020 gate defects that shipped untested
Every defect fixed in
|
|||
| f7cc27908c |
fix(kyberforge): close the vacuous-green and consumer-resolution defects
Review of the ADR-0020 gate found four ways it could exit 0 without measuring, and one way it hard-failed a repo it had no business failing. On a gate shipping hot with no baseline, a silent pass is the worst outcome available and a false block is the second worst. Consumer resolution was the blocker. _authoring_root() fell back to the nearest .git, so it returned truthy in ANY git repo; _collect_authoring_root() then contributed nothing and the deployed-tree branch was dead code in precisely the consumer case it exists for. A consumer repo routing to an installed sibling got an unblockable ERROR, and deleting .git "fixed" it. It now keys on which of the two walk-up passes matched. A name-count delta was tried first and is wrong: a single-plugin monorepo re-collects its own package and adds no new name, so the delta reads zero and drags the deployed trees — including a global ~/.claude — back into the universe. That reintroduces the install-dependence ADR-0020 forbids, one layer down. The three silent passes: an indented `---` inside a block scalar truncated the frontmatter and reclassified the rest of the description as body; a non-string description was str()-coerced, so `description: true` measured as the four-character "True"; and an unterminated fence blanked the rest of the body, disabling the ERROR-tier references/ check and the gotcha counts. Two measurement defects came with them. The awk line/word counts discarded awk's exit status, so an unreadable file passed both spec ceilings in total silence, and awk NR/NF disagreed with the audit script's splitlines()/split() on Unicode whitespace — the "fix one gate, get blocked by the other" bug, on the two axes the differential test deliberately excluded. Both counts now run in the Python block that already reads the file. A type error also no longer reports itself as a syntax error. Also: glob metacharacters in the checkout path silently disabled the resolver; re.I was applied to some extraction patterns and not others; agent-audit missed `tools:` written as a YAML block sequence, the shape Copilot files use; and a nonexistent agent file raised a bare FileNotFoundError instead of a diagnostic. The shared resolver block stays byte-identical across all three scripts. Corpus output is unchanged — 26 description FAIL, 9 body FAIL, 2 dangling, 0 missing references, 58 SUGGESTIONs — so no documented count moves. Refs: #99 ADR: 0020 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015W3iwF9ncfRZddGBxsMCYi |
|||
| e7ebc667b3 |
chore(release): kyberforge 1.6.0, marketplace 0.4.2
The four preceding commits change `plugins/kyberforge/.apm/` content that reaches the compiled artifacts — three validators, a new reference file in each of `skill-audit` and `skill-author`, and the authoring rules across both author skills — so per `apm-workflow`'s configure policy the package earns a bump, minor for the new capability. Root `apm.yml`'s `executables.allow` key moves with it, in this commit and not a later one. apm approves a package's `hooks/` and `bin/` by an exact `<name>#<version>` dictionary lookup with no wildcard and no version-less form, so a `kyberforge#1.5.0` key left behind a 1.6.0 package errors nowhere: the entry stops matching, the `SessionStart` freshness hook stops deploying, and the install goes quietly stale. That is the failure ADR-0019 records as having actually happened, and `check-executables-allow-sync` exists to catch it. The catalog bump was missing from the working tree and is added here. `apm-workflow`'s marketplace policy is explicit that an existing entry's `version:` moving earns the catalog a **patch** — the set of packages is unchanged, only its metadata moved — and that the root `version:` stays in step with `marketplace.version`, since apm audit reads one and the compiled manifest carries the other. Nothing enforces this: `apm pack --check-clean` catches a bump made in `apm.yml` but never re-packed, while a bump never made at all fails nothing. Manifests regenerated with `apm pack` plus `scripts/sync-marketplace-mirror.sh` for `.github/plugin/marketplace.json`, which no apm output profile targets. `.agents/plugins/marketplace.json` is unchanged — the codex profile's shape carries no version field for either the catalog or its entries. |
|||
| 64ffb9f35a |
docs: make ADR-0020 match what actually shipped, and record what did not
The ADR was written against base commit `f9b919d` and then not updated as the implementation moved, so several of its numbers were measuring one thing and being read as another — the exact conflation the ADR exists to stop, reproduced inside it. Corrections, all reproducible now that each figure states its method: - The preload tax is 23,427 chars / ~5,900 tokens, not 23,612 / ~6,200. - `MAX_WORDS=2770` is a density proxy for the agentskills.io ~5,000-token ceiling, not "2× p90". Neither percentile reaches it: 2× the body-only p90 is 2,698 and 2× the whole-file p90 is 3,052. Reading it as a percentile pairs a whole-file gate against a body-only distribution. - `apm-workflow` is a 421-word body; 554 is its whole-file count. `skill-author` and `agent-author` were 2,623 and 2,582 body words — 2,760 and 2,758 whole-file, which is where "within twelve words of the gate" comes from. Two numbers for one file is the point, and only one of them is what either gate measures. - Every `file:line` citation now says it resolves against `f9b919d`, since this change rewrites most of the cited files. Three things the ADR asserted that no validator implemented are now filed by tier in an exhaustive enforcement table — deterministic, prose-pattern, or auditor judgment — because a rule filed under "Enforcement" that nothing enforces is the failure mode this ADR is most exposed to. The Gotchas entry count moves to SUGGESTION to match the script; the paraphrase FAIL is marked as an auditor's, since semantic equivalence is not pattern-matchable. Two gaps recorded rather than quietly left: - The agent body-gate exemption lives in `agent-audit`'s validator and in the `skill-size-check` hook's `SKILL.md`-only `files:` pattern — *not* in `scripts/skill-size-check.sh`, which measures whatever path it is handed and today reports 900-word body FAILs on `git-orchestrate` (933), `gitea-orchestrate` (1,199) and `apm-orchestrate` (1,080). Agents escape by file pattern, not because the script knows the difference, so widening that pattern would silently enforce a gate this ADR declines to set. - The `skill-audit`/`agent-audit` merge is deferred to #101. This change made the split deeper, not shallower: the dispatch retrofit took them from 3 and 4 reference files to 7 and 8, and their two same-named `description-quality.md` files now differ on 100 of ~120 lines after normalising skill/agent. The merge reopens ADR-0008 and touches every call site in `skill-author`, `agent-author` and `forge`, so it is its own change. #100 carries the dangling-target fixes. AGENTS.md and CONTEXT.md take the same corrections plus the two live setup changes: PyYAML is now a hard requirement rather than an optional accelerator (a fallback that mis-parses an unfamiliar scalar shape reports a clean pass on a file it never measured), and `.claude/settings.json`'s `pretty-format-json` exclusion is documented as load-bearing rather than as a tidy-up candidate. LESSONS.md's autofix entry is corrected on its own provenance, which it got wrong in both directions. `git log --date=iso` puts the introducing commit at 18:47 and the fix at 21:54 — three hours, not "weeks" — and `git branch -a --contains` puts the introducing commit on this branch only, not on main. It was manufactured inside the same PR that diagnosed it. The added lesson is that "pre-existing" is a claim about history and history is queryable: a defect found while working on a branch feels inherited, and the feeling is not evidence. Refs: ADR-0020, #99, #100, #101 |
|||
| d02765d595 |
fix(ci): close the RUN_TESTS_STRICT leak at its source, not at each caller
|
|||
| 311e7cd22c |
fix(kyberforge): reconcile the authoring rules the ADR-0020 trim left disagreeing
Six defects, each one a place where two files that an author reads in the same sitting told them different things — or where the trim dropped a rule and nothing noticed because no gate covers prose. **"Use proactively" contradicted itself across the pair.** All three agent templates said to add it where the runtime should delegate unprompted, while `agent-audit`'s `KyberforgeCopilot.ProactivePhrase` rule grades it a hard FAIL in any `*.agent.md` — which is the Copilot half of every project/user pair *and* the vendor-neutral plugin-scope file, since that compiles to a real Copilot agent downstream. Following the template produced a file the repo's own gate rejects. The phrase is now permitted in exactly one place, the Claude Code `.md`, and `references/contract.md` carries the per-file table plus the consequence authors ask about next: a pair whose CC half has it and whose Copilot half does not is correct, because `agent-audit` checks that both halves describe the same job, not that they match word for word. **The output-schema rule contradicted itself inside one file.** `contract.md` said any content only one branch reaches moves to `references/`, and then offered an "Output format template" body pattern with no qualification. Stated once now, so it is not re-litigated: an output schema stays in the body only when every flow produces it and it is roughly 50 words or less. No third option. **Gotchas tiers disagreed with the script.** `validate.sh` emits the entry count through `suggest()` and exits 0, while `skill-author` and `skill-audit` both called more than five entries a FAIL. Whether a given gotcha earns its place is judgment, so the prose moves to the script's tier rather than the reverse. The paraphrase rule stays a FAIL and is explicitly marked as the auditor's call — no script detects it. **The dispatch exemplar was cited at the wrong number.** `apm-workflow`'s body is 421 words; 554 is its whole-file count. Both `contract.md` and `body-discipline.md` cited 554 while describing a body budget, so an author calibrating against the exemplar overshot by ~30% — the exact whole-file/body-only conflation those two sections exist to warn against, reproduced inside the warning. **"Error handling" came back as a required body element.** It was one of four and is the one that gets dropped, and dropping it is not neutral: an agent handed malformed input with no instruction invents a recovery, and a subagent's invented recovery is invisible to its caller until the output is wrong. Restored in `agent-audit`'s rubric as a SUGGESTION, in `agent-author`'s contract and both scope checklists as a required element, and as an `## Errors` section in all three templates. **`skill-author` Step 4 gains the one check the audit misses.** An empty body reports `PASS SKILL.md body word count 0` — a word gate cannot tell "concise" from "absent". Step 4 now hand-checks for a non-empty section, and its commit verification is conditioned on actually being inside a git worktree, which a skill under `~/.claude/skills/` is not. Also here: absolute repo paths removed from `skill-author`'s SKILL.md and contract.md in favour of naming the skill (`zoom-out`'s description is quoted inline instead of pointed at), the boundary-target universe documented to match the resolver, a two-hops-from-SKILL.md limit on reference chains, and `new-agent.sh`'s next-steps output naming the description budget and the deliberate absence of an agent body gate. Refs: ADR-0020 |
|||
| 2540e50fcc |
feat(kyberforge): give skill-author a procedure for the #99 retrofit
ADR-0020 shipped its gates hot with no baseline file, so 26 of 39 descriptions and 9 of 39 bodies are over their FAIL tier and editing any of them for any reason requires bringing the skill into contract first. `references/improve.md` said exactly that and stopped there — it mandated a retrofit and supplied no procedure for one. Four dry-run retrofits confirmed what that costs. Asked the same questions — what to cut first, when a body is two flows rather than one, what else has to change alongside — they invented six to ten different answers, so the same skill retrofitted twice produced two different skills and neither run could be reviewed against anything. `references/retrofit.md` fixes the answers: an ordered cut list ranked by tokens removed against behaviour lost (inverting that order is how a retrofit deletes the instruction the skill existed to carry), the test for whether a body holds two mutually exclusive flows, the reference-file conventions, the collateral checklist for `README.md` and `references/sources.md`, and a worked description retrofit. It also states the trap the dry runs kept hitting: retrofit the skill in place, inside its package. The boundary-target universe is built by walking up from the file being checked, so a scratch copy has no authoring root above it, the check prints `INFO ... DID NOT RUN`, and the run still exits 0 — a line that reads as a pass and is not one. A retrofit signed off on a copy carries an unverified boundary target into the corpus. Loaded from the improve flow only when a budget is actually exceeded, so a routine improvement pays nothing for it. Refs: ADR-0020, #99 |
|||
| a85bdbed42 |
fix(kyberforge): restore skill-audit's script-failure fallback and E100 diagnostic
The ADR-0020 body trim took `skill-audit` from 2,623 body words to a dispatch shape, and two things went out with it that were not padding. The manual structural fallback was one. Its replacement was a single sentence telling the auditor to report an INFO when `validate.sh` cannot run — so with no `python3` or no PyYAML, `skill-audit` reported the gap honestly and then audited nothing structural at all. Every ADR-0020 measurement, the whole-file ceilings, the name-to-directory match, the `references/` pointer check and the script hygiene checks silently left the audit. A skill's whole Structure dimension hanging on one optional interpreter is the same vacuous-pass shape the gate scripts were just fixed for, one layer up. The `E100 Runtime error ... does not exist` diagnostic was the other. That exit code means an explicit relative `--config` was passed to `vale-wrap.sh` while vale itself was installed and working; without the note, Step 1's fallback reads exit 2 as "vale unavailable" and downgrades the description, body-discipline and patterns dimensions to full LLM judgment for a config error it could have fixed. That misreading is already recorded in CONTEXT.md as the reason both audit skills stopped passing `--config` at all. Both are restored in `references/validation-scripts.md`, loaded only when a Step 1 script fails — so the body pays nothing for them on a clean run, which is what the dispatch pattern is for. The file also carries the by-hand boundary-target procedure and the three ways to misread the result, including that `INFO ... DID NOT RUN` is not a pass. `references/file-structure.md` gains the one sanctioned spelling for a cross-skill reference. The possessive form (``skill-audit's references/validation-scripts.md``) is the only spelling both rules accept: a full repo path is what that section already forbids, and a bare `references/<file>.md` is now a hard ERROR from the ADR-0020 pointer check, which requires the file to exist in the skill's *own* directory. Without the rule the two constraints look mutually exclusive. Refs: ADR-0020 |
|||
| b6e68e9a2b |
fix(kyberforge): close the vacuous-pass paths in the ADR-0020 gate scripts
Three ways the gates could report green having measured nothing. All three were
invisible to a passing test suite, because pre-commit prints nothing at all for a
hook that exits 0 — a gate that declines to check and a gate that checked and
passed produce the identical signal.
- A UTF-8 BOM, a leading blank line, a trailing space after a `---` marker or
CRLF line endings defeated the `^---\n` frontmatter matcher. Every ADR-0020
check was then skipped and the file passed: measured at the time, a
550-character description with a 1,000-word body exited 0 behind a BOM.
All four shapes are now tolerated, and frontmatter that genuinely cannot be
parsed is a hard ERROR rather than a silent skip.
- An agent file with a valueless `description:` followed by another key let a
line regex capture the *next* key, which looked non-empty, so the
missing-or-empty branch never fired and every gate below it early-returned on
the empty folded value — zero output, exit 0, on a blocking gate. The one
field this contract is entirely about was the one field a gate could fail to
notice was absent. Presence is now decided on the YAML-folded value and
nowhere else, and a missing or empty description is a hard FAIL in all three
validators.
- The hand-rolled frontmatter fallback disagreed with PyYAML across the FAIL
boundary on folded scalars, so which reader happened to be available decided
the verdict. A fallback that mis-parses a scalar shape reports a vacuous pass,
which is worse than not running, so it is deleted: python3 and PyYAML are hard
requirements that fail loudly with an install pointer.
Boundary-target resolution no longer derives its universe from its own location.
A `${BASH_SOURCE}`-relative repo root leaked this repo's 39-skill universe into
every consumer repo running the hook through pre-commit, so a consumer skill
routing to `skill-audit` resolved against a plugin it had never installed. The
interim form resolved through `.claude/` and `.agents/`, which are gitignored
`apm install` output — the same commit reported 2 dangling targets on a machine
that had run the install and 6 on a fresh clone. Resolution now walks up from the
file being checked to an authoring root (nearest ancestor holding
`plugins/*/.apm/{skills,agents}`, else the nearest `.git`, in two passes so a
nested `.git` cannot outrank a real monorepo root); the universe is every skill
and agent under `<root>/plugins/*/` plus the file's own apm package and that
package's declared `dependencies.apm`. Deployed trees are consulted only when no
authoring root exists at all — the consumer case. One commit now gets one verdict,
which a gate shipping hot with no baseline file has to.
Narrowed in the same pass: a routing target inferred from the prose boundary form
and corroborated by nothing else reports at SUGGESTION instead of blocking. A
blocking check with no escape hatch is the wrong trade when the inference from
prose is the weak part of it.
New deterministic checks, all previously untested or absent: every
`references/<file>.md` a body names must exist (ERROR — a broken pointer is not a
style opinion); a description with no boundary clause at all, a Gotchas section
over five entries, and a Gotchas section over 25% of the body are SUGGESTIONs.
Where no universe can be determined the target check prints `INFO ... DID NOT
RUN` rather than passing quietly. Each prose-scanning check needed its own
false-positive fix — a fenced example of a Gotchas section was being read as the
section itself — and those fixes are pinned rather than assumed.
The resolver is one block copied verbatim into all three scripts between
BEGIN/END markers, because a cache-installed plugin's scripts cannot read outside
their own plugin directory. Nothing asserted the copies were still identical; a
one-line edit to a single copy passed every constant-agreement assertion, since
constants are not what drifts.
Tests land here rather than in a later commit. The existing suites assert the old
behaviour and go red against these scripts, so splitting them would leave a commit
whose own `run-tests` pre-push gate fails in isolation.
Refs: ADR-0020
|
|||
| 76075223c7 |
fix(ci): unbreak the pre-push gate — strict-mode leak and apm-owned settings drift
Two pre-existing failures, both red at HEAD before ADR-0020 work began,
both invisible in an ordinary local run.
RUN_TESTS_STRICT leaked from the environment into test-run-tests.sh's
fixture children. The meta-test is itself a suite the runner discovers,
so under the gate's own invocation the variable propagated outer runner
-> batch_run -> the fixture's copy of run-tests.sh, flipping it strict.
Case 10c (a deliberate control asserting a skip is tolerated WITHOUT
strict) then failed. Six further cases were silently running strict too
and asserting against the wrong stream — case 9 was matching the stderr
strict block rather than the stdout skip list it was written to check.
run_fake now spawns via 'env -u RUN_TESTS_STRICT', so fixture strictness
is a property of the case, never of how the file was launched. No
assertion weakened; run-tests.sh itself is untouched.
pretty-format-json --autofix was re-sorting apm's output on the way into
every commit. .claude/settings.json is apm-owned (ADR-0018/0019) and its
exclude list named fifteen generated manifests but not this file, so
since
|
|||
| 36ba7a18f8 |
fix(lint): drop the stale hooks/hooks.json from the content mirror
plugins/lint/hooks/hooks.json was no longer produced from .apm/hooks/, so check-plugin-content-sync failed on it at HEAD: DRIFT plugins/lint/hooks/hooks.json: stale, no longer produced from .apm/hooks/ Surfaced by running sync-plugin-content.sh --all during unrelated work. Unrelated to ADR-0020; committed separately so the contract change stays reviewable on its own. Per ADR-0017's 2026-08-14 amendment, a hooks.json a sync no longer generates is deleted as stale. |
|||
| 4a5c3c0cff |
feat(kyberforge): enforce the ADR-0020 context contract for skills and agents
Skill name+description pairs are preloaded into every session, costing ~6,200 tokens across 39 skills before any skill is invoked. The authoring rules mandated that growth: skill-author:104 and description-quality.md:21 both required padding, while skill-author:102 (the deflating rule) had no FAIL condition behind it. Gates (blocking, no baseline file): - description 250 chars SUGGESTION / 400 FAIL, measured on the folded YAML value - body-only 600 words SUGGESTION / 900 FAIL, independent of the unchanged whole-file 2770-word / 500-line spec backstop - every boundary-clause routing target must resolve to a real skill or agent; catches skill-improve, neuledge-context and gitea-labels - agents take the description gates but deliberately no body gate; a test pins that absence Vale: DescriptionOpener widened to ^This\b, new CompositionNote rule banning architecture notes from descriptions. 10 hits, 0 false positives. Kyberforge's own four skills retrofitted: descriptions 3,364 -> 938 chars (-72%), bodies 8,306 -> 2,487 words (-70%), all via the apm-workflow dispatch pattern. Fixes the skill-improve dangling route and the agent-author misroute to manual review. Also fixes a pre-existing false positive where any line-initial 'read ' was flagged as interactive input, which had already caused two scripts to be rewritten around it. Refs: ADR-0020 |
|||
| 1c6eababb0 |
docs(adr): set a context contract for skill and agent authoring
Every installed skill's name+description is preloaded every session - 23,612 chars (~6,200 tokens) across 39 skills. The authoring rules optimised for triggering reliability with no counter-pressure on size: skill-author:104 and description-quality.md:21 both mandate padding, while skill-author:102 (the rule that would deflate it) is judgment-only and absent from description-quality.md's FAIL conditions. ADR-0020 sets the description shape (trigger + one capability + boundary), two-tier size gates sitting below the unchanged agentskills.io ceilings, a mandatory dispatch pattern for multi-branch bodies, a Gotchas constraint, an agent-side delegation check, and invocation as a design axis. Gates ship blocking with no baseline. Adds five CONTEXT.md glossary entries: preload tax, skill context contract, dispatch body, hand-invoked skill, delegation discipline. Refs: ADR-0020 |
|||
| 2e395a4efa |
chore(apm): sync deployed install after apm update
Deploys kyberforge's SessionStart apm-currency hook into .claude/settings.json (ADR-0019), bumps bin 1.1.2->1.1.3 and kyberforge 1.4.1->1.5.0 in apm.lock.yaml with new exec_status fields, and removes lint's now-empty .apm/hooks/ source dir (the generated hooks/hooks.json mirror is untouched). |