From safer
Wrapper that exposes the sister codemod's safer-spec-migrate skill inside safer-by-default. The body of this skill is inlined at bin/safer-gen-skills time from vendor/safer-spec-development/skills/safer-spec-migrate/SKILL.md. Use when an adopter is migrating an existing module (with prior public exports) onto the living-spec layer. Do NOT use to bootstrap a fresh module; route to /safer:contract-init. Do NOT edit the body block below. Edit the upstream vendor/safer-spec-development/skills/safer-spec-migrate/SKILL.md (via sister submodule bump) and re-run bin/safer-gen-skills.
How this skill is triggered — by the user, by Claude, or both
Slash command
/safer:contract-migrateThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
<!-- AUTO-GENERATED from this directory's SKILL.tmpl + PRINCIPLES.md. Do not edit; edit the .tmpl and regenerate via bin/safer-gen-skills. -->
You are migrating a project's committed safer-spec artifacts (MODULE.md, .safer-spec/<slug>.json) from one SPEC_FORMAT_VERSION to another. generate and validate are CLI commands; migrate is a SKILL because the diff between format versions involves judgment (which fields to drop, how to merge new sections, what to flag for the human) that a coding agent does more reliably than a versioned codegen path baked into the CLI.
fromVersion — read from the on-disk files. The two artifact kinds use DIFFERENT keys:
MODULE.md YAML frontmatter: format-version: (dashed)..safer-spec/<slug>.json sidecar: "formatVersion" (camelCase).
Confirm at least one of each kind to make sure they agree.toVersion — the version the currently-installed CLI emits. Run pnpm safer-spec --version (or npx safer-spec --version) to read it directly from the installed binary — that's the canonical source. Do NOT read src/commands/version.ts; the npm package ships dist/** and skills/** only, so that path won't exist for adopters.dryRun — default true. When dry-run, do not write to the working tree; produce a unified diff per file in a tmpdir and ask the user to confirm before re-running with dryRun: false.If fromVersion === toVersion for every file, nothing to migrate. Report cleanly and exit.
CHANGELOG.md between fromVersion and toVersion — the format-version section lists the structural changes (e.g., "0.3 → 0.4: drop purpose: frontmatter; rename Public surface to Exports; add ## Children section").MODULE.md — confirm its frontmatter format-version: value matches fromVersion..safer-spec/<slug>.json sidecar — confirm its "formatVersion" value matches the same fromVersion. If the two artifact kinds disagree, STOP and report the discrepancy; a partial-migration state needs human triage.src/<folder>/index.ts, src/<folder>/__tests__/<slug>.spec.test.ts. The migration MUST preserve every fact those files declare; only the rendering changes.For each tracked MODULE.md (use git ls-files '**/MODULE.md' '**/*.json' scoped to .safer-spec/):
format-version: for MODULE.md, "formatVersion" for sidecar JSON. If the value equals toVersion, skip (already migrated — idempotent).fromVersion, regenerate. The regeneration step branches on dryRun:
dryRun: true (the default): cp -r the entire repo to a tmpdir, run pnpm safer-spec generate --folder <folder> --write THERE, then diff -ur <project>/<folder> <tmpdir>/<folder> to show the user the proposed change. The working tree is never touched.dryRun: false: run pnpm safer-spec generate --folder <folder> --write against the project directly. The codemod's emitter is the canonical source-of-truth for toVersion's shape; do not hand-edit the markdown.After all folders are regenerated (or dry-run-regenerated):
pnpm safer-spec validate --planned (against the regenerated location — tmpdir for dry-run, project tree for the real run) to check that every regenerated MODULE.md + sidecar passes the drift cross-check.validate reports a gap, STOP. The gap means the regeneration produced bytes that don't match what the source files imply — usually a JSDoc directive that needs updating, not a migration bug. Tell the user the diagnostic verbatim.For dryRun: true, the diff comes from step 2's diff -ur of tmpdir vs project. Show the user. Ask:
dryRun: false to apply against the project."For dryRun: false, run git diff -- '**/MODULE.md' '**/*.json' after the regeneration to see what the write produced. Same questions; commit with git add -p to stage selectively.
Refuse to migrate (do NOT regenerate anything) when:
MODULE.md or .safer-spec/ files. Migration must start from a clean checkpoint so the diff is purely the migration's doing.CHANGELOG.md has no section describing the fromVersion → toVersion transition. You'd be guessing at the shape change.formatVersion: doesn't match fromVersion for any inspected file (and isn't already toVersion). Probably the user meant a different fromVersion.Each refusal is a STOP — tell the user the specific reason and what they need to fix before re-running.
A versioned migration table baked into the CLI would have to grow with every format-version bump. The committed MODULE.md shape is already what generate emits at the current SPEC_FORMAT_VERSION; migration reduces to "regenerate then diff." The judgment lives in (a) reading the CHANGELOG to know what changed, (b) deciding when an unexpected diff is a migration bug vs. real source drift, and (c) deciding whether to ask the user for confirmation. All three are agent work. The CLI keeps the regen path; the agent owns the migration loop.
The original migrate stub lived in src/commands/migrate.ts. It never had a real implementation — keeping it as Effect.die("Not implemented: migrate") for hypothetical future bumps would have meant carrying the wrong-shaped abstraction. Removed in favor of this skill.
Provides behavioral guidelines to reduce common LLM coding mistakes, focusing on simplicity, surgical changes, assumption surfacing, and verifiable success criteria.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
npx claudepluginhub chughtapan/safer-by-default --plugin safer