Install
$ agentstack add skill-ramboz-jig-migrate ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
> Spec 008 created this skill from scratch. The deterministic filesystem > walk + verdict logic + report rendering live in migrate.py; this > SKILL.md drives the judgment layer (when to invoke, how to interpret > ambiguities, what operations to suggest in what order).
What this skill does
Closes the "already spec-driven" gap that scaffold-init doesn't handle: projects that organically grew the same workflow jig codifies but landed on different conventions (folder names, filename prefixes, slice topology). Direct example: a project with docs/slices/ (flat) and docs/decisions/ (validator-style) — scaffold-init would not detect it as scaffolded and would either refuse confusingly or pollute the tree.
migrate flips that around: detect existing shape first, then propose a migration plan, then (in later slices) apply the rename / restructure operations.
migrate.py exposes four subcommands:
report— strictly read-only inventory + plan.rename-decisions— applies ADR-0004's rename. Idempotent; refuses
on conflict; has a --dry-run mode; --host claude|codex selects whether cross-reference rewrites scan CLAUDE.md/.claude/ or AGENTS.md/.codex/.
split-slices— extracts embedded slice sections into sibling
slice files.
copy-machinery— copies jig runtime machinery into the target's
host-local scaffold runtime; --host claude writes .claude/, and --host codex writes .codex/.
How to use
Run the migration report
python3 "${CLAUDE_PLUGIN_ROOT}/skills/migrate/migrate.py" report \
- `
— path to the project root (e.g./path/to/repo`,
. for cwd).
Run the rename-decisions migration
Once report has been reviewed and the verdict is adoptable, the recommended sequence is:
# 1. Preview the plan (no writes).
python3 "${CLAUDE_PLUGIN_ROOT}/skills/migrate/migrate.py" \
rename-decisions --dry-run
# 2. After reviewing the planned operations, apply them.
python3 "${CLAUDE_PLUGIN_ROOT}/skills/migrate/migrate.py" \
rename-decisions
What it does, in display order:
docs/adrs/→docs/decisions/(directory rename, atomic).- Per-file renames:
NNN-.md→adr-NNNN-.md
(pad 3-digit to 4-digit; add adr- prefix where missing).
- Cross-reference rewrites in text files under
docs/,CLAUDE.md,
and .claude/ by default. With --host codex, rewrites scan docs/, AGENTS.md, and .codex/ instead. The helper itself (migrate.py and its fixtures) is never rewritten.
Refusal cases (exit 2, no mutations):
- Both
docs/adrs/anddocs/decisions/present (manual merge first). - Two source files normalize to the same target name (collision).
- `` missing, not a directory, or unreadable.
No-op cases (exit 0):
- Neither dir present, OR all files already on the canonical shape —
emits "already aligned: nothing to do" and returns.
Run the copy-machinery operation
copy-machinery brings a migrated project to scaffold-mode parity — the same host-local runtime shape /jig:scaffold-init produces by default for greenfield projects. See the dedicated section [## Copying machinery into your project](#copying-machinery-into-your-project) below for the full description.
Quick reference:
python3 "${CLAUDE_PLUGIN_ROOT}/skills/migrate/migrate.py" \
copy-machinery
Exit codes
0— verdict isadoptableORnot-yet-spec-driven(the report is
the deliverable regardless of verdict).
1— verdict ispartial(borderline; report still emits, but
/jig:scaffold-init may be a better fit).
2— user error (missing argument, dir doesn't exist, target is a
file not a directory).
Verdict logic
migrate counts four migration triggers in ``:
- Spec-or-slice dir (
docs/specs/ordocs/slices/). - Decision-or-ADR dir (
docs/decisions/ordocs/adrs/). - Workflow doc (
docs/workflow.md). - Architecture doc (
docs/architecture.md).
| Triggers | Verdict | Recommendation | |---|---|---| | 3 or 4 | adoptable | Proceed with the suggested operations | | 2 | partial | Borderline — scaffold-init may be a better fit | | 0 or 1 | not-yet-spec-driven | Run /jig:scaffold-init instead |
Report structure
Six sections, in fixed order:
- Inventory — table of detected artifacts (paths + counts + shape
notes). Inventories everything the helper found, including items that are inventoried-only (spikes, custom skills, custom agents).
- Mapping — table of "current path/name → jig target name". For
ADR files this includes the 3-digit-to-4-digit pad and the adr- prefix add (per ADR-0004). For flat slices, the row points to the Ambiguities section because no automated topology mapping exists in slice 008-01.
- Conflicts — situations that block specific migration operations
(e.g. docs/adrs/ AND docs/decisions/ both present means rename-decisions refuses on this project). Empty if no conflicts.
- Ambiguities — judgment calls the user must make. Common entries:
"flat slices reference M1–M6 milestones — map each to a parent spec?"; "custom skills overlap jig's stock set — replace or layer?"; "CLAUDE.md is 59KB with sprint log — port subset or leave?".
- Contract surfaces detected — (added by spec 022-02) flags
external-interface artifacts already on disk and prose API contracts that would benefit from standard schemas (OpenAPI / JSON Schema / AsyncAPI / .proto / GraphQL SDL). Four detection types: (a) existing schema artifacts, (b) prose API contracts in canonical doc files, (c) env-contract triple (markdown + .env.example + checker), (d) hand-typed boundary types (e.g. problem-details.ts). Each detected surface gets a one-line classification + recommendation; "No contract surfaces detected" prose when empty. Companion to the /jig:contracts skill's per-surface recommendation table.
- Operations — ordered list of
migrate.pycalls
the user should run, with --dry-run first. For slice 008-01, the only operations mentioned are future subcommands marked (slice 008-NN, not yet implemented) — so the report's main value right now is the first five sections.
When to invoke
Auto-trigger phrases (in this SKILL.md's description):
- "migrate this project to jig"
- "adopt jig here"
- "this repo already has specs — set up jig"
- "scaffold-init refused — what now"
- "introduce jig to an existing codebase"
Typical session flow:
- User invokes the skill against an existing project.
- Helper runs
migrate.py report. - SKILL.md (this file's body) helps interpret ambiguities: what's a
real conflict vs. just an open question? What's safe to defer?
- User makes the judgment calls flagged in Ambiguities.
- Once future slices land (008-02
rename-decisions, 008-04
slice-to-spec), the user runs those operations from the report's suggested order, with --dry-run first.
End-to-end example
# 1. Inventory the project.
python3 .../migrate.py report /path/to/existing-project
# Expected output (when 3+ triggers are present):
#
# # Migration report — `/path/to/existing-project`
#
# **Verdict:** adoptable
#
# _Three or more migration triggers detected. Proceed with the
# operations below._
#
# ## Inventory
#
# | Path | Count | Note |
# |------|-------|------|
# | `docs/slices/` | 27 | flat slice files (validator-style) |
# | `docs/decisions/` | 22 | decision records (ADR-0004 aligned) |
# | `docs/spikes/` | 4 | spike memos (inventoried only) |
# | `docs/workflow.md` | 1 | workflow doc present |
# | `docs/architecture.md` | 1 | architecture doc present |
# | `CLAUDE.md` | 1 | 59231 bytes (larger than baseline) |
#
# ## Mapping
#
# | Current | jig target | Note |
# |---------|------------|------|
# | `docs/decisions/` | `docs/decisions/` | kept (already aligned) |
# | `docs/decisions/adr-001-foo.md` | `docs/decisions/adr-0001-foo.md` |
# pad to 4-digit + ensure `adr-` prefix |
# | `docs/slices/slice-NN-*.md` (27 files) | topology question |
# no automated mapping in 008-01 |
#
# ## Conflicts
#
# _None detected._
#
# ## Ambiguities
#
# - **Flat slices reference 6 milestone(s) (M1, M2, M3, M4, M5, M6).**
# Under jig's nested model, each could become a parent spec...
#
# ## Operations
#
# Suggested order (each operation is `--dry-run` first):
#
# 1. **`migrate.py rename-decisions `** (slice 008-02, not yet
# implemented) — apply ADR-0004 rename...
# 2. **`migrate.py slice-to-spec `** (slice 008-04, not yet
# implemented) — interactively map flat slices...
Copying machinery into your project
copy-machinery brings a migrated project to scaffold-mode parity — the same host-local runtime shape /jig:scaffold-init produces by default for greenfield projects. After running it, the project owns its own copy of jig's skills, agents, hook scripts, and hook registration. The dev can edit those files in their own repo, and they ride along under version control.
When to use it:
- After
rename-decisionshas applied ADR-0004 to existing ADRs. - After
split-sliceshas split any monolithicspec.mdfiles
with embedded slices into the file-per-slice layout.
- Standalone, when a project already has spec-driven layout but
the dev wants the machinery in their tree (rather than only in the installed plugin under ${CLAUDE_PLUGIN_ROOT}).
migrate.py report will surface this subcommand in the Operations section when the verdict is adoptable or partial and the default host scan does not find pre-existing jig-managed skills. Codex users can also run the explicit copy-machinery --host codex command when they want Codex runtime machinery even if the conservative report wording is not the deciding signal.
Host selection:
--host claudewrites Claude scaffold machinery under.claude/
and is the source-checkout default.
--host codexwrites Codex scaffold machinery under.codex/.--host autois the CLI default; helpers copied under.codex/skills/
infer Codex, and all other invocations infer Claude.
How to run it:
python3 "${CLAUDE_PLUGIN_ROOT}/skills/migrate/migrate.py" \
copy-machinery
What it does:
- Copies skills into the host runtime (
.claude/skills/jig-/
or .codex/skills/jig-/), rewriting helper paths in SKILL.md bodies to that runtime.
- Copies agents into the host runtime (
.claude/agents/jig-*.mdfor
Claude, .codex/agents/jig-*.toml for Codex).
- Copies hook scripts into the host runtime, pinning each script's mode
to 0o755.
- Generates or merges host hook registration.
--host claudeuses
.claude/settings.json, with per-entry metadata.managed_by_jig: true markers. --host codex uses .codex/hooks.json, with a schema-clean top-level hooks object.
Subsequent runs are idempotent: re-running copy-machinery overwrites the copied files in place and updates jig-managed hook registration. On --host claude, non-jig hooks in .claude/settings.json survive untouched. On --host codex, jig-managed .codex/hooks.json is regenerated as a whole because Codex hook registration is a single file and jig ownership is detected from generated jig hook command paths.
Refusal: unmanaged hooks
If the host hook configuration already exists and is not jig-managed, copy-machinery exits non-zero (exit code 3) and emits the UnmanagedHooksError refuse-message to stderr — no filesystem writes occur. For --host claude, this means .claude/settings.json has hooks under hooks. but none carry the managed_by_jig marker. For --host codex, this means .codex/hooks.json exists and does not look like a jig-generated hook config. This matches the same safety stance scaffold-init enforces.
The documented escape is --force:
python3 "${CLAUDE_PLUGIN_ROOT}/skills/migrate/migrate.py" \
copy-machinery --force
With --force, --host claude appends jig's hooks alongside existing entries, which survive unchanged. With --force, --host codex replaces an unmanaged .codex/hooks.json with jig's generated hook registration. Use the Codex force path only when you are sure the existing hook config should be replaced or has been backed up.
Relationship to scaffold-mode
migrate.py copy-machinery is the migration-path equivalent of scaffold-init --with-machinery (default since slice 016-03). Both end up calling the same host-aware copy_machinery(plugin, target, *, force, host) façade in scaffold.py, so the resulting host runtime shape is equivalent regardless of which adoption path produced it. Closing this gap for Claude was spec 021's reason for being; spec 059-01 extends the same adoption path to Codex.
Agentic slice-to-spec migration
For projects where migrate.py report returns Verdict: adoptable AND the inventory shows flat slice files under docs/slices/ rather than nested docs/specs/NNN-slug/spec.md form, there is no deterministic helper to do the grouping (slice 008-04 was deferred deliberately — see Non-goals on spec 020). Instead, the LLM driving the migration follows the algorithm below. Output is a new docs/specs/ tree; originals stay where they are until the caller verifies and chooses to clean up.
When to invoke
After migrate.py rename-decisions (so ADR filenames are jig-shaped), when the report's Ambiguities section names "Flat slices reference N milestone(s)" or similar. The follow-up is this agentic workflow. Do NOT run it if specs already live under docs/specs/NNN-slug/spec.md — that's already the jig shape.
Algorithm
For each migration, in order:
- Read milestone summaries. Walk
docs/milestones/*.md (or whatever the source's milestone-doc convention is). For each milestone, capture the title, scope, and slice list. These become the basis for spec naming.
- Decide milestone → spec mapping. Each milestone becomes one
spec folder. Naming convention: docs/specs/NNN-mM-/ where:
NNNis a 3-digit spec number (start at 001, ascend per
milestone order — match the project's chronology when possible);
mMis the milestone tag lowercased (e.g.m1,m4.5);- `` is a slug of the milestone's headline
("EDS thin E2E" → eds-thin-e2e). Skip milestones that have no slices.
- For each source slice file:
- Read its body. Locate the milestone tag (prose
- **Milestone:** M1, frontmatter milestone: M1, or filename prefix — adapt to what the source uses).
- Locate its status. The source's vocabulary is usually
4-state — translate per the table below.
- Locate the heading. Source shape is usually
# Slice NN — Title (H1, single number, no spec prefix). Transform to ## Slice NNN-NN — (H2, jig spec-slice fragment, slug-form title). Use the target spec's NNN from step 2 and the original slice number for the second NN.
- Prepend a frontmatter block (frontmatter shape per spec 015
- 018):
`` --- status: dependencies: [] last_verified: --- ` Leave dependencies: []` for now — backfilling structured deps from prose "Depends on" lines is per-slice judgment work, not bulk-migration scope.
- Preserve the original slice body verbatim AFTER the new
heading (Status / Milestone / Depends on / Estimated size prose lines included — they're harmless trailing context).
- Write new files under
docs/specs/NNN-mM-/:
spec.mdsynthesized from the milestone summary (header +
overview + ## Decomposition + ## Slices link list).
- One
slice-NN-.mdper source slice. Keep
the original filename's shortname (no re-slugging) so existing cross-references resolve.
- Do NOT delete originals. The source
docs/slices/and
milestone summaries stay in
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: ramboz
- Source: ramboz/jig
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.