Repository navigation
Conversation
ADR 0056. Skills live in Trax.Docs/skills/, are marked internal so the skills CLI never serves them from main, and each release publishes them to TraxSharp/skills as a Claude Code plugin and marketplace, stamped with the release version.
Trax.Docs/skills/ holds the skills, kept off the site. Trax.Skills.Publish checks them (name, description, the internal marker, markdown only, links inside the skill) and stages the tree a release publishes; SkillsAreWellFormedTests runs the same rules and resolves every docs link a skill makes. The contributor skill is marked internal so npx skills add TraxSharp/Trax does not offer it.
build stages the skills at the release version; a new skills job, after publish, verifies the staged digests and commits them to TraxSharp/skills through createCommitOnBranch with a GitHub App token scoped to that repository, then tags the commit. Both stay off until the SKILLS_APP_ID repository variable is set.
EveryCSharpFenceIsMarkedTests and SampleExcerptsMatchSourceTests read published pages only, and skills/ is not published, so a skill's fences went unchecked apart from compile. Both now read the skills too.
A skill is not a site page and links to the pages it routes to inline.
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Theauxm
added this pull request to stack #104
October 20, 2026 19:29
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…ository The release's skills job now commits the staged tree to the skills branch of this repository with its own token and tags it skills-v<version>; no GitHub App and no second repository. A static marketplace on main points Claude Code's trax plugin at the branch, and SkillsAreWellFormedTests holds it to the one the stager expects. ADR 0056 records why the separate repository was dropped.
The release no longer touches skills. A Skills workflow, dispatched with a release tag like website.yml, stages the tree, commits it with the workflow token on top of skills to skills-next (GitHub signs it), then waits on the skills-deploy environment; once approved it fast-forwards skills to that commit and tags it skills-v<version> with a deploy key, the only bypass the skills rulesets allow.
This branch has not been deployed
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.
Trax's agent skills are published from a release tag to a
skillsbranch, only when a maintainer approvesBackground
An agent skill is a folder with a
SKILL.md: a name, a one-line description of when to useit, and instructions a coding agent loads when its task matches the description. Claude Code reads
them natively, as a plugin installed from a marketplace (a repository with a
.claude-plugin/marketplace.json). Most other agents (Cursor, Codex and so on) get them through theskills CLI,
npx skills add <source>, which copies the folders into the agent's own directory.People building on Trax use both. The skills themselves come in the next PR; this one decides where
they live and how they are published. ADR 0056 records it.
Problem
Caution
🟥 Whoever can change the published skills can instruct every consumer's agent.
A skill is instructions an agent follows in someone else's repository, so what is published has to
change only when a maintainer says so.
Example
Release 1.70.0 is out. A maintainer then dispatches Skills with
v1.70.0, as they dispatchWebsite:
stagev1.70.0;Trax.Skills.Publish stagecopiesTrax.Docs/skills/*, stripsinternal: true, writestrax-version: "1.70.0"into eachSKILL.md, writesplugin.jsonat 1.70.0, a README and the licence; uploads the tree with its digestspreparecontents: writeskills-nexttoskills, commits the tree on it throughcreateCommitOnBranch(GitHub signs it), and lists every file added, changed or removed, with a compare link, in the run summarypublishskills-deployenvironment; once approved, fast-forwardsskillsto exactly the commitpreparemade and tags itskills-v1.70.0The release workflow is unchanged and never touches skills.
A source skill and the same skill on the branch:
Then, in an app:
npx skills add TraxSharp/Traxon its own finds nothing,--full-depthincluded: every sourceskill is marked internal, and the CLI does not follow a marketplace to another ref (both measured).
An install from a tree URL records the ref in
skills-lock.json, andnpx skills checkkeeps itthere.
How this solves it
Caution
🟥 Only an approved run moves the
skillsbranch.Its ruleset refuses updates, deletion and force pushes to everything but deploy keys, and the tag
ruleset does the same for
skills-v*, creation included. The key is a secret of theskills-deployenvironment, so it is released only when a maintainer approves the run. A deploy key cannot push a
commit GitHub would verify, and the
Commitsruleset requires one, so the work is split: theworkflow token writes the signed commit to
skills-next, which nobody installs from, and the keyonly moves
skillsto it, as a fast-forward that is refused ifskillsmoved since. A tag isnever moved: one that already names another commit fails the job.
flowchart LR Tag["v1.70.0 tag"] --> Stage["stage: Trax.Skills.Publish"] Stage -->|"tree + digests"| Prep["prepare: commit to skills-next"] Prep --> Next["skills-next: signed preview"] Next --> Approve{"🟥 skills-deploy approval"} Approve -->|"deploy key, fast-forward"| Branch["skills + skills-v1.70.0"] Market["main: .claude-plugin/marketplace.json"] -->|"plugin source ref: skills"| Branch Branch --> CC["/plugin install trax@traxsharp"] Branch --> CLI["npx skills add .../tree/skills"] class Tag,Stage,Prep,Next,Approve,Branch,Market,CC,CLI tooling classDef tooling fill:#334155,stroke:#0f172a,color:#fffThe first version of this PR published to a separate
TraxSharp/skillsrepository through a GitHubApp, from the release itself. Once the internal marker turned out to be needed anyway,
mainservesnothing, so the second repository only bought a shorter install URL; and publishing from the release
left nobody approving what changed. ADR 0056 records all three.
Checked: the Trax.Docs suite and ADR guard green; actionlint, shellcheck and zizmor clean on the
workflows and script; the prepare script run against a stubbed
ghfor a first run (creatingskills-next), a later run (resetting it), an unchanged tree and a missingskills; a staged treepassing
claude plugin validate --strictand listing and installing with the skills CLI; the rootmarketplace passing
claude plugin validate --strict.Architectural hinges
Trax.Docs/adr/0056-agent-skills-are-written-in-the-docs-and-published-from-a-release.md:the decision, the measurements behind the internal marker, and the options rejected (a separate
repository, publishing from the release, skills on
main, plugin-only, copies in every template).Trax.Docs/tools/Trax.Skills.Publish/SkillRules.cs(SkillRules.CheckOne): every rule askill must pass, shared by the guard test and the stage.
Trax.Docs/tools/Trax.Skills.Publish/Stager.cs(Stager.Stage,MarketplaceManifest): whata consumer actually installs, and the marketplace that points Claude Code at it.
.github/workflows/skills.yml: the three jobs, what each holds, and the approval between thesigned commit and the live branch.
.github/scripts/publish-skills.sh: the signed commit onskills-nextand the change list theapprover reads.