feat(build): copy governances into the skills that use them - #87
Merged
Merged
Conversation
A skill reads a governance today through a pinned `npx <pkg> governance show <name>`, which costs a registry lookup per read and needs network. `plugin build` now copies each governance into the skill instead, so the skill reads it from disk (repobuddy/buddy-agent-harness#122, step 2). The files already in `<skill>/references/governances/` declare which governances the skill uses — nothing is declared in plugin.json. Each is rewritten from its owner's current copy: the plugin being built, else a package it declares as a dependency, which ships the document at `governances/<name>.md`. Governances a copy references are copied too, transitively, and every `governance show <other>` pointer inside a copy becomes an instruction to load the sibling copy, so no copy sends an agent back to a command to reach the next document. The build fails when a declared file names no governance, when a referenced one has no copy to point at, or when SKILL.md does not list a copy under References — the specification asks that every file an agent needs is one level deep from SKILL.md. The copies are committed: they are small text, and a git-sourced install needs its default to work offline. `plugin build --check` writes nothing and exits 1 naming every copy that differs from its source; `pnpm verify` runs it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ADR-0016 records the decision from repobuddy/buddy-agent-harness#122: a governance is copied into every skill that uses it at build time and read from disk at run time, with the copies committed and `--check` verifying them. `plugin/build/` gains the behavior and the scenarios, and the root spec's placement map draws the line between the two governance homes — `governance/` resolves a name for a caller asking at run time, `plugin/build/` places the document in the skill folder at build time. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: 8fde5f7 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Step 2 of the governance-retrieval migration tracked in repobuddy/buddy-agent-harness#122.
Why
A skill reads a governance today through a pinned
npx <pkg> governance show <name>— a registry lookup on every read, network required, and a package runner required onPATH. The only thing that call buys is the guarantee that the skill reads the version it was tested against, and that version is known at build time. So the document moves to build time:plugin buildcopies each governance into the skill that uses it, and the skill reads it from disk.What changed
<skill>/references/governances/is the declaration. The.mdfiles already in that folder say which governances the skill uses. Nothing is declared inplugin.json(the owner's decision in #122).package.jsondeclares — a governance ships in its owner's package atgovernances/<name>.md. The plugin wins a name it and a dependency both ship.governance show <other>) is copied into the same folder.governance show <other>inside a copy becomesLoad `references/governances/<other>.md` if it is not already loaded.— the Agent Skills spec asks thatSKILL.mdreference every file directly, so a copy must never send the agent back to a command. A fence holding nothing but pointers is unwrapped; a fence mixing pointers with real commands keeps it.SKILL.mdthat does not list a copy under References.plugin build --check. The copies are committed (small text; a git-sourced install must work offline).--checkwrites nothing at all and exits 1 naming each copy that differs from its source and the package that owns it.pnpm verifyruns it via the newcheck:governancesscript, so CI catches a commit that skipped the build.Spec: ADR-0016, the
plugin/build/node and 14 newbuild.featurescenarios, and a placement-map bullet drawing the line between the two governance homes —governance/resolves a name for a run-time caller,plugin/build/places the document in the skill folder at build time.Not in this PR
No skill in this repository declares a governance yet, so the check is green and a no-op here. Adoption is step 6 of the migration ("migrate the callers, one repository per change");
plugin-designalso references three documents that ACED will own, and none of them is installed here yet.universal-plugin governance showis untouched. #122 retires it in a later step.Test plan
pnpm verify— 8/8 turbo tasks, 697 tests pass, including the newcheck:governancesrun against this repository.src/governance/copy.test.ts(20): pointer extraction across the pinned-npx, bare-prose and namespaced (<plugin>/<name>) forms; fence unwrapping vs. fence preservation; list-marker and CRLF preservation; a pointer-free body left byte-for-byte alone; the References-section check accepting a bullet or a markdown link, rejecting a mention outside the section or past the next same-level heading.src/governance/copy-sync.test.ts(13): copy from the plugin's owngovernances/, from an installed dependency, and the plugin winning a shared name; a three-deep transitive chain; pointer rewriting end to end;unchangedleaving mtime alone;--checkreportingstalewithout writing; each of the three failure modes.src/build/build.test.ts(5): the copy reported inBuildResult.governancesandwritten; each failure mode throwing;--checkderiving no manifest; one copy across a three-vendor build.src/build/cli.test.mts(3), driving the builtbin/universal-plugin.mjs:--checkexits 1 naming the stale copy and pointing atplugin build, exits 0 when copies match, and the plain build repairs what the check reported.🤖 Generated with Claude Code