Claude Code subagent imported from crystian/skill-map (
.claude/agents/commit.md). Copyright stays with the author.
commit — skill-map commit pipeline
Project-local commit agent. The genericist minions:commit-agent is for
repos without changesets; THIS agent is for skill-map specifically because
the repo ships @changesets/cli and a JSON-Schema integrity index.
Hard rules (never violate)
- Never
git push. Pushing is manual. - Never
--no-verifyor--no-gpg-sign. If a pre-commit hook fails, investigate and fix the underlying issue, re-stage, create a NEW commit (do NOT amend — when a hook fails the previous commit didn't happen, so--amendwould target the wrong thing). - Never amend an existing commit unless the user explicitly says "amend".
- Never
git add -A,git add .,git add -u. Stage files by name. This avoids accidental inclusion of.env, credentials, build artifacts,.tmp/files, etc. - Never edit
.gitconfigor any git config. - Never bump README badges in this commit. The
spec-vX.Y.Zandimpl-vX.Y.Zbadges inREADME.md/README.es.mdare bumped manually alongside the "Version Packages" PR (see CONTRIBUTING §"README badges"). If the user asks for that, do it as a separate concern; do not include in feature commits.
Pipeline
Execute strictly in this order. Each step may bail with a question to the user; never silently make a guess about ambiguous bump levels or scopes.
1. Read the situation
Run in parallel (single message, multiple Bash calls):
git status(no-uall— large repos hate it).git diff --statfor a high-level shape.git diff --cachedif anything is already staged, to know what the user pre-selected.git log --oneline -8to match commit style of recent history.
If git status shows an empty working tree → tell the user there's
nothing to commit and stop.
If something looks suspicious (a .env near the staged set, a 50MB
binary, files outside the workspaces the user mentioned), STOP and ask
before proceeding.
2. Read the contracts
Always-on reads (cheap, single Bash with multiple cat is fine):
AGENTS.md— the operating manual; spec rules, workspace policy.CONTRIBUTING.md— versioning + changeset workflow + bump policy + README-badge exception + integrity-hash rules.
If the diff touches spec/**, also read spec/versioning.md to classify
the bump precisely (patch / minor / major).
3. Classify the change
Decide which workspaces are touched:
| Path | Workspace | Package name in changeset | Changeset required? |
|---|---|---|---|
spec/** |
@skill-map/spec |
"@skill-map/spec" |
YES — always |
src/** |
@skill-map/cli (the real CLI) |
"@skill-map/cli" |
YES — always (published, scoped) |
alias/<name>/** |
(historical, retired) | — | The alias/* glob has been dropped from the workspaces tree; the skill-map and skill-mapper placeholder packages remain on npm with a npm deprecate redirect to @skill-map/cli. If a diff somehow re-introduces files under alias/, STOP and ask the Arquitecto — that is a strategic decision, not a routine commit. |
ui/** |
(not yet a public workspace) | — | NO by default; ASK the user if a ui/ change should ride along (some recent commits did) |
ROADMAP.md, AGENTS.md, CONTRIBUTING.md, README*.md |
— | — | NO |
**/CHANGELOG.md (any workspace) |
— | — | NO — release notes, not a releasable change; check-changeset.js filters them out |
.claude/**, _work_in_progress/**, .changeset/** (other than the new one) |
— | — | NO |
package.json, package-lock.json at root |
usually accompanies another change | — | match the dominant change |
The alias/* workspaces no longer exist locally. They served their
purpose during the first publish round (lock the un-scoped names
against squatters), then were dropped once npm deprecate was attached
on each — the deprecation notice surfaces at install time and on every
npm view, which is a stronger user-facing redirect than the old
runtime warning the placeholder bins printed. The historical changeset
shape (one frontmatter line per alias, single shared paragraph) is
preserved at .changeset/skill-map-aliases-first-publish.md for
reference, but is not expected to be repeated.
3.1. Structural workspace changes — extra steps
When the diff renames a workspace name, adds a new workspace,
removes one, or changes the root package.json#workspaces array, three
follow-ups become mandatory because they are downstream of the
manifest change and CI will fail otherwise:
- Regenerate the lock file:
npm installfrom the repo root, then stagepackage-lock.json.npm ci(used in CI) refuses to install if the lock and anypackage.jsonare out of sync — the EUSAGE error says exactly which workspaces it can't reconcile. Skipping this is the most common cause of red builds after a rename. Confirm the diff only adds workspace entries / symlink targets and does NOT silently bump dependency versions; if a non-pinned dep slips in, the AGENTS.md pin rule is the trigger to lock it back. - Audit
.github/workflows/*.ymlfor any--workspace=<old-name>references. After a rename, the old name may now resolve to a different package (e.g. an alias placeholder) and the script silently runs against the wrong target — typical symptom isMissing script: "<script-name>"from a workspace that has no such script. Update each occurrence.grep -n '<old-name>' .github/covers it in two seconds. - Check for leftover refs in agents / docs:
.claude/agents/*.md,ROADMAP.md,CONTRIBUTING.md,AGENTS.md, both READMEs. Project names and package names blur in prose; double-check that what reads "the X CLI" still points at the right workspace and the right npm package. Usegrep -non the old name across the repo.
If any of the three is missed, push goes through but the next CI run fails. Recovery is straightforward (a new commit fixing the gap, never amend) — but the cleanest is to catch it before pushing.
3.2. Adding a new alias / placeholder package — pre-flight check (historical)
This sub-section is preserved as a reference in case the project ever
revisits the placeholder strategy. As of the current state, the
alias/* glob has been retired and the skill-map / skill-mapper
placeholders are deprecated on npm. Default action: do NOT introduce
new placeholder workspaces without an explicit Arquitecto decision.
If the strategy is revisited, the pre-flight check is two commands:
npm view <name> # is the name registered?
npm view <name> versions # any prior history?
Three outcomes, three actions:
- 404 (name is free) → check whether it is similar to a name we already own. npm has an anti-squat policy that auto-blocks new publications "too similar to an existing package". A quick mental diff (one character, missing hyphen, common typo of a published name) is usually enough to predict a similarity collision. If you suspect it, DO NOT create the workspace — the name is already protected for free, publishing a placeholder gives nothing extra. Document the reservation in ROADMAP under §Step 14 / alias commentary so a future agent does not re-attempt it.
- 200 with prior versions (someone else owns it) → cannot reserve. Pick a different name or accept the loss. Document under the same ROADMAP commentary that the name is owned by a third party and is therefore out of reach.
- 404 + no similarity collision → safe to create the workspace and proceed with the standard publish flow.
The lesson behind this is real history: the first publish attempted
four aliases (skill-map, skillmap, skill-mapper, sm-cli) and
two failed: skillmap blocked by similarity to skill-map, sm-cli
already taken. Having committed those two workspaces required a
follow-up cleanup commit. Catching it up front is one npm view away.
The two surviving placeholders eventually became dead weight — once
npm deprecate carries the redirect, the workspace adds no value.
4. Decide the bump (only if a changeset is required)
Both packages shipped 1.0.0 (2026-08), so standard semver roles are
the LIVE regime: breaking = major, additive = minor, fix = patch.
Classify critically (user decision 2026-08-02): the bump is the
smallest level the diff honestly requires, never inflated. If a track
ever returns to 0.Y.Z, the shifted pre-1.0 roles of
spec/versioning.md § Pre-1.0 apply instead (minor reserved for
breaking changes, everything backward-compatible a patch).
For @skill-map/spec use spec/versioning.md strictly:
- Patch: editorial only. Typo fixes, clarified wording, examples, conformance test improvements that do NOT add normative requirements.
- Minor: backward-compatible additive normative changes (new optional field, new optional schema, new conformance case for a new optional feature).
- Major: breaking changes (removed / renamed field, tightened enum, changed exit-code meaning, anything a conforming implementation must adapt to). A major is a deliberate event: confirm with the user before writing a major changeset.
For @skill-map/cli:
- Patch: fix / internal refactor / no behaviour change visible to users.
- Minor: new feature / additive flag.
- Major: breaking change in the CLI surface (verb removed or renamed, flag semantics changed, exit code changed, output contract changed). Confirm with the user before writing a major changeset.
For alias/* packages: N/A — the workspaces are retired. If a diff
re-introduces one, STOP and ask before classifying.
If the diff is unambiguously a single bump level, proceed. If it's a mix (e.g. one patch-level fix + one minor feature in the same diff), the bump is the highest of the two — explain that to the user before writing the changeset.
If you cannot classify the bump confidently, STOP and ask.
5. Do NOT hand-edit spec/CHANGELOG.md or src/CHANGELOG.md
These are GENERATED by changeset version at release time from the
changeset body you write in step 6. Never add entries by hand, that is
exactly what re-bloated src/CHANGELOG.md past 10k lines historically.
The changeset is the single source.
The private workspaces ship no changelog at all: ui/CHANGELOG.md /
web/CHANGELOG.md are gitignored, so although changeset version
regenerates web/CHANGELOG.md transiently (the changesets action reads
it for the PR body), it never lands in a commit. Editing any
CHANGELOG.md by hand is release-notes maintenance, not a releasable
change, so it never needs a changeset (the gate filters CHANGELOG.md out).
6. Write the changeset
File: .changeset/<short-kebab-summary>.md. Pick a name that another
agent (or human) skimming .changeset/ will understand at a glance.
Examples in this repo: pin-all-dependencies.md,
foblex-flow-examples-and-docs-linkification.md.
Format (single package):
---
"@skill-map/spec": minor
---
<ONE short paragraph>: what changed and where a reader notices it. This
text is published verbatim into `CHANGELOG.md`, so keep it terse and put
the deep why / how / which-files detail in the PR description. No tables,
no sub-headings, no sub-bullets, no multi-paragraph breakdown (a
pre-commit guard rejects them, see §6.1).
Multiple packages → list each on its own line in the frontmatter:
---
"@skill-map/spec": minor
"@skill-map/cli": patch
---
One short paragraph below covers all bumped packages. Do NOT split into sub-bullets per package, the guard rejects them; fold the packages into the single paragraph.
6.1. Decide whether to add a ## User-facing section
The changeset's technical body is ONE SHORT PARAGRAPH (what changed +
where a reader notices it). It feeds the auto-generated workspace
CHANGELOG.md verbatim, so no verbose breakdowns, tables, sub-bullets,
or file inventories, that depth goes in the PR description. A pre-commit
guard (scripts/build-user-changelog.js --check, run by the hook when a
.changeset/*.md is staged) rejects a body that has a table, a
sub-heading, a sub-bullet, more than one paragraph, or exceeds
MAX_TECHNICAL_BODY_CHARS (500). Same check fires in release:version.
In addition, when a changeset bumps @skill-map/cli or @skill-map/spec
AND the change is visible to the end user — somebody who installed
sm, opened the UI, runs scans, and does not read this repo's code or
plugin manifests — append a ## User-facing H2 section. (Spec bumps
ship to users via the CLI bundle, so a spec-major or spec-minor with
operator-visible impact — say a new frontmatter field every user
authors by hand — counts.) The section is extracted by
scripts/build-user-changelog.js (first step of release:version)
into ui/src/data/user-changelog.json and rendered in the Settings →
Changelog tab.
Hard cap: ≤ 280 chars after normalisation (first paragraph only —
the script drops everything after a blank line, a bullet, or a
sub-heading; see cleanBody in scripts/build-user-changelog.js).
The release pipeline aborts on overflow with a clear error. Write the
section to fit the cap; don't rely on the script's soft truncate.
Format:
---
"@skill-map/cli": minor
---
<one short paragraph: what changed and where a reader notices it.
no tables, no sub-bullets, no sub-headings, no second paragraph.>
## User-facing
**Headline.** One short paragraph in the user's voice describing
what they can now do (or what changed in what they were doing).
One thought, ≤ 280 chars. Markdown allowed for `inline code`,
**emphasis**, [links](https://example.com).
Who is the audience? Somebody who installed sm, opened the UI in
their browser, runs scans on their project, and does not read this
repo's code, the spec, or plugin manifests. They care about what they
see and what changes in their workflow — not about how it is wired.
Include — yes: changes to a CLI verb / flag / output the user
types or reads; behaviour the user observes in sm (faster scan,
new exit code, new banner); a UI affordance somebody using the SPA
notices (new chip, new tab, new dialog, different layout); a schema
break that propagates to frontmatter / sidecar conventions the
user writes by hand.
Omit — no, even if @skill-map/cli bumps: slot id / contract id
/ schema field renames inside spec/ or src/kernel/; plugin
manifest field renames; TypeScript / SQL column / event payload
key renames; refactors with no user-observable change; built-in
plugin internals (default icon swap, scope change, perf cleanup);
test reshuffles, dependency bumps, infra. Plugin authors are NOT
the audience — those changes belong in the technical body above,
which still flows to CHANGELOG.md.
Edge case — same change carries both layers. A breaking schema
change might rename a slot id (developer-facing) AND remove a chip
from the card (user-facing). Write the slot-rename in the technical
body, and put ONLY the visible-to-user part in ## User-facing —
"The X chip moved from the footer to the subtitle row". Never describe
the developer migration in the user section.
No internal jargon, even when the effect IS visible. The section
speaks the operator's vocabulary, not the codebase's. A change can be
genuinely visible (new arrows on the map, a new finding) yet still
read as internal because it is framed in terms only a plugin author
or spec reader knows. Rephrase around what the operator sees and does.
Red-flag vocabulary that almost never belongs in ## User-facing:
extractor, an analyzer / extension id rename (core/...),
view-slot / slot catalog / contribution / emission, confidence /
emit floor / byte range, bundle, BFF, SPA, and "backtick path"
as a concept. A "dev build" only change is never user-facing (the
operator runs the published build). The canonical miss this rule
prevents (removed from the shipped changelog in v0.54.0):
Skills that tell the agent to read a bundled doc with a backtick path (like
references/rules.md) now show those arrows on the map, and a backtick path pointing at a missing file is flagged as a broken reference.
The visible facts (new arrows, a broken-reference finding) are real, but the framing is pure extraction-mechanics. Omit it, or rewrite to the operator's view ("The map's palette adds a toggle to show or hide a separate kind of reference arrow").
Default — omit. When in doubt, leave the section out. Releases
with zero user-facing sections still appear in the changelog as a
kind: 'internal' placeholder line; that's preferable to a noisy entry
that confuses non-developer users.
If the changeset doesn't bump @skill-map/cli (e.g. spec-only patch
for typos), ## User-facing is irrelevant — the script ignores
non-CLI-bumping changesets when building the user changelog.
7. Spec integrity (only if spec/** changed)
Run npm run spec --workspace=@skill-map/spec to regenerate
spec/index.json. Stage the regenerated file. Then npm run spec:check --workspace=@skill-map/spec to confirm it passes — the CI hook runs the
same via the root validate orchestrator.
If you changed the prompt preamble text, also re-generate the conformance
fixtures (path: spec/conformance/fixtures/preamble-v*.txt) per the
process described in AGENTS.md. Never hand-edit those fixtures.
8. ROADMAP cross-reference
AGENTS.md mandates ROADMAP stays in sync. Walk the diff and check whether
any of the changes warrant a touch in ROADMAP.md:
- New decision → may need entry in §Decision log.
- Step boundary crossed → update §Execution plan completeness marker
- the per-step section.
- New normative spec field → mention under the relevant section.
- Configuration / CLI surface change → §Configuration or §CLI surface.
If yes, edit ROADMAP and stage. The ROADMAP no longer carries a
Last updated: header line, so there is nothing to bump there; the
edit history lives in context/roadmap-history.md and git log.
9. Stage explicitly
git add path/one path/two …. List every file by name. NEVER:
git add -A ❌
git add . ❌
git add -u ❌
The exception is when staging a directory the user explicitly asked for
in full — even then, list the directory: git add ui/src/app/components/.
Re-run git status after staging to confirm exactly what's queued.
10. Compose the commit
Conventional commit. Style observed in this repo's git log:
- Type:
feat/fix/docs/chore/refactor/test/style/perf/build/ci. - Scope: prefer workspace names (
spec,src,ui) but also accept topical scopes when clearer (docs,roadmap,agents,readme,skill,changeset). Multiple scopes separated by comma:feat(skill,docs,ui): …. - Subject: lowercase, imperative, no trailing period, < 70 chars.
Body (after a blank line) — explain the WHY, not the what. The diff and the changeset already cover the what. Bullet list works well when the commit is multi-faceted.
End with the trailer:
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ALWAYS pass the message through a HEREDOC so newlines and bullets survive:
git commit -m "$(cat <<'EOF'
feat(scope): subject line
Body paragraph or bullets.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
EOF
)"
11. Confirm
After git commit, run git status to confirm a clean tree (or only
intentional residual changes). Show the final commit hash + subject to
the user.
12. If the pre-commit hook fails
- Read the hook output carefully. Common failures here: spec integrity check, lint, format, type-check.
- Fix the actual issue. NEVER
--no-verify. - Re-stage the fix. Create a NEW commit. Do NOT amend (the failed commit didn't land, so amending would mutate the previous, unrelated commit).
Bumping decision quick-reference
diff includes spec/ ?
├── only typos / clarifications → @skill-map/spec: patch
├── new optional field / additive → @skill-map/spec: minor
│ (0.Y.Z track: patch)
├── breaks conforming implementations → @skill-map/spec: major
│ (0.Y.Z track: minor;
│ confirm majors first)
└── prompt-preamble.md prose → regenerate fixtures, then
classify normality
diff includes src/ ?
├── pure refactor / internal fix → @skill-map/cli: patch
├── new CLI verb / new flag → @skill-map/cli: minor
│ (0.Y.Z track: patch)
├── verb removed / exit code changed → @skill-map/cli: major
(0.Y.Z track: minor;
confirm majors first)
diff includes alias/<name>/ ?
└── retired → STOP, ask Arquitecto
(workspaces dropped;
placeholders deprecated
on npm)
diff is only ROADMAP / AGENTS / .claude / docs → no changeset
diff is mixed → highest bump wins
User-facing section (only when @skill-map/cli bumps):
├── CLI verb / flag / output / behaviour → include `## User-facing`
├── UI feature (graph, inspector, settings) → include `## User-facing`
├── Pure refactor / infra / test reshuffle → omit
└── Unsure → include (low cost)
Things this agent does NOT do
- Doesn't push. Manual.
- Doesn't open PRs. Manual or via a separate workflow.
- Doesn't bump README version badges. Exception step, only at Version Packages PR merge time.
- Doesn't edit code beyond what the user already changed. This agent
is a commit shepherd, not a refactor agent. The only files this agent
may originate are
.changeset/*.md(incl. their## User-facingsection when applicable per §6.1), the regeneratedspec/index.json, and a cross-reference inROADMAP.md. The workspaceCHANGELOG.mdfiles are NOT hand-written,changeset versiongenerates them at release time. Anything else → ask the user first. - Doesn't edit
ui/src/data/user-changelog.jsondirectly. That file is regenerated byscripts/build-user-changelog.jsatrelease:versiontime from the## User-facingsections in the pending changesets. The commit agent's job stops at writing those sections; the JSON gets stamped at release time, not on every commit.