skills/spec-to-repo/SKILL.md
--- name: spec-to-repo description: Graduate an accepted vault spec into a fresh repo. Reads the spec, scaffolds the repo (delegates to a stack skill or stamps a minimal layout), copies the spec into docs/specs/, derives .ralph/prd.json from the User Stories section, and cross-links the vault entry. Closes the loop between research-in-vault and implementation-in-repo. Use when an accepted vault-genesis spec is ready to become code. category: development argument-hint: [--scaffold tanstack|minima
npx skillsauth add RonanCodes/ronan-skills skills/spec-to-repoInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Graduates a vault-genesis spec into a working repo. After this runs, the repo has the spec next to its code, a Ralph-ready PRD derived from the spec's stories, and a cross-link back to the vault genesis snapshot.
Sister skills: /generate-spec (produces the vault input), /compare-specs (diffs versions), /compare-codebase-to-spec (audits drift), /ralph (consumes the derived PRD).
# Minimal scaffold (git init + docs/ + .ralph/, no stack opinions)
/spec-to-repo --scaffold minimal --target ~/Dev/myapp <vault-spec-path>
# TanStack Start + Cloudflare Workers stack (delegates to /ro:new-tanstack-app)
/spec-to-repo --scaffold tanstack --target ~/Dev/myapp <vault-spec-path>
# Repo already exists, just copy spec and derive PRD
/spec-to-repo --scaffold none --target ~/Dev/existing/myapp <vault-spec-path>
If --target is omitted, default to $HOME/Dev/<name> (adjust to your projects dir) where <name> is from --name flag, the spec frontmatter title, or kebab-cased prompt.
If --scaffold is omitted, ask via AskUserQuestion. Default recommendation is tanstack for web/SaaS specs, minimal for everything else.
Run these checks in order. If any fails, surface the exact problem and stop. Do NOT silently work around credential failures (the night-shift Dataforce run on 2026-05-06 worked around a revoked Cloudflare token by adding continue-on-error: true to CI; that's exactly what this pre-flight prevents).
| Check | Command | Pass condition |
|---|---|---|
| gh is authenticated | gh auth status | "Logged in to github.com account ..." |
| Target GitHub org exists and the user is a member | gh api /user/orgs --jq '.[].login' then check the spec's stated org appears in the list | Org login matches spec's repo field (case-sensitive on GitHub) |
| wrangler is installed and auth works | wrangler whoami | Returns email + account list, NOT "You are not authenticated" |
| Cloudflare token in env actually works | curl -s "https://api.cloudflare.com/client/v4/user/tokens/verify" -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \| jq .success | true |
| Cloudflare account ID matches | curl -s "https://api.cloudflare.com/client/v4/accounts" -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \| jq .result[0].id matches $CLOUDFLARE_ACCOUNT_ID | exact match |
| pnpm + node + git versions | pnpm -v && node -v && git --version | All present, node 20+ |
| Spec env vars all populated | for each env var listed in the spec's GitHub Actions secrets table, check it's set in ~/.claude/.env.<context> and not empty | All set |
Report the pre-flight as a table to the user. If anything fails, include the EXACT remediation (e.g. "mint a fresh CF token at https://dash.cloudflare.com/profile/api-tokens with scopes X / Y / Z").
This pre-flight takes ~30 seconds and catches the night-shift class of problem before kicking off hours of work.
Read the vault spec. Confirm:
status: accepted. If status: draft or anything else, ask via AskUserQuestion: "Spec status is <status>. Graduate anyway?" Default no.repo is empty or unset. If already populated, this spec has already graduated; surface the existing repo path and ask whether to abort, re-graduate to a new repo, or refresh the derived PRD only.Simplicity-Labs not simplicitylabs). The night-shift run nearly used the wrong org name because the spec used the lowercase form; pre-flight (step 0) catches this.--target exists and is non-empty: ask "Target <path> exists and contains files. Continue?" Show top-level ls for context. Default no.--target doesn't exist: create the parent directory if needed.--name flag, then spec title slug, then prompt.Branch on --scaffold:
tanstack: Invoke /ro:new-tanstack-app --target <path> --name <name> and let it run its own decisions (DB, auth, observability). Wait for it to finish before continuing.
minimal: Stamp this layout:
<target>/
├── .gitignore (node, dist, .ralph/archive, .env, .dev.vars)
├── README.md (one paragraph from spec Outcomes section + link to spec)
├── docs/
│ └── specs/ (created, empty for now; spec lands here in step 4)
├── .ralph/ (created, empty for now; prd.json lands here in step 5)
└── .gitkeep markers in docs/, .ralph/
Then git init, git add -A, initial commit:
🌱 chore: scaffold repo from vault spec <vault-short>:<filename>
none: Skip scaffolding. Confirm <target> is a git repo; if not, abort with a clear message.
Copy the vault spec markdown file to <repo>/docs/specs/<basename> (preserve filename: e.g. myapp-spec-v1-fresh-2026-05-02.md becomes spec-v1-fresh-2026-05-02.md in the repo, dropping the project-name prefix since the repo identity is implicit).
Update the repo copy's frontmatter:
| Field | Value |
|---|---|
| repo | repo URL (from git remote get-url origin if set) or absolute path |
| graduated-from-vault | <vault-short>:<original vault path> |
| status | accepted (preserved) |
| date | preserved (this is the genesis date, not graduation date) |
| version | v1 (preserved) |
Do not edit the body. The spec is the same artefact, just relocated.
.ralph/prd.jsonParse the spec's ## 5. User Stories section. For each ### US-NNN — <title> block:
| Spec field | PRD field | How to map |
|---|---|---|
| ### US-NNN — <title> | id, title | direct |
| "As a X, I want Y, so that Z" line | description | direct |
| Each row of the EARS table | one entry in acceptanceCriteria | format as WHEN <trigger> THE system SHALL <behaviour> (preserve existing wording) |
| Order in spec (top to bottom) | priority | 1, 2, 3, ... |
| ### 8. Plan milestone for the story | (notes) | optional: prefix notes with M<n>: <milestone goal> |
Write to <repo>/.ralph/prd.json:
{
"project": "<repo-name>",
"branchName": "ralph/v1-genesis",
"description": "<one-paragraph summary from spec § Outcomes>",
"spec": "docs/specs/<basename>",
"userStories": [
{
"id": "US-001",
"title": "...",
"description": "As a ..., I want ..., so that ...",
"acceptanceCriteria": [
"WHEN ... THE system SHALL ...",
"WHEN ... THE system SHALL ..."
],
"priority": 1,
"passes": false,
"notes": "M1 (tracer): <milestone goal>"
}
]
}
The spec field is new and points at the in-repo spec path; future Ralph runs and audits use it as the source-of-truth pointer.
Open the original vault spec and update frontmatter:
| Field | New value |
|---|---|
| status | graduated-to-repo |
| repo | the same repo URL/path used in step 4 |
At the bottom of the body, add (or update if it exists) a single line:
> Graduated to repo: [<repo-name>:docs/specs/<basename>](file://<absolute-path>) on YYYY-MM-DD.
If the vault has cross-vault link conventions (it does for llm-wiki), use the obsidian:// URL form when the repo is itself in a known location, otherwise a plain file:// link is fine.
In the new repo, commit steps 4-5 as one change:
✨ feat(spec): graduate v1 genesis spec from vault and derive Ralph PRD
Use the user's normal commit conventions (emoji + conventional format, no Co-Authored-By).
Run, in this order:
open <repo> (Finder) so the user can see the layout.open -a "Visual Studio Code" <repo>/docs/specs/<basename> or whatever the user's editor is. If unsure, just print the path.obsidian://open?vault=llm-wiki-<vault-short>&file=<url-encoded-path-without-.md> so the user can verify the cross-link.Print a 5-line summary:
✅ Spec graduated.
vault: <vault-spec-path> (status: graduated-to-repo)
repo: <repo-path>
spec: <repo>/docs/specs/<basename>
PRD: <repo>/.ralph/prd.json (<N> stories, priority 1 = US-001 "<title>")
Next: run /ralph in <repo> to start the tracer-bullet implementation.
.ralph/prd.json only (skipping repo scaffold + spec copy).~/Dev/<existing>): don't auto-suffix. Ask explicitly.git available: surface and stop. Do not attempt fallback.wrangler whoami fails, stop and ask the user to mint a fresh token. If org membership check fails, stop and ask the user to confirm the org name. The autonomous loop must not start with broken credentials; the night-shift Dataforce run shipped CI-green-but-not-actually-deployed code because pre-flight didn't catch a revoked CF token.gh api). Detect this in pre-flight via gh api /orgs/<org> --jq '.plan.name' and surface to the user: "The Simplicity-Labs org is on the free plan; branch protection on private repos requires GitHub Team ($4/user/month). Continue with soft enforcement (auto-merge + squash-only + delete-on-merge), or upgrade first?"Co-Authored-By lines (the user has explicitly asked for this in CLAUDE.md).description field one paragraph; longer summaries belong in the spec, not the PRD./ralph./ro:cf-ship or /ro:fly-deploy.testing
--- name: linear-pipeline description: The Fable orchestrator for a single dispatched Linear ticket. Holds almost no context itself; it receives `--issue <ID> --detached`, decides the stage sequence, and fans out a sub-agent per stage, passing forward only each stage's artifact (never re-derived, never inlined into its own context). Step zero, before any planning or stage routing, is a boundary triage against `canon/security-boundary.md` (#199): a match tags Ronan Connolly and stops the run, no
development
--- name: in-your-face description: Capture a chat-only answer into a durable artifact (markdown + HTML, PDF when cheap) and launch it automatically so the user cannot miss it. Use when user says "in your face", "don't let me lose this", "save that answer", "make that durable", or right after answering a substantive side question (a recipe, comparison, how-to, or generated prompt) that would otherwise die with the context. category: workflow argument-hint: [--no-open] [--vault <short>] [hint of
tools
One-shot headless OpenAI Codex CLI calls for background/admin AI tasks — summaries, classification, extraction, admin glue. The default engine for anything that runs AI constantly in the background (daemon-driven, per-event), because it bills the flat ChatGPT subscription instead of Claude usage or per-token API spend, and it keeps working while Claude is rate-limited. NEVER for coding — coding stays Claude. Use when a skill or daemon needs a cheap always-on AI call, when the user says "use codex", "ask codex", "codex as backup", or when building a background summarizer/classifier into a listener or loop. Reads auth from ~/.codex/auth.json (ChatGPT account, no API key).
research
Turn a warranty rejection, repair quote, or RMA email into a cited decision brief — legal read (NL/EU consumer law), is the part user-serviceable, live part and new-unit prices, repair-vs-DIY-vs-new economics, before-you-send-it checklist, deadlines. Use when the user pastes or screenshots a repair quote, warranty rejection, "not covered" email, onderzoekskosten fee, or asks "should I repair or replace this".