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/ai-projects/myapp <vault-spec-path>
# TanStack Start + Cloudflare Workers stack (delegates to /ro:new-tanstack-app)
/spec-to-repo --scaffold tanstack --target ~/Dev/ai-projects/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 ~/Dev/ai-projects/<name> 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/ai-projects/<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.development
Close the loop on a Linear ticket when its work ships - move the status and post a deploy comment with the PR link, what shipped, and a try-it link, mentioning the collaborator. Used as the tail of /ro:linear-nightshift for every merged mirror, or manually after an ad-hoc build. Triggers on "linear update", "update the linear ticket", "mark NUT-x done", "tell eoin it shipped", "/ro:linear-update".
devops
Run a night-shift against a collaborator's Linear board. Pulls the team's Grilled tickets (/ro:linear-grill moves a ticket to Grilled once its questions are answered), VERIFIES the questions were actually answered (unanswered → bounce the ticket to the "Question for <name>" state), mirrors verified tickets to ephemeral GitHub issues with ready-for-agent, then runs the standard /ro:night-shift machinery on GitHub. Tail-calls /ro:linear-update for everything that merged + deployed. Triggers on "linear nightshift", "nightshift linear", "drain the linear board", "run the shift off linear", "/ro:linear-nightshift".
development
Grill a collaborator's Linear tickets and move every processed ticket to where it belongs. Resolves the board from the repo's .ro-linear.json, reads the collaborator's Backlog / Ready-for-agent issues, then per ticket either posts 3-5 decision-extracting questions (state moves to "Question for <name>") or confirms it build-ready (state moves to "Grilled", the gate /ro:linear-nightshift consumes); shipped-and-confirmed tickets close as Done. The async-collaborator counterpart of /ro:day-shift for people who never touch GitHub. Triggers on "grill linear", "grill eoin's tickets", "linear grill", "add questions to the linear tickets", "/ro:linear-grill".
development
--- name: about-page description: Add a standard About page to any web app, what it is, the tech stack, and an FAQ, wired into a footer link with a sticky footer. Built with Spartan + Tailwind (the canonical component layer) and falls back to semantic HTML so it ships reliably. Use whenever building, polishing, or shipping an app, every app should have one. Triggers on "add an about page", "about page", "footer about link", or as a standard step in app build/polish. category: frontend argument-h