Skip to content

#1125 Honor invocation tokens in rulebook bodies - #1129

Merged
williamthorsen merged 10 commits into
mainfrom
1125
Jul 31, 2026
Merged

#1125 Honor invocation tokens in rulebook bodies#1129
williamthorsen merged 10 commits into
mainfrom
1125

Conversation

@williamthorsen

@williamthorsen williamthorsen commented Jul 31, 2026

Copy link
Copy Markdown
Owner

What

A rulebook can now route an agent to another skill, subagent, or rulebook as a direct invocation rather than a name mentioned in prose; each delivery renders that invocation in the form the receiving harness understands. A rulebook that routes to a missing target, or to one that deploys nothing an agent can invoke, now fails the run. Naming a routing target is now enough to have it deployed alongside the rulebook that names it.

Why

A hub-and-spoke guidance set exists to send an agent to the right reference, and a rulebook had no way to say where. Prose routing left the reader a name to type, with nothing guaranteeing the named artifact had been deployed and nothing failing when it did not exist -- a gap that widens as more packages ship a cheatsheet plus a set of reference rulebooks.

Details

🎉 Features

  • A {rulebook:<slug>} token in a rulebook body renders the harness skill sigil plus the skill name its target deploys under, honoring a skill-name override on that target.
  • {skill:} and {subagent:} tokens render in a rulebook body as they already do in skills and subagents, in both ambient and skill delivery.
  • A token naming a rulebook that deploys no skill to invoke fails the run before anything is written, reporting every offending token at once and pointing at dependencies: for the relationship it cannot express.
  • The error for an unusable token names the file carrying it, so an author goes straight to the source.
  • Linking to a sibling rulebook still fails, and the rejection now names the {rulebook:<slug>} token that addresses it instead.
  • The content specification documents the new kind, why only a rulebook body renders one, why an ambient-only target is rejected, and which token kinds are checked against the deployed set.

🐛 Bug fixes

  • A declared subagent whose body fails to render aborts the sync before the ambient host and skill files are written, and fails --dry-run rather than passing it. This covers an unmapped {tool:NAME} placeholder alongside the newly rejected token.

🏗️ Internal features

  • The invocation-token grammar recognizes a rulebook kind alongside skill and subagent, resolving a target to the skill name it deploys under or reporting why it cannot.
  • A token in a rulebook body is a closure edge, so a named target deploys without a duplicate dependencies: entry. A rulebook naming itself keeps the reference without becoming a dependency cycle, and a {rulebook:} token counts as an edge only from a rulebook body.

♻️ Refactoring

  • The subagent render is extracted from its deploy so the pre-write gate and the write share one path.
  • The rulebook slug derived in the sibling-rulebook rejection no longer shadows the enclosing link-target parameter.

🧪 Tests

  • The shipped-content suite builds a rulebook catalog from every shipped rulebook, turning it into a build-time gate on tokens as well as links.
  • A subagent named by a token in a rulebook body is asserted to enter the deployed closure, alongside the skill and rulebook edges.

Closes #1125

The invocation-token grammar recognizes a `rulebook` kind alongside `skill` and `subagent`. A rulebook token resolves to the skill name its target deploys under, honoring a `skill-name` override, and reports a reason when the target deploys no skill to invoke.
A rulebook that names another artifact by invocation token in its body pulls that artifact into the deployed set, so the reference needs no duplicate `dependencies:` entry. A rulebook naming itself keeps the reference without becoming a dependency cycle.

A `{rulebook:<slug>}` token counts as an edge only from a rulebook body, the one place it renders.
A rulebook body may now invoke what it routes to. A `{rulebook:<slug>}` token renders as the deployed skill name of the rulebook it names, and `{skill:}` and `{subagent:}` tokens render in a rulebook body as they already do in skills and subagents. Each renders behind the sigil of the harness it is delivered to, in both ambient and skill delivery.

A token naming a rulebook that deploys no skill to invoke fails the run before anything is written, naming every offending token at once and pointing at `dependencies:` for the relationship it cannot express.
Linking to a sibling rulebook still fails the run, and the error now names the `{rulebook:<slug>}` token that addresses it instead, so the rejection teaches the convention rather than only reporting the rule.
…fication

