Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 62 additions & 23 deletions .agents/skills/agent-conduct/SKILL.md

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions .agents/skills/skill-lifecycle/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ The agent most likely to get a skill wrong is the one editing a skill, and befor
- **Generated distributions serve GitHub Copilot and Claude Code.** `scripts/build_dist.py` generates `.github/skills/` for GitHub Copilot and a Claude-plugin-compatible copy at `.claude-plugin/fleet-skills/`, published through `.claude-plugin/marketplace.json`. Neither generated tree is hand-edited, and `build_dist.py --check` exits non-zero when either tree differs from `.agents/skills/`.
- **The skill set is implicit.** Every `.agents/skills/<name>/` directory carrying a `SKILL.md` is a skill, and the generated `plugin.json` derives its list from those directories, so adding or retiring a skill edits no manifest by hand. `marketplace.json` names the plugin, not the skills, and is untouched by ordinary lifecycle work.
- **A rule's text reaches a skill as a generated include, never as a copy.** A region opened by a line holding only `<!-- include: <path> > <heading> -->` and closed by a line holding only `<!-- /include -->`, each indented at most three spaces, is filled by `build_dist.py` with the body under that heading. The key is the root-relative path, spelled as the tree spells it, then ` > `, then the heading text at any level from two, matched case-insensitively. The fill lands in `.agents/skills/` itself, since Codex and opencode read that tree directly and a region left empty there is a skill with a hole in it, and the generated trees mirror the filled source. A source is any regular file under the repository root outside the two generated trees and reached through no symlink, so a key may name a `GOVERNANCE.md` section, an `AGENTS.md` subsection, or a section of a sibling skill, and a region filled from a file carrying regions of its own reads that file's filled text. Regenerating after a source edit changes the bytes of every skill unit including it, and `--check` fails the pull request until that regenerate runs, so the whole-unit review pass `scripts/canonical_review.py` records for each of those units is owed again, which is the cost of a carrier reading generated text in the skill's own context.
- **`--check` holds every region to its source.** It fails when a region differs from what its source renders now, so a hand edit inside one and a source edit nobody regenerated for both fail the pull request the same way a stale mirror does. A region it cannot render is a failure rather than a stale result, exit 2 rather than 1, because regenerating cannot repair it: a key with no ` > ` or an empty heading, a path naming no file, a heading that no longer resolves or that recurs in its source, a body with nothing in it or leaving a code fence open, a region in a file the generator does not walk, reached through a key, since it walks only the Markdown files of the skill directories, a region that opens inside another or never closes, a close marker with no region open, a cycle, a path outside the root, through a symlink, under a generated tree, or spelled otherwise than the tree spells it, a skill file or source that is not UTF-8, and a file holding a region while mixing line endings.
- **`--check` holds every region to its source.** It fails when a region differs from what its source renders now, so a hand edit inside one and a source edit nobody regenerated for both fail the pull request the same way a stale mirror does. A region it cannot render is a failure rather than a stale result, exit 2 rather than 1, because regenerating cannot repair it: a key with no ` > ` or an empty heading, a path naming no file, a heading that no longer resolves or that recurs in its source, a body with nothing in it or leaving a code fence open, a region in a file the generator does not walk, reached through a key, since it walks only the Markdown files of the skill directories, a region that opens inside another or never closes, a close marker with no region open, a cycle, a path outside the root, through a symlink, under a generated tree, or spelled otherwise than the tree spells it, a skill file or source that is not UTF-8, a file holding a region while mixing line endings, and a line outside a code block that begins like a marker and matches neither form, which read as content would leave a region unfilled.
- **`scripts/skills_install.py`, run from a hub checkout, installs both forms per machine**: an overlay copy into `~/.agents/skills/` for Codex and opencode, marked per skill so a retired skill is removed on the next run and a foreign skill is never touched, and a user-scope plugin install for Claude Code via the `claude` CLI. Each run stamps the hub commit into `~/.agents/skills-install-stamp.json`, and `--report` reads that stamp against the checkout and exits non-zero when the machine is behind. The install is global per user, and per-repo pinning is a settled non-goal (`docs/fleet-map.md` "Skills Install Model").

## Deciding a Topic Deserves a Skill
Expand Down Expand Up @@ -46,7 +46,7 @@ A skill surfaces at a trigger moment. A rule that binds every action all the tim
Packaging keeps one topic in one authoritative place while the skill makes it surface automatically. It has three shapes, and each pairing states which it uses:

- **Moved content.** The law-doc section keeps a summary and the skill holds the full rules (`git-commit-conventions`, `comment-and-doc-style`, `pr-review-conduct`). The section ends with the standard pointer sentence: packaged as the named skill at `.agents/skills/<name>/SKILL.md` in the hub, not a repo-relative link since that path is hub-local and not carried into every fleet repo, read the skill for the full rules.
- **Kept authority.** The source doc keeps the full rules and the skill is the summary that routes to them (`audit-a-repo` over `AUDIT.md`, `workflow-ci-contract` over `WORKFLOW.md`, `agent-conduct` over its GOVERNANCE sections). The skill states per topic which doc section owns it.
- **Included content.** The doc keeps the full rules and the skill needs them whole to work in isolation, so it carries the section as a generated include rather than as a summary or a copy, declared with the region markers "The Pipeline" above describes and keyed on the doc's section. The doc side states the shape with one sentence naming the skill that includes the section, and the skill side is the region itself. The doc wins by construction, since `scripts/build_dist.py` writes the region from it and its `--check` reports a region that differs from it as stale.
- **Kept authority.** The source doc keeps the full rules and the skill is the summary that routes to them (`audit-a-repo` over `AUDIT.md`, `workflow-ci-contract` over `WORKFLOW.md`). The skill states per topic which doc section owns it.
- **Included content.** The doc keeps the full rules and the skill needs them whole to work in isolation, so it carries the section as a generated include rather than as a summary or a copy, declared with the region markers "The Pipeline" above describes and keyed on the doc's section (`agent-conduct` over the three `GOVERNANCE.md` sections it surfaces). The doc side states the shape with one sentence naming the skill that includes the section, and the skill side is the region itself. A section carried this way is read outside its own document, so it names a sibling section by document and heading rather than as above or below, and it links to no file by a relative path, since the path would resolve against the skill's directory rather than the doc's. The doc wins by construction, since `scripts/build_dist.py` writes the region from it and its `--check` reports a region that differs from it as stale.

In every shape the doc is the authority when the two are found to disagree, the moved-content shape included: the doc's summary says what the rule is, and the skill's full text is what gets corrected. A deliberate change to a packaged rule is not such a disagreement. It lands where the full text lives, and in the same change the author either edits the other side's summary to match, since a summary has no mechanical check, or regenerates the include, which has one. A rule stated fully in both places by hand is the drift this pattern exists to prevent, and an include is the one full second statement that cannot drift undetected.
2 changes: 1 addition & 1 deletion .claude-plugin/fleet-skills/.source-digests/agent-conduct
Original file line number Diff line number Diff line change
@@ -1 +1 @@
c159c9d53085e97d
f9c1bff5e71e2fe0
Original file line number Diff line number Diff line change
@@ -1 +1 @@
00f2d268c69166fd
2f7679713ee7c760
Loading