Goal
Build a firstmate skill for vendoring agent skills that can absorb upstream updates while keeping local deviations in check. It is a port of the captain's prior art in Quidge/ltf4 plus one additive audit subcommand — no new architecture. Design settled in a captain-driven design session (2026-08-05).
Prior art (port from)
Quidge/ltf4 : .agents/skills/rebasing-adapted-skill/SKILL.md
Quidge/ltf4 : scripts/skill-adaptation.py (a uv run self-contained script, dep pyyaml)
Fetch reliably with gh-axi api repos/Quidge/ltf4/contents/<path> --header "Accept: application/vnd.github.raw" (the default YAML wrapper truncates large base64 bodies).
The model
- Provenance file
ADAPTATION.md sits in the skill root, sibling to SKILL.md. Provenance lives only there, never in SKILL.md.
- Pins =
ADAPTATION.md YAML frontmatter attributions: — a list of GitHub tree URLs pinned to full 40-char commit SHAs + path (https://github.com/<owner>/<repo>/tree/<40-hex-sha>/<path>). Immutable; no branch/tag refs. A skill may pin multiple attributions.
- Deviation ledger = the
## Deviations body section — natural-language bullets of intentional differences from upstream, read as merge policy (keep what a bullet protects; otherwise silence = match upstream). Not a changelog.
- The script is deliberately dumb; the agent does the semantic 3-way merge (base = pinned SHA, ours = current, theirs = chosen new SHA), reading
## Deviations as policy, showing a plan and waiting for approval before writing, then advancing pins and refreshing the ledger only on intent change. Never take ADAPTATION.md from upstream.
Settled decisions
| # |
Question |
Decision |
| Q1 |
Scope |
Rebase-only (initial import stays a manual one-liner via template). |
| Q2 |
Keep deviations honest |
audit mode — read-only check of ours − base vs the declared ## Deviations, flagging undeclared drift and stale bullets. |
| Q3 |
Script vs agent boundary |
Dumb script (scaffold + validate + the deterministic audit diff); agent does the merge and finalizes NL bullet↔delta correlation. |
| Q4 |
Pin format |
GitHub tree URL with full SHA (human-clickable, one string). |
| Q5 |
Provenance marker |
Presence of ADAPTATION.md — no SKILL.md frontmatter stamping. |
Build
Two artifacts, mirroring ltf4 with one addition and one layout change.
Script — skill-adaptation.py
- Keep existing
template <tree-url>... (stdout ADAPTATION.md stub) and validate-skill-dir <dir> [-q] (structural validity, no network).
- Add
audit <skill-dir> [-q] — read-only. Per attribution: resolve the pinned base tree, fetch base files at that SHA (deterministic), compute ours − base per path, and emit two lists: undeclared drift (real differences with no covering bullet) and stale bullets (bullets mapping to no current difference). Exit non-zero if either list is non-empty (composes as a gate); -q quiet predicate.
- Script location (captain, this build): the script lives inside the skill dir at
<skill-dir>/scripts/<script>.py — self-contained so it travels with the vendored skill — not a repo-level scripts/. (Deliberate change from ltf4's layout for vendorability.)
Skill — rebasing-adapted-skill
- Port the ltf4 process, with audit as the first rebase step: run
audit, surface undeclared drift + stale bullets, get them reconciled before planning the merge, so the 3-way merge starts from an honest ledger and can't silently clobber undeclared local work.
- Standalone audit entry too — "is my vendored skill still honest?" without a rebase.
- Everything else stands: multi-attribution, tree-URL pins with full SHAs,
## Deviations as policy, agent-driven merge, advance pins + refresh ledger only on intent change.
The two rot modes audit catches
- Undeclared drift — a local change made without a covering bullet; on the next rebase "silence = match upstream" silently reverts it. Audit: "differs from base but no
## Deviations bullet covers it — declare or drop."
- Stale bullet — upstream later adopts the same change; the bullet now describes a difference that no longer exists. Audit: "bullet maps to no actual difference — retire it."
Open refinement (confirm at build intake)
Whether audit correlates bullets↔deltas heuristically or simply presents both sides for the agent to correlate. Report's recommendation: present both sides, agent correlates (simplest, honest about NL ambiguity); add heuristic matching later only if worth it. The deterministic diff stays in the script.
Delivery
Firstmate shared-tracked skill → .agents/skills/ in this repo. Must load firstmate-coding-guidelines and ship through the repo's normal no-mistakes → PR path. Note the firstmate provenance parallel: firstmate's own skills carry metadata.internal: true; a vendored external skill omits it. ADAPTATION.md presence (Q5) is a compatible, orthogonal "upstream-tracked" signal — this skill, if itself vendored in, would carry ADAPTATION.md and omit internal: true.
Goal
Build a firstmate skill for vendoring agent skills that can absorb upstream updates while keeping local deviations in check. It is a port of the captain's prior art in
Quidge/ltf4plus one additiveauditsubcommand — no new architecture. Design settled in a captain-driven design session (2026-08-05).Prior art (port from)
Quidge/ltf4:.agents/skills/rebasing-adapted-skill/SKILL.mdQuidge/ltf4:scripts/skill-adaptation.py(auv runself-contained script, deppyyaml)Fetch reliably with
gh-axi api repos/Quidge/ltf4/contents/<path> --header "Accept: application/vnd.github.raw"(the default YAML wrapper truncates large base64 bodies).The model
ADAPTATION.mdsits in the skill root, sibling toSKILL.md. Provenance lives only there, never inSKILL.md.ADAPTATION.mdYAML frontmatterattributions:— a list of GitHub tree URLs pinned to full 40-char commit SHAs + path (https://github.com/<owner>/<repo>/tree/<40-hex-sha>/<path>). Immutable; no branch/tag refs. A skill may pin multiple attributions.## Deviationsbody section — natural-language bullets of intentional differences from upstream, read as merge policy (keep what a bullet protects; otherwise silence = match upstream). Not a changelog.## Deviationsas policy, showing a plan and waiting for approval before writing, then advancing pins and refreshing the ledger only on intent change. Never takeADAPTATION.mdfrom upstream.Settled decisions
template).auditmode — read-only check ofours − basevs the declared## Deviations, flagging undeclared drift and stale bullets.ADAPTATION.md— noSKILL.mdfrontmatter stamping.Build
Two artifacts, mirroring ltf4 with one addition and one layout change.
Script —
skill-adaptation.pytemplate <tree-url>...(stdoutADAPTATION.mdstub) andvalidate-skill-dir <dir> [-q](structural validity, no network).audit <skill-dir> [-q]— read-only. Per attribution: resolve the pinned base tree, fetch base files at that SHA (deterministic), computeours − baseper path, and emit two lists: undeclared drift (real differences with no covering bullet) and stale bullets (bullets mapping to no current difference). Exit non-zero if either list is non-empty (composes as a gate);-qquiet predicate.<skill-dir>/scripts/<script>.py— self-contained so it travels with the vendored skill — not a repo-levelscripts/. (Deliberate change from ltf4's layout for vendorability.)Skill —
rebasing-adapted-skillaudit, surface undeclared drift + stale bullets, get them reconciled before planning the merge, so the 3-way merge starts from an honest ledger and can't silently clobber undeclared local work.## Deviationsas policy, agent-driven merge, advance pins + refresh ledger only on intent change.The two rot modes audit catches
## Deviationsbullet covers it — declare or drop."Open refinement (confirm at build intake)
Whether
auditcorrelates bullets↔deltas heuristically or simply presents both sides for the agent to correlate. Report's recommendation: present both sides, agent correlates (simplest, honest about NL ambiguity); add heuristic matching later only if worth it. The deterministic diff stays in the script.Delivery
Firstmate shared-tracked skill →
.agents/skills/in this repo. Must loadfirstmate-coding-guidelinesand ship through the repo's normal no-mistakes → PR path. Note the firstmate provenance parallel: firstmate's own skills carrymetadata.internal: true; a vendored external skill omits it.ADAPTATION.mdpresence (Q5) is a compatible, orthogonal "upstream-tracked" signal — this skill, if itself vendored in, would carryADAPTATION.mdand omitinternal: true.