Upstream skill tracker
Vendor and follow upstream skill repositories with a clear baseline,
local edits, a review queue for new commits, and durable per-commit
decisions. Use this skill whenever the task involves bringing skill
content from another repo into skills/<category>/<name>/ — or keeping
already-vendored content in sync.
This is a meta-skill. Its body documents the workflow; its scripts are
deterministic helpers; its references hold long-form documentation
(manifest schema, frontmatter shape, pilot example).
When to invoke
Match the request to one of four operations:
| Request shape |
Operation |
"Import / vendor / pull in skill X from <repo>" |
§1 Adopt a new upstream |
| "I'm editing this imported skill" |
§2 Local modifications |
| "What's changed upstream?" / "Any new upstream commits?" |
§3 Monitor for new commits |
"Review upstream commit <sha>" / "Backport <sha>" |
§4 Review a single commit |
If the user is registering a brand-new local skill not from any upstream,
this is not the right skill — point at .claude/skills/skill-creator-lang
instead.
Tool detection
for tool in git python3 jq; do
command -v "$tool" >/dev/null && echo "ok: $tool" || echo "MISSING: $tool"
done
jq is optional (only used to format JSON output). git and python3
are required.
State files
This skill operates on three repo-root paths. None of them ships
populated; they are created when the user adopts the first upstream.
upstream/sources.yaml — manifest. Authoritative for source state.
See references/manifest-schema.md for the field reference.
upstream/decisions/<id>.log — append-only TSV. One row per reviewed
upstream commit. Format: <sha>\t<decision>\t<iso-date>\t<note>,
where decision ∈ {accept, skip, defer, cherry-picked:<local-sha>}.
.cache/upstream/<id>.git — bare partial clone (--filter=blob:none).
Gitignored. Recreated on demand by scripts/fetch.py.
The per-skill metadata.upstream-* block in vendored SKILL.md files
is advisory (self-describing attribution). The manifest is the source
of truth for tooling. See references/frontmatter-block.md.
§1 — Adopt a new upstream
Use when the user wants to vendor one or more skills from a not-yet-tracked
repo, or to add more skills from an already-tracked repo.
Procedure:
Confirm the source. Get the user to provide:
- upstream URL (e.g.
https://github.com/grafana/skills)
- branch (default
main)
- subpath inside the repo where skills live (e.g.
skills/)
- the upstream-relative paths of each skill to import
- the destination
category: + name: (and which target-plugin
should expose it)
- the upstream's license (so it can be recorded; not validated)
Pick or confirm the source id. Lowercase, hyphenated, unique
within the manifest. Often <org>-<repo> (e.g. grafana-skills).
Edit upstream/sources.yaml. Add a new sources[] entry per
references/manifest-schema.md. Each skills[] entry needs
upstream:, category:, name:, target-plugin:, and
(optionally) merge-strategy:. Set upstream-rev, reviewed-rev,
last-fetched to empty strings — the import script fills them.
Ensure the target plugin exists. If target-plugin: names a
plugin not yet under plugins/, create the directory first with
.claude-plugin/plugin.json and an empty skills/ directory, and add it
to .claude-plugin/marketplace.json.
Run the import:
python3 .claude/skills/upstream-tracker/scripts/import.py <id>
The script:
- Ensures the bare partial clone under
.cache/upstream/<id>.git.
- Resolves the upstream HEAD sha for
branch.
- For each
skills[] mapping, applies the entry's merge-strategy:
(standalone → copy to skills/<category>/<name>/;
umbrella-references → drop body into
skills/<category>/<umbrella>/references/<topic>.md).
- Injects
metadata.upstream-id / upstream-rev / upstream-path / upstream-imported into each imported SKILL.md.
- For
standalone entries: creates the
plugins/<target-plugin>/skills/<name> symlink and adds
./skills/<name> to that plugin's .claude-plugin/plugin.json
skills array (idempotent).
- Sets manifest
upstream-rev and reviewed-rev to the resolved sha.
- Appends an
accept row to upstream/decisions/<id>.log for the
resolved sha.
- Refuses to overwrite an existing local skill under
standalone
without --force; merge-strategy: replace overwrites silently.
- Re-runs
scripts/validate.py afterwards.
Verify. From the repo root:
just check
Investigate any failures before committing.
Commit the manifest entry, the decision log line, the imported
skill directories, the symlinks, and the plugin.json update
together. One commit per adoption keeps git log readable.
§2 — Local modifications
Use when editing an already-vendored skill.
Rules:
Edit freely. Treat the imported SKILL.md as repo-owned content;
refactor, reword, fix bugs.
Do not touch metadata.upstream-rev. It records the upstream sha
the file was vendored from — the baseline, not the current state.
Local edits drift from this baseline by design; that's the whole
point. The validator only flags drift if the manifest has reviewed
past the baseline.
Do not touch the decision log. Local edits are recorded in
git log -- skills/<path>/, which already gives full provenance.
If the local edit is a backport from an upstream commit not yet
reviewed, switch to §4 first — drive the change through the review
loop so the cursor advances.
§3 — Monitor for new commits
Use when the user wants to see what has changed upstream since the last
review (e.g. "what's pending", "any new commits to backport").
Procedure:
Run the fetch helper:
python3 .claude/skills/upstream-tracker/scripts/fetch.py
For each source in the manifest, this script:
- Ensures the bare partial clone under
.cache/upstream/<id>.git.
- Runs
git fetch origin <branch>.
- Computes commits in
reviewed-rev..origin/<branch> whose
--name-only output intersects the source's subpath.
- Updates the manifest's
upstream-rev (HEAD now seen) and
last-fetched. Does not touch reviewed-rev.
- Prints a Markdown report grouped by source.
Read the report. Per-source sections list pending commits with
sha · author · date · subject · paths-touched-within-subpath. An
empty section is the steady state (no review needed).
Decide what to review. Tell the user what's pending and ask which
commits (if any) to review now. Default to oldest-first to keep
reviewed-rev advancing monotonically.
The fetch script is idempotent: re-running shows the same pending list
until commits are decided in §4.
§4 — Review a single commit
Use when the user names a specific upstream commit, or when §3 surfaced
a pending list and the user wants to walk through it.
Procedure:
Run the review helper:
python3 .claude/skills/upstream-tracker/scripts/review.py <id> [--sha <sha>]
With no --sha, it walks the pending list oldest-first. With
--sha, it operates on just that commit.
For each commit, the script prints:
- Commit metadata (author, date, subject, body).
git show <sha> -- <subpath> — the diff restricted to the source's
subpath so cross-cutting upstream changes don't drown the signal.
- The current
reviewed-rev and the cursor position.
Choose a decision:
Cursor advance rule. After every decision write, the script
walks the decision log forward from the current reviewed-rev and
advances through contiguous rows whose decision is one of
accept, skip, or finalized cherry-picked:<sha>. A defer row
blocks advance — fix it (re-review with a different decision) or
live with the cursor stalled until the user resumes.
Bump per-skill metadata when needed. Cherry-picking new content
into a vendored skill should also bump that skill's
metadata.upstream-rev to the picked sha (the script offers to do
this when the cherry-pick is confirmed). For accept / skip the
per-skill metadata stays at its baseline — those decisions don't
change local content.
Common operations
"Adopt grafana-skills as the pilot"
See references/pilot-grafana-skills.md for the worked example.
"Retire a source"
Remove the sources[] entry from upstream/sources.yaml. The decision
log under upstream/decisions/<id>.log stays as historical record.
.cache/upstream/<id>.git is local-only and can be deleted at will.
Imported skills remain in skills/; their metadata.upstream-id will
trigger advisory warnings from validate.py --strict-upstream, which
is the intended signal that the source is no longer tracked.
"Multiple upstreams ship the same skill name"
The manifest local paths must be unique across all sources — that's
the only enforcement. Pick distinct local names if the upstreams collide.
Footguns
- Don't
git fetch upstream from outside the helper. The script
uses a bare partial clone; manual fetches into the user's main
worktree pollute it.
- Don't edit
metadata.upstream-rev manually after import. It's
the baseline pointer; tooling assumes it matches a real upstream sha.
- Don't
--force import unless the local skill was originally vendored
from the same source and you want to overwrite local edits. Use the
cherry-pick flow (§4) for incremental upstream changes.
defer is sticky. A deferred commit blocks the cursor until
re-decided — that's the design, not a bug. If many commits pile up
behind a defer, re-review the defer first.
References
references/manifest-schema.md — upstream/sources.yaml field reference.
references/frontmatter-block.md — metadata.upstream-* shape and
validator behaviour.
references/pilot-grafana-skills.md — worked example: vendoring
github:grafana/skills.
1---2name: upstream-tracker3description: Track external upstream skill repositories: import a skill from upstream into this catalogue, modify it locally without losing the baseline, monitor the upstream for new commits since the last review, and review each upstream commit one-by-one to accept, skip, defer, or cherry-pick it into the local copy. Use when the user says "import skill from <repo>", "vendor <repo>", "monitor upstream for new commits", "what's changed upstream", "check upstream for updates", "review upstream commit", "backport <sha>", or "follow <repo> for new skills". Operates on `upstream/sources.yaml` (manifest), `upstream/decisions/<id>.log` (per-source review cursor), and `.cache/upstream/<id>.git` (local bare partial clone). Helper scripts under this skill's `scripts/` do the deterministic git work; the agent following this SKILL.md drives the decisions.4---56# Upstream skill tracker78Vendor and follow upstream skill repositories with a clear baseline,9local edits, a review queue for new commits, and durable per-commit10decisions. Use this skill whenever the task involves bringing skill11content from another repo into `skills/<category>/<name>/` — or keeping12already-vendored content in sync.1314This is a meta-skill. Its body documents the workflow; its scripts are15deterministic helpers; its references hold long-form documentation16(manifest schema, frontmatter shape, pilot example).1718## When to invoke1920Match the request to one of four operations:2122| Request shape | Operation |23|---|---|24| "Import / vendor / pull in skill X from `<repo>`" | §1 Adopt a new upstream |25| "I'm editing this imported skill" | §2 Local modifications |26| "What's changed upstream?" / "Any new upstream commits?" | §3 Monitor for new commits |27| "Review upstream commit `<sha>`" / "Backport `<sha>`" | §4 Review a single commit |2829If the user is registering a brand-new local skill not from any upstream,30this is **not** the right skill — point at `.claude/skills/skill-creator-lang`31instead.3233## Tool detection3435```bash36for tool in git python3 jq; do37 command -v "$tool" >/dev/null && echo "ok: $tool" || echo "MISSING: $tool"38done39```4041`jq` is optional (only used to format JSON output). `git` and `python3`42are required.4344## State files4546This skill operates on three repo-root paths. None of them ships47populated; they are created when the user adopts the first upstream.4849- `upstream/sources.yaml` — manifest. Authoritative for source state.50 See `references/manifest-schema.md` for the field reference.51- `upstream/decisions/<id>.log` — append-only TSV. One row per reviewed52 upstream commit. Format: `<sha>\t<decision>\t<iso-date>\t<note>`,53 where `decision ∈ {accept, skip, defer, cherry-picked:<local-sha>}`.54- `.cache/upstream/<id>.git` — bare partial clone (`--filter=blob:none`).55 Gitignored. Recreated on demand by `scripts/fetch.py`.5657The per-skill `metadata.upstream-*` block in vendored `SKILL.md` files58is **advisory** (self-describing attribution). The manifest is the source59of truth for tooling. See `references/frontmatter-block.md`.6061## §1 — Adopt a new upstream6263Use when the user wants to vendor one or more skills from a not-yet-tracked64repo, or to add more skills from an already-tracked repo.6566Procedure:67681. **Confirm the source.** Get the user to provide:69 - upstream URL (e.g. `https://github.com/grafana/skills`)70 - branch (default `main`)71 - subpath inside the repo where skills live (e.g. `skills/`)72 - the upstream-relative paths of each skill to import73 - the destination `category:` + `name:` (and which `target-plugin`74 should expose it)75 - the upstream's license (so it can be recorded; not validated)76772. **Pick or confirm the source `id`.** Lowercase, hyphenated, unique78 within the manifest. Often `<org>-<repo>` (e.g. `grafana-skills`).79803. **Edit `upstream/sources.yaml`.** Add a new `sources[]` entry per81 `references/manifest-schema.md`. Each `skills[]` entry needs82 `upstream:`, `category:`, `name:`, `target-plugin:`, and83 (optionally) `merge-strategy:`. Set `upstream-rev`, `reviewed-rev`,84 `last-fetched` to empty strings — the import script fills them.85864. **Ensure the target plugin exists.** If `target-plugin:` names a87 plugin not yet under `plugins/`, create the directory first with88 `.claude-plugin/plugin.json` and an empty `skills/` directory, and add it89 to `.claude-plugin/marketplace.json`.90915. **Run the import:**92 ```bash93 python3 .claude/skills/upstream-tracker/scripts/import.py <id>94 ```95 The script:96 - Ensures the bare partial clone under `.cache/upstream/<id>.git`.97 - Resolves the upstream HEAD sha for `branch`.98 - For each `skills[]` mapping, applies the entry's `merge-strategy:`99 (`standalone` → copy to `skills/<category>/<name>/`;100 `umbrella-references` → drop body into101 `skills/<category>/<umbrella>/references/<topic>.md`).102 - Injects `metadata.upstream-id / upstream-rev / upstream-path /103 upstream-imported` into each imported `SKILL.md`.104 - For `standalone` entries: creates the105 `plugins/<target-plugin>/skills/<name>` symlink **and** adds106 `./skills/<name>` to that plugin's `.claude-plugin/plugin.json`107 `skills` array (idempotent).108 - Sets manifest `upstream-rev` and `reviewed-rev` to the resolved sha.109 - Appends an `accept` row to `upstream/decisions/<id>.log` for the110 resolved sha.111 - Refuses to overwrite an existing local skill under `standalone`112 without `--force`; `merge-strategy: replace` overwrites silently.113 - Re-runs `scripts/validate.py` afterwards.1141156. **Verify.** From the repo root:116 ```bash117 just check118 ```119 Investigate any failures before committing.1201217. **Commit** the manifest entry, the decision log line, the imported122 skill directories, the symlinks, and the plugin.json update123 together. One commit per adoption keeps `git log` readable.124125## §2 — Local modifications126127Use when editing an already-vendored skill.128129Rules:1301311. **Edit freely.** Treat the imported `SKILL.md` as repo-owned content;132 refactor, reword, fix bugs.1331342. **Do not touch `metadata.upstream-rev`.** It records the upstream sha135 the file was vendored from — the **baseline**, not the current state.136 Local edits drift from this baseline by design; that's the whole137 point. The validator only flags drift if the manifest has reviewed138 *past* the baseline.1391403. **Do not touch the decision log.** Local edits are recorded in141 `git log -- skills/<path>/`, which already gives full provenance.1421434. **If the local edit is a backport from an upstream commit not yet144 reviewed**, switch to §4 first — drive the change through the review145 loop so the cursor advances.146147## §3 — Monitor for new commits148149Use when the user wants to see what has changed upstream since the last150review (e.g. "what's pending", "any new commits to backport").151152Procedure:1531541. **Run the fetch helper:**155 ```bash156 python3 .claude/skills/upstream-tracker/scripts/fetch.py157 ```158 For each source in the manifest, this script:159 - Ensures the bare partial clone under `.cache/upstream/<id>.git`.160 - Runs `git fetch origin <branch>`.161 - Computes commits in `reviewed-rev..origin/<branch>` whose162 `--name-only` output intersects the source's `subpath`.163 - Updates the manifest's `upstream-rev` (HEAD now seen) and164 `last-fetched`. Does **not** touch `reviewed-rev`.165 - Prints a Markdown report grouped by source.1661672. **Read the report.** Per-source sections list pending commits with168 `sha · author · date · subject · paths-touched-within-subpath`. An169 empty section is the steady state (no review needed).1701713. **Decide what to review.** Tell the user what's pending and ask which172 commits (if any) to review now. Default to oldest-first to keep173 `reviewed-rev` advancing monotonically.174175The fetch script is idempotent: re-running shows the same pending list176until commits are decided in §4.177178## §4 — Review a single commit179180Use when the user names a specific upstream commit, or when §3 surfaced181a pending list and the user wants to walk through it.182183Procedure:1841851. **Run the review helper:**186 ```bash187 python3 .claude/skills/upstream-tracker/scripts/review.py <id> [--sha <sha>]188 ```189 With no `--sha`, it walks the pending list oldest-first. With190 `--sha`, it operates on just that commit.1911922. **For each commit, the script prints:**193 - Commit metadata (author, date, subject, body).194 - `git show <sha> -- <subpath>` — the diff restricted to the source's195 `subpath` so cross-cutting upstream changes don't drown the signal.196 - The current `reviewed-rev` and the cursor position.1971983. **Choose a decision:**199 - **`accept`** — the commit's effect is already absorbed (or trivial).200 Append `accept` to the decision log; advance the cursor.201 - **`skip`** — the commit doesn't apply to this fork (e.g. upstream202 scaffolding, removed tests we don't carry). Append `skip`; advance203 the cursor.204 - **`defer`** — needs more thought; not deciding now. Append `defer`;205 **do not** advance the cursor. The commit will reappear in §3.206 - **`cherry-pick`** — the change should land locally. The script207 extracts the patch with `git -C cache show <sha> -- <subpath>` and208 applies it to the working tree via `git apply -p<n>209 --directory=skills/<local>/`. The user reviews the working-tree210 diff, edits as needed, and commits separately. The decision log211 records `cherry-picked:<pending>`; once the user runs:212 ```bash213 python3 .claude/skills/upstream-tracker/scripts/review.py <id> \214 --confirm <upstream-sha> <local-sha>215 ```216 the row is finalized to `cherry-picked:<local-sha>` and the217 cursor advances.2182194. **Cursor advance rule.** After every decision write, the script220 walks the decision log forward from the current `reviewed-rev` and221 advances through **contiguous** rows whose decision is one of222 `accept`, `skip`, or finalized `cherry-picked:<sha>`. A `defer` row223 blocks advance — fix it (re-review with a different decision) or224 live with the cursor stalled until the user resumes.2252265. **Bump per-skill metadata when needed.** Cherry-picking new content227 into a vendored skill should also bump that skill's228 `metadata.upstream-rev` to the picked sha (the script offers to do229 this when the cherry-pick is confirmed). For `accept` / `skip` the230 per-skill metadata stays at its baseline — those decisions don't231 change local content.232233## Common operations234235### "Adopt grafana-skills as the pilot"236237See `references/pilot-grafana-skills.md` for the worked example.238239### "Retire a source"240241Remove the `sources[]` entry from `upstream/sources.yaml`. The decision242log under `upstream/decisions/<id>.log` stays as historical record.243`.cache/upstream/<id>.git` is local-only and can be deleted at will.244Imported skills remain in `skills/`; their `metadata.upstream-id` will245trigger advisory warnings from `validate.py --strict-upstream`, which246is the intended signal that the source is no longer tracked.247248### "Multiple upstreams ship the same skill name"249250The manifest `local` paths must be unique across all sources — that's251the only enforcement. Pick distinct local names if the upstreams collide.252253## Footguns254255- **Don't `git fetch` upstream from outside the helper.** The script256 uses a bare partial clone; manual fetches into the user's main257 worktree pollute it.258- **Don't edit `metadata.upstream-rev` manually after import.** It's259 the baseline pointer; tooling assumes it matches a real upstream sha.260- **Don't `--force` import unless the local skill was originally vendored261 from the same source and you want to overwrite local edits.** Use the262 cherry-pick flow (§4) for incremental upstream changes.263- **`defer` is sticky.** A deferred commit blocks the cursor until264 re-decided — that's the design, not a bug. If many commits pile up265 behind a defer, re-review the defer first.266267## References268269- `references/manifest-schema.md` — `upstream/sources.yaml` field reference.270- `references/frontmatter-block.md` — `metadata.upstream-*` shape and271 validator behaviour.272- `references/pilot-grafana-skills.md` — worked example: vendoring273 `github:grafana/skills`.