The content specification describes `{rulebook:<slug>}` alongside the skill and subagent tokens: what it renders to, why only a rulebook body renders one, and why an `ambient`-only target is rejected in favor of `dependencies:`. The links section now sends an author writing a sibling-rulebook link to the token instead, and the rewriting caveat covers tokens as well as links, so an example keeps its `<slug>` placeholder rather than naming a real artifact.
…ries it

The error raised for an unusable `{rulebook:<slug>}` token names the file it was found in, so an author fixing a skill or subagent goes straight to the source rather than searching the deployed set for it.
A subagent whose body fails to render now aborts the sync before the ambient host and skill files are written, and fails `--dry-run` rather than passing it. Previously the failure surfaced only in the last write pass, leaving earlier passes already on disk.

This covers an unmapped `{tool:NAME}` placeholder as well as the `{rulebook:<slug>}` token a subagent body may not carry.
A subagent named by a token in a rulebook body is asserted to enter the deployed closure, alongside the skill and rulebook edges already covered.

Drops a rulebook-transform assertion whose name claimed the pre-pass runs before rewriting. Both paths throw, so the assertion held either way; the sibling case asserting two offending tokens in one error is what distinguishes them.
The rulebook slug derived inside the sibling-rulebook branch is named `targetSlug`, so it no longer shadows the enclosing `target` parameter holding the link target as authored.
The content specification states that only `{rulebook:<slug>}` is checked against the deployed set. A `{skill:<slug>}` or `{subagent:<slug>}` token renders on every harness its body reaches, including one its target narrows itself away from with `harnesses:`, so an author naming such a skill scopes it in the surrounding text.
@williamthorsen williamthorsen added feature Added or improved external functionality scope:agents labels Jul 31, 2026
@github-actions

Copy link
Copy Markdown

Dependency audit

Production dependency audit passed.

@williamthorsen williamthorsen self-assigned this Jul 31, 2026
@williamthorsen
williamthorsen marked this pull request as ready for review July 31, 2026 01:40
@williamthorsen
williamthorsen merged commit ca9c72d into main Jul 31, 2026
3 checks passed
@williamthorsen
williamthorsen deleted the 1125 branch July 31, 2026 02:03
williamthorsen added a commit that referenced this pull request Aug 4, 2026
…e-v0.2.2 codeassembly-v0.4.0 factory-v0.2.2 codeassembly-mcp-v0.2.2

codeassembly-v0.4.0
- #1153 feat: Make codeassembly and kb CLI tools publishable (#1164)
- #1091 fix: Anchor a project-deployed link where its target deploys (#1159)
- #1156 refactor: Rename packages to publishable names (#1157)
- #1152 tooling: Run every test in the default gate, classified by what it reaches (#1155)
- #1110 tooling: Migrate Vitest to nmr's centralized model (#1154)
- refactor: Refine typescript-preferences
- #1150 fix: State doc-description form and make comment mood opt-in (#1151)
- deps: Upgrade first-party linting deps to latest version
- #1137 feat: Establish personal rulebooks for code layout and TypeScript preferences (#1144)
- #1126 feat: Check a package's own guidance content before it ships (#1138)
- refactor: Fix lint
- tooling: Remove redundant lint rules
- #1133 fix: Reject an anchor link that names no heading (#1135)
- #1122 feat: Capture lede decisions as an accumulating corpus (#1132)
- #1125 feat: Honor invocation tokens in rulebook bodies (#1129)
- #1107 feat: Render rulebook links and path tokens per harness (#1124)
- #1115 feat: Sync guidance at build and install so an upgrade cannot leave it stale (#1123)
- #1114 feat: Adopt a dependency's guidance by naming the package (#1121)
- #1088 feat: Deliver project ambient rulebooks per harness (#1113)
- #1087 refactor: Rename the authoring rulebook and mark its enforced rules (#1092)
- #1095 tooling: Move compilation out of the install lifecycle into a bootstrap step (#1102)
- #1094 refactor: Remove the ambient ripgrep dependency from the test suite (#1097)
- deps: Upgrade all deps to latest version
- tooling: Upgrade all deps to latest version & modernize configs
- refactor: Fix lint
- #1077 feat: Show the proposed edit above post-review menu options (#1078)
- #1068 feat: Deliver ambient rulebooks mechanically, retiring GLOBAL.md (#1075)
- #1069 feat: Add a no-second-person rule to the lede-voice doctrine (#1070)
- #1050 feat: Add a redundancy rule to the lede-voice doctrine (#1058)
- #1035 internal: Add lifecycle workspace with the canonical envelope, vocabulary & lane fold (#1049)
- #1006 internal: Extend lifecycle-event instrumentation to five high-traffic skills (#1034)
- #1028 feat: Rule out absence-of-removed-code tests (#1032)
- #114 feat: Let reviewers emit gated insights into review artifacts (#1031)
- #1027 internal: Retire input.received and redundant skill.progress emits (#1030)
- #1026 fix: Name the side effects an approval ask authorizes (#1029)
- #1022 fix: Normalize action and question label identifiers across asks blocks (#1025)

factory-v0.2.2
- #1156 refactor: Rename packages to publishable names (#1157)
- deps: Upgrade all deps to latest version
- #1152 tooling: Run every test in the default gate, classified by what it reaches (#1155)
- #1110 tooling: Migrate Vitest to nmr's centralized model (#1154)
- tooling: Remove redundant lint rules
- deps: Upgrade deps to latest version
- deps: Upgrade all deps to latest version
- deps: Upgrade all deps to latest version
- tooling: Upgrade all deps to latest version & modernize configs
- refactor: Fix lint
- deps: Upgrade all deps to latest version

kb-v0.3.0
- #1153 feat: Make codeassembly and kb CLI tools publishable (#1164)
- #1156 refactor: Rename packages to publishable names (#1157)
- #1152 tooling: Run every test in the default gate, classified by what it reaches (#1155)
- #1110 tooling: Migrate Vitest to nmr's centralized model (#1154)
- tooling: Remove redundant lint rules
- #1095 tooling: Move compilation out of the install lifecycle into a bootstrap step (#1102)
- tooling: Upgrade all deps to latest version & modernize configs
- refactor: Fix lint

codeassembly-lifecycle-v0.2.0
- #1153 feat: Make codeassembly and kb CLI tools publishable (#1164)
- #1156 refactor: Rename packages to publishable names (#1157)
- #1152 tooling: Run every test in the default gate, classified by what it reaches (#1155)
- #1110 tooling: Migrate Vitest to nmr's centralized model (#1154)
- tooling: Remove redundant lint rules
- #1095 tooling: Move compilation out of the install lifecycle into a bootstrap step (#1102)
- tooling: Upgrade all deps to latest version & modernize configs
- #1038 feat: Add the read-only git adapter for worktree and base-branch ground truth (#1059)
- #1051 feat: Bound fold memory and rescan cost with a retention window (#1057)
- #1035 internal: Add lifecycle workspace with the canonical envelope, vocabulary & lane fold (#1049)

codeassembly-mcp-v0.2.2
- deps: Upgrade all deps to latest version
- #1156 refactor: Rename packages to publishable names (#1157)
- #1152 tooling: Run every test in the default gate, classified by what it reaches (#1155)
- #1110 tooling: Migrate Vitest to nmr's centralized model (#1154)
- #1095 tooling: Move compilation out of the install lifecycle into a bootstrap step (#1102)
- tooling: Upgrade all deps to latest version & modernize configs
- refactor: Fix lint

codeassembly-run-core-v0.2.2
- #1156 refactor: Rename packages to publishable names (#1157)
- #1152 tooling: Run every test in the default gate, classified by what it reaches (#1155)
- #1110 tooling: Migrate Vitest to nmr's centralized model (#1154)
- #1095 tooling: Move compilation out of the install lifecycle into a bootstrap step (#1102)
- tooling: Upgrade all deps to latest version & modernize configs
- refactor: Fix lint
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Added or improved external functionality scope:agents

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A rulebook routes to other artifacts in prose, not by invocation

1 participant