bama
BAMA: 모든 Mac 앱을 만들 수 있습니다
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기A filesystem contract (.workflow/meta.json) + 50 agent skills that take a product from idea to production: web (Next.js 16) & mobile (Expo/RN), plus an eve agent engine, Linear/scrum, an enforced design-system lint, registry intake and EU data-residency decisions. Runs on Claude Code, Codex, Copilot, Gemini, Cursor.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
📖 Browse every skill → — one page per skill: what it does, when it applies, what it deliberately doesn't, and the references it ships. Generated from skills.json, so it can't drift from the suite.
The poster above is the interactive map (dark/light): docs/dev-flow-skill-map.html
A filesystem contract for agent-driven SDLC.
One folder (.workflow/), one state file (meta.json), and 51 skills (9 core + 18 web + 2 agent + 16 mobile + 4 monorepo + 2 refactor) that read/write it. The contract is the product — the skills are durable, replaceable consumers.README 전문 보기 ↗📖 Browse every skill → — one page per skill: what it does, when it applies, what it deliberately doesn't, and the references it ships. Generated from skills.json, so it can't drift from the suite.
The poster above is the interactive map (dark/light): docs/dev-flow-skill-map.html
A filesystem contract for agent-driven SDLC. One folder (
.workflow/), one state file (meta.json), and 56 skills (13 core + 19 web + 2 agent + 16 mobile + 4 monorepo + 2 refactor) that read/write it. The contract is the product — the skills are durable, replaceable consumers.v1.0.0 — install as a Claude Code plugin:
/plugin marketplace add lukedj78/dev-flowthen/plugin install dev-flow@dev-flow. Other runtimes (Codex · Copilot · Gemini · Cursor) useinstall.sh. See the CHANGELOG.The web family now includes
eve-agent— scaffold and grow an eve agent as the AI engine behind a Next.js app, opted into viastack.agent. It lives inside the app, inapps/agent, or alone at the repo root when the product has no UI at all (three topologies). See docs/example-full-walkthrough.md and the autonomous-loop runbook docs/loop-engineering.md.Rule zero — doc-grounded, never invent. The skills are a second brain: when one says "use library X", it ships the how from X's official docs, prefers the version-matched source the tool itself ships (
next devmaintains anAGENTS.mdblock pointing at bundled docs; eve shipsnode_modules/eve/docs), marks fast-moving identifiers[VERIFY], and gets re-verified on a cadence — logged in docs/vercel-changelog-watch.md. The map of every how-to is docs/knowledge-index.md.Golden rules (on every project, see the contract — ③ is enforced by tools; ① and ② are checked in review, by
spec-review): ① code is written in English (identifiers, constants, comments — independent of the conversation language); ② every frontend ships i18n from day one — web via next-intl, mobile via the RN i18n stack, minimum locales English + Italian, no hardcoded user-facing copy; ③ UI is composed only from the chosen library's primitives — for shadcn the components the CLI installs intocomponents/ui/(all of them, atscaffolded), changed only through DESIGN.md tokens andcvavariants; never a hand-rolled primitive, never a second component library, never a forked primitive, and a truly new one only as a recorded exception. The primitive renders the design: when a board differs, the primitive'scvavariants and DESIGN.md tokens are tuned until it matches pixel by pixel, never the board, and converting an existing screen is proved with a before/after pixel diff. Enforced by the design-system lint (design/no-handmade-uifor raw elements and redrawn primitives; undeclared component libraries and the primitives' headless bases are banned imports outsidecomponents/ui/), a write-time guard (Claude Code hooks installed at scaffold),spec-review's Standards axis andshadscan's routing.
┌────────────────────────┐
│ .workflow/meta.json │ ◄─── single source of truth
│ (phase + stack + │ every skill reads
│ history + artifacts) │ every skill writes
└─────────┬──────────────┘
│
┌─────────────────┴─────────────────┐
│ │
▼ stack.framework="next" ▼ stack.framework="expo-rn"
│ │
│ WEB FAMILY (19 skills) MOBILE FAMILY (16 skills)
│ │
┌──────────┼──────────┐ ┌────────┼─────────┐
│ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼
prd-from- design-md- module-add rn- rn- rn-
idea to-app (auth, db, bootstrap add- module-add
prd-to- screenshot- payments, rn- screen (auth, db,
tasks to-page email, ci, …) styling rn- storage,
figma-to- write-tests rn- write- realtime,
design-md expo- tests push,
image-to- router … payments)
design-md vercel-deploy rn-eas-deploy
│ │
└─────────────────┬─────────────────┘
│
▼
Codebase at <project-root>/
(Next.js app or Expo app)
The skills are interchangeable consumers of the contract. Tomorrow you could rewrite any of them in TypeScript, swap one out for a Cursor-flavored variant, or extend with your own — as long as they read meta.json and respect the phase semantics, they compose.
Your product can ship its own agent-skill. When what you build ends up with
an API a coding agent could drive, that is a distribution channel most products
never notice they have — and it takes exactly one artefact to open it. Near
feature_complete, dev-flow offers to write it: see
product-to-agent-skill.
Three stacks today, one contract. The web stack ships Next.js (or Astro/Vite) + shadcn/Base UI/MUI apps; the mobile stack ships Expo + React Native + NativeWind apps with EAS publishing to the App Store + Play Store; the monorepo stack ships both in one turborepo (with apps/web/ + apps/mobile/ + shared packages/). dev-flow (the orchestrator) reads meta.json#stack.framework and routes to the correct family — prd-from-idea and prd-to-tasks are stack-agnostic and used by all three.
Most "AI agent toolkits" hardcode orchestration in prompts. That works until the conversation drops context — then the agent forgets which step you were on, what design tokens it picked, which modules it wired.
dev-flow fixes that the way distributed systems fix it: state lives on disk, not in the agent's head. Every skill is independently re-runnable from .workflow/meta.json. Resume a build the next morning, hand it off to a different agent, run two skills in parallel — the contract holds.
The skill count is an implementation detail. The contract is the moat.
meta.json records where you are; any skill can pick up.phase they consume and produce.meta.json#history with inputs, outputs, phase delta. You always know who wrote what when.scaffolded until its design-system lint is wired — update_meta.py set-phase runs the check — or an opt-out is recorded with its reason. A guardrail is worth most before the first violation exists, and a rule an agent is merely asked to follow is the rule a hurried agent skips.DESIGN.md by hand, the system knows that registry.json and /showcase (which were derived from it) are now stale — and it knows transitively, so a chain of derivations propagates.The contract is also published as a standalone Python package, dev-flow-contract, so any future tool — a Cursor plugin, a CLI, a different LLM agent — can read/write .workflow/ without depending on Claude Code. It is a reference implementation, held to the contract by tests, not what the skills run, and it does not run the phase gates: phase moves go through update_meta.py.
Requirements: the bundled scripts need Python 3.9 or newer (3.9 is macOS's own python3; CI
compiles and tests every script on it) and git. Most scripts use the standard library only.
Two ways in, two philosophies. The plugin subscribes you to the suite as a managed bundle that updates when we ship. install.sh copies the skill files so you can fork and hack on them — and it's the route for Codex / Copilot / Gemini / Cursor. Pick one; installing both leaves you with every skill twice.
/plugin marketplace add lukedj78/dev-flow
/plugin install dev-flow@dev-flow
Every skill arrives namespaced (dev-flow:forms, dev-flow:rn-bootstrap, …), and /plugin marketplace update pulls new releases. The shipped set is generated from the canonical taxonomy, so what you install always matches skills.json and the CHANGELOG.
install.sh (editable copies, all runtimes)git clone [email protected]:lukedj78/dev-flow.git
cd dev-flow
./install.sh # defaults to Claude Code
./install.sh --platform codex # or Codex CLI / Copilot / Gemini / Cursor
./install.sh --list-platforms # see all supported runtimes
./install.sh --projects ~/projects # also refresh the hooks of your projects that have them
The script copies every skill folder into the platform-appropriate location (e.g. ~/.claude/skills/, ~/.codex/dev-flow-skills/, ~/.gemini/skills/), drops in the right bootstrap file (AGENTS.md, GEMINI.md, .cursorrules) when needed, and moves any pre-existing version of a skill, or a bootstrap file it did not write, to <skills-dir>-backup-<timestamp>/ (outside the skills folder, so it is never loaded as a second copy; the newest 3 are kept, DEV_FLOW_KEEP_BACKUPS=0 keeps all). ./uninstall.sh --platform <same> removes the skills and only the bootstrap files still exactly as installed; add --restore to put back what the most recent install moved aside.
--projects <dir> (repeatable, opt-in) re-runs, after installing, the setup of every project in <dir> (and <dir> itself) that already has a dev-flow hook: registry-intake or the primitives guard. Each project runs its hook from a committed copy, and the phase gate refuses while that copy is older than the installed skill, so without the flag every skill update needs one setup per project. Projects without a hook are not touched, nothing is committed, and a setup that fails or skips itself is named in the output.
Portability: dev-flow's skills are designed to be runtime-portable. See Cross-platform support below.
/plugin add a single skill (local development)If you have the repo cloned locally:
/plugin add /path/to/dev-flow/dev-flow
/plugin add /path/to/dev-flow/prd-from-idea
…
Run once per skill folder. Useful if you only want to install a subset.
gh skill install (GitHub CLI extension)gh extension install <ext-author>/gh-skill # one-time
gh skill install lukedj78/dev-flow # private repo, requires auth
# OR for a specific subset
gh skill install lukedj78/dev-flow dev-flow design-md-to-app
This works with the same gh auth you already use to clone private repos.
.skill filesThe dist/ folder contains packaged .skill archives. Drag them into your Claude Code window one at a time — useful when you don't have shell access on the target machine. (dist/ is regenerated periodically; the newest skills — e.g. eve-agent — may ship source-only until repackaged, so prefer install.sh for the full set.)
ls ~/.claude/skills/ | wc -l
# Should print 56. Restart Claude Code if you don't see them in /skills.
The core happy-path skills (the web flow most projects start with):
| Skill | What it does |
|---|---|
dev-flow | The orchestrator — reads .workflow/meta.json and proposes what to do next |
founder-intelligence | Optional, for a commercial idea whose market is not settled: research, founder interview, competitors, business model and MVP scope in an evidence-tagged Playbook the founder approves before any PRD. Replaces the inventory step on that path; invocable later on an existing project |
prd-from-idea | Idea paragraph → PROJECT.md + PRD.md |
prd-to-tasks | PRD.md → tasks.md (importable into beads / Linear / GitHub Issues) |
wireframe-canvas | Screen inventory → every screen as a desktop + phone artboard on a Design canvas, approved before any scaffold; then the PNGs on the issues |
project-infra-setup | GitHub repo, Vercel project, Neon / Blob / Resend connectors, DNS and secrets, set up from the CLI |
scrum | Run a project with agile scrum on the tracker chosen at design time — Linear, Jira or GitHub: sprints, estimates, planning, velocity, bug triage; the tracker as source of truth |
compliance-audit | GDPR + EU AI Act audit of an existing project (11-point risk register) + safe auto-remediation; flags legal decisions. Horizontal; proposed as a pre-deploy gate |
app-security | Can this code be attacked? Vulnerable dependencies, secrets in code and git history, Server Actions and routes with no session or ownership check (IDOR), data over-exposure — scanned, then read against an OWASP checklist; an opt-in Strix level proves exploits. The fifth pre-deploy gate |
app-verification | A manual, written once into the project (.claude/skills/verify-<app>/), for proving features on the real app: launch until usable, a doctor check, the real selectors, what counts as proof, cleanup of only what the run started; one feature file per PRD story, seeded from the wireframe inventory. Proven live once; a maintain pass keeps it true |
spec-review | Review a diff on two axes — does it match PRD.md/tasks.md, and does it obey the contract it was built under? Parallel sub-agents, reported side by side, never merged |
install.sh installs every skill, not just these. Beyond the core flow above: the compliance-audit capability, the web discipline skills (forms, data-fetching, state-discipline, transitions), the web add-ons (animated-icons animated icons, vercel-doctor cost/perf and shadscan UI-quality pre-deploy gates, vercel-deploy the ship step), the agent engine (eve-agent, eve-registry-porting), registry-intake (governance for third-party registry components), the 2 refactor skills (promote-component, composition-patterns-guide), the 16 mobile rn-* skills, and the 4 monorepo skills. Full breakdown in the catalogue.
mkdir -p ~/projects/my-app && cd ~/projects/my-app
"I want to build a CRM for veterinary clinics. Customer records, vaccination history, appointment scheduling, document archive."
The orchestrator (dev-flow) will:
.workflow/meta.json.prd-from-idea → PROJECT.md + PRD.md..workflow/DESIGN.md.design-md-to-app → fully scaffolded codebase + showcase.screenshot-to-page for routes from your screenshots.module-add for db / auth / etc.By the end you have a runnable Next.js app at the project root, with a .workflow/ folder that documents every decision.
Seven concrete recipes — what to type, what to expect. Pick the one that matches your situation and start there. The sections below assume you've installed the skills (see Quick start).
Situation: empty directory, you have an idea, no design assets yet.
mkdir -p ~/projects/vet-crm && cd ~/projects/vet-crm
In Claude Code, say:
"I want to build a CRM for veterinary clinics. Customer records, vaccination history, appointment scheduling."
The orchestrator routes through phases:
1. dev-flow → init_workflow . (creates .workflow/meta.json, phase=empty)
2. prd-from-idea → PROJECT.md + PRD.md (phase=prd_drafted)
3. prd-to-tasks → tasks.md (phase=tasks_split)
scrum → issues + sprint 1 on the tracker chosen in the PRD
4. image-to-design-md → DESIGN.md (asks for reference screenshots)
OR figma-to-design-md if you have a Figma URL
OR url-to-design-md if you are starting from an existing site or app
5. wireframe-canvas → screen inventory + every screen on a Design canvas (desktop 1440 + phone 390), approved
design-md-to-app → full scaffold + /showcase (phase=scaffolded; refused before the approval)
6. screenshot-to-page → /clients, /appointments, … (phase=page_generated)
7. module-add db → Drizzle + Neon
8. module-add auth → better-auth
9. product-to-agent-skill → skills/<slug>/SKILL.md (only if your API is public)
Step 9 is the one people don't know exists. When the product ends up with an API that somebody else's coding agent could drive, dev-flow says so once and offers to write your product's own agent-skill — the file your users install to run your product from Claude Code or Cursor. It lands in your repo, ships with it, and is never added to this one. Skipped entirely when the API only serves your own pages.
Check progress at any time:
$ python3 ~/.claude/skills/dev-flow/scripts/show_state.py .
Project: 'Vet CRM' ('vet-crm')
Phase: scaffolded
Stack: framework=next, ui=shadcn
Skill runs: 4
- prd-from-idea → phase=prd_drafted
- image-to-design-md → phase=design_extracted
- url-to-design-md → phase=design_extracted
- design-md-to-app → phase=scaffolded
Next step proposal: screenshot-to-page OR module-add
End-to-end time: ~25 minutes if Neon credentials are ready, ~10 minutes with placeholder env values.
DESIGN.md — skip straight to scaffoldSituation: you wrote a DESIGN.md by hand (or copied from another project) and want to scaffold immediately.
mkdir my-app && cd my-app
mkdir .workflow
cat > .workflow/DESIGN.md << 'EOF'
# My App Design System
## Color Palette
- primary: #0066cc
- background: #ffffff
- on-surface: #111827
## Typography
- display: Inter, 48px, 600
- body: Inter, 16px, 400
...
EOF
In Claude Code:
"Use this DESIGN.md to scaffold the app. Next + shadcn."
design-md-to-app starts directly from phase=design_extracted, skips PRD/tasks (the DESIGN is already there), and produces:
package.json, app/, components/site/, lib/server/, lib/queries/registry.json (token-first shadcn install)app/showcase/page.tsx with 9 sectionsapp/error.tsx, app/loading.tsx, lib/env.ts (Zod-validated), next.config.ts (security headers)screenshot-to-page and module-addSituation: you have a Figma URL and want to extract the design system.
mkdir ~/projects/aether && cd ~/projects/aether
In Claude Code:
"Extract the design system from this Figma file:
https://www.figma.com/design/<file-key>/Aetherfield"
figma-to-design-md picks the first available access path:
| Path | When it fires | Quality |
|---|---|---|
| A — Figma Dev Mode MCP | A mcp__figma* tool is exposed in this session | High — uses real variables + styles |
| B — Figma REST API | FIGMA_ACCESS_TOKEN is set, OR you provide a personal access token when asked | Medium-high — variables + styles via /v1/files/<key> |
| C-bis — Playwright-assisted | Browser MCP available but no Figma access — opens the file in a headless browser, screenshots key frames, runs k-means on the pixels | Medium — palette inferred, typography from rendered text |
| C — Manual export | Nothing else available — guides you to export PNGs + (optional) Tokens Studio JSON | Lower, but always works |
The skill tells you explicitly which path it's using:
$ "Using Path A — Figma MCP, found mcp__figma__get_file"
$ "Using Path B — REST API with token from env"
$ "No Figma access. Falling back to Path C-bis with Playwright."
Path B example (most common — you have a token but no MCP):
export FIGMA_ACCESS_TOKEN=figd_xxx
"Extract design from
https://www.figma.com/design/<file-key>/MyProject"
The extraction produces:
.workflow/DESIGN.md (Google design.md spec).workflow/screenshots/<frame-name>.png (2–3 reference frames).workflow/_design-md-mapping.json recording which path was used + any fallbacksIf Path A/B couldn't read typography (rare), the skill stops and asks instead of inventing weights — typography is non-negotiable.
Situation: you have a screenshot of a UI and want it as a real route.
Drop the screenshot in .workflow/screenshots/dashboard.png, then:
"Turn
dashboard.pnginto/dashboard."
screenshot-to-page picks the verification mode based on the kind of route:
| Route shape | Mode | Target | Iter cap |
|---|---|---|---|
/dashboard, /settings, /clients/<id>, anything CRUD | structure-first (default) | ≤ 8% delta, token-correct | 3 |
/, /pricing, /about, /sign-up, marketing/landing | pixel-tight (opt-in) | ≤ 2% delta | 8 |
Why two modes: pixel-tight on dashboards produces rigid HTML that imitates pixels instead of respecting tokens. The next developer can't tell which spacing was a design choice and which was an LLM matching one pixel. For brand-critical surfaces (heros, pricing), the inverse is true — fidelity IS the value.
The skill states the chosen mode in its hand-off:
"Iterated in
structure-firstmode (3 passes, final delta 6.4%) — token-correct, semantically clean. Switch to pixel-tight if you want closer fidelity for production."
Situation: you edited .workflow/DESIGN.md by hand (changed primary from blue to purple) after the app was already scaffolded.
$ python3 ~/.claude/skills/dev-flow/scripts/check_drift.py . --plan
✗ .workflow/DESIGN.md image-to-design-md self-drift
⚠ registry.json design-md-to-app upstream-stale
⚠ app/showcase/page.tsx design-md-to-app upstream-stale (transitively via registry.json)
Migration plan (re-run these skills, in order):
image-to-design-md:
✗ .workflow/DESIGN.md (self-drift)
design-md-to-app:
⚠ registry.json
⚠ app/showcase/page.tsx
Run the skills in the order shown — each one's outputs will refresh
the artifacts and clear the drift downstream.
You know exactly what to re-run and in what order. Drift propagates transitively through derived_from chains.
This is the use case the linear phase enum could not handle — the system now models the actual iterative workflow of product development.
Situation: scaffold is running. You want a database, then auth, then payments.
"Add a database."
module-add checks prerequisites, picks the default (Drizzle + Neon), installs:
drizzle-orm, @neondatabase/serverless, drizzle-kitlib/db/schema.ts with tenant-scoped indexes, uniqueIndex, soft-delete archivedAt convention, RLS docsdrizzle.config.ts, lib/db/index.tspnpm db:push / db:migrate / db:studio scripts in package.jsonDATABASE_URL in .env.local.example"Add auth."
Detects stack.db = neon-drizzle, picks better-auth as the default:
lib/auth.ts, lib/auth-client.ts, app/api/auth/[...all]/route.tslib/auth-server.ts with getCurrentUserId() / getCurrentTenantId() helpers — replaces the stubs in lib/server/<domain>.tslib/db/schema.tsBETTER_AUTH_SECRET, BETTER_AUTH_URL env vars"Add payments."
Stripe with subscriptions + one-time:
lib/stripe.ts (server SDK with pinned apiVersion), lib/stripe-client.ts (memoized loader)app/api/stripe/webhook/route.ts (signed receiver, idempotent handler) + /portal redirectapp/billing/page.tsx reference UIsubscriptions table in Drizzle schemastripe listen --forward-to localhost:3000/api/stripe/webhook during devSame shape for module-add email (Resend + React Email), module-add test (Vitest + Playwright), module-add ci (husky + GH Actions). Re-running is idempotent — the skill detects existing installs and skips.
Situation: you want to build your own tool — a CLI, a Cursor extension, a different LLM agent — that reads/writes .workflow/.
pip install -e ./contract-package # while not on PyPI yet
from pathlib import Path
from dev_flow_contract import (
init_workflow, record_artifact, set_phase, append_history,
check_drift, Phase
)
root = Path("./my-project")
init_workflow(root, name="My Project")
# After your tool writes a file:
(root / ".workflow" / "DESIGN.md").write_text("# Design")
record_artifact(root, ".workflow/DESIGN.md", produced_by="my-extractor")
# Bump the phase + record the run:
set_phase(root, Phase.DESIGN_EXTRACTED)
append_history(
root,
skill="my-extractor",
inputs={"source_url": "https://..."},
outputs=["DESIGN.md"],
phase_after=Phase.DESIGN_EXTRACTED,
)
# Later, check what's stale:
report = check_drift(root)
if report.has_drift:
for row in report.rows:
if row.status != "fresh":
print(f"{row.path}: {row.status}")
dev-flow is MIT and works offline. It is also allowed to say that somebody else's skill exists when a project reaches a point where one would help — the way a colleague tells you which tool down the hall does the thing you just asked for.
That list lives in dev-flow/references/external-skills.md,
and four rules keep it from turning this repo into a paid product:
npx skills add for you,
nothing external goes into install.sh, and no skill here imports or requires one.Nothing in that file is a dependency: delete every row and dev-flow does exactly
what it did before. The first entry is
sleekdotdesign/agent-skills —
a mobile-design service worth mentioning to somebody on the Expo stack who has no
design and does not want to write a DESIGN.md, alongside the note that our own
DESIGN.md path costs nothing.
One entry is free and used as-is: Matt Pocock's
resolving-merge-conflicts (MIT) — read both sides'
primary sources before a hunk, keep both intents, invent nothing, run the checks. What it cannot
know about a dev-flow project lives in
dev-flow/references/merge-conflicts.md: which files
are derived and must be regenerated, not merged (pnpm-lock.yaml, registry.json,
registry-lock.json and its snapshots, AGENTS.md managed blocks, generated migrations, the 38
vendored contracts.md copies), meta.json resolved field by field with the further phase applied
through set-phase so the gates rerun, a lint cap conflict taking the lower number — and two
overrides to its last step: stage by name, never git add -A, because other agents share these
trees; commit only a merge the user asked for.
agent-guardscontract-package is a package you install. agent-guards/ is the
opposite and deliberately so: a file that gets copied, not depended on.
It holds the four mechanical defences an agent needs when its tools return text nobody at your company
wrote — fence the result, gate writes on provenance, bound what memory accepts, refuse in the result
instead of throwing. TypeScript, one file, zero dependencies, nothing importing eve. The eve-agent
skill writes it into a project at agent/lib/guards.ts, the same way shadcn writes a component:
the code lands in your repository and you own it.
It was a published package for about an hour, and that was the wrong shape for this repo. A dependency means a version to bump and a lockfile entry in every project, for four functions any project may legitimately want to tune — the fence label, the blocked patterns and the cap are domain decisions.
What a dependency buys is not drifting, and the toolchain buys it instead. CI runs 29 tests on Node 20, 22 and 24, then removes one defence and requires the suite to notice. The linter's check 15 fails if the copy the skill hands out differs from the source CI tested by a single byte. So what lands in a project is what was tested, and an upstream improvement arrives as a re-copy and a readable diff rather than a silent version bump.
That remove-a-defence check is also how one test was caught being vacuous: it asserted the absence of an ASCII turn marker, which also held when the Unicode fold never ran and the text stayed fullwidth.
agent-guards is code the skills hand out. Bottega is the opposite direction: an app built from
the skills, whose only job is to run and be wrong in public.
It is the TypeScript answer to Anthropic's Python commerce-agents —
one Next.js app, two assistants over one shop: a shopping assistant that cannot buy anything
(checkout renders the cart and hands off) and a desk assistant that cannot write anything (every
change is staged and waits for a person to press Apply). Both sides read the same catalogue, and
which tools a caller gets is decided by the authenticated principal, never by the URL they opened.
The point is not the demo. A written convention cannot fail; a running one can, and everything below was returned by running it rather than by reviewing it:
| What broke | Why prose missed it |
|---|---|
The shopping assistant's first move was bash running env | grep | The skill documented how to call disableTool(). It never said a user-facing agent must, so nobody did. → eve-concepts.md now scaffolds the sentinels |
| The agent arrived with no tools at all and told the shopper so | Executors were inline, as the rule required — and still captured a per-session arrow. eve skips the whole resolver result and logs one line. → the rule is now two rules |
| The chat rendered nothing on a clean 200 | The field is messageDelta, not delta. Silent by construction. → a caveat on the "use useEveAgent()" advice |
| The cart accepted an item and rendered empty | Next evaluates a module in more than one graph; the route handler and the page held separate stores |
append-history accepted a phase that does not exist | Found before a line of app code was written, by using the contract for real |
Two of those are security findings, and neither was a subtle one — they were simply invisible to
anything that reads a skill instead of running it. The same loop found the fence's JSON-escaping hole
(\\n boundaries, not just real newlines) and the missing optimistic-concurrency half of the apply
check, both of which now live in agent-guards and its template.
The dev-flow Claude Code skills are interchangeable consumers of this package. Tomorrow you can rewrite any of them in TypeScript, swap one for a Cursor variant, or extend with your own — as long as your tool reads/writes the contract correctly, it composes.
Situation: an agent that is not Claude Code — v0, Codex, an eve agent in Slack, a hosted
assistant — needs one of these skills for a single job, and cannot run ./install.sh.
Every SKILL.md here is a conforming Agent Skill and this repository is public, so each one already
has a stable raw URL:
https://raw.githubusercontent.com/lukedj78/dev-flow/main/<skill>/SKILL.md
Point the agent at that and it has the skill. Vercel does the same thing with
vercel.com/design.md — a single public file their agents load to
produce on-brand pages from tools that have no access to the repository.
Two limits worth knowing before relying on it:
references/ do not come along. A SKILL.md that says "see references/contracts.md" is
giving the agent a relative path it cannot resolve from a raw URL. Either fetch the reference
explicitly at its own raw URL, or use the packaged dist/<skill>.skill bundle, which carries
every file.main is a moving target. For anything you want to be reproducible, pin the URL to a commit
SHA instead of main — the same reason a lockfile exists.The counterpart pattern from the same Vercel piece is worth taking too: judgement in prose, the
mechanics in an artefact the agent never reads. Their skill carries the design reasoning; the
published stylesheet carries the class names and tokens and loads in the browser, and the skill
explicitly forbids reading its implementation into context. The agent cannot drift what it never
sees. Our equivalent is the generated theme layer — once design-md-to-app has written it, the
downstream skills consume its names and must not invent new ones.
dev-flow is designed to be runtime-portable. The contract (.workflow/) is just JSON + Markdown + folders, the helper scripts are pure Python, and the skill bodies are tool-name-agnostic prose. The only Claude Code-specific bit is the discovery mechanism — and that's solved per-runtime by a small bootstrap file.
| Runtime | Install path | Bootstrap | Status |
|---|---|---|---|
| Claude Code | ~/.claude/skills/ | none — auto-discovered | ✅ fully tested |
| Codex CLI (OpenAI) | ~/.codex/dev-flow-skills/ | AGENTS.md (auto-copied) | 🧪 scaffolded, not yet validated end-to-end |
| Copilot CLI (GitHub) | ~/.config/gh-copilot/skills/ | none — skill tool auto-discovers | 🧪 scaffolded |
| Gemini CLI (Google) | ~/.gemini/skills/ | GEMINI.md (auto-copied) | 🧪 scaffolded |
| Cursor | ~/.dev-flow-skills/ | .cursorrules (auto-copied) | 🧪 scaffolded |
| Generic (any LLM agent) | ~/.dev-flow-skills/ | system-prompt.md (manual integration) | 🧪 scaffolded |
🧪 scaffolded means: the install path + bootstrap file are wired and tested for shape — scripts/test_install.py installs, reinstalls and uninstalls on every runtime in the table, in CI on Linux and macOS — but full end-to-end runs against the real runtime haven't been validated yet. If you try one and hit issues, please file an issue — happy to iterate.
Tool-name mapping — the skill bodies use Claude Code names (Bash, Read, Edit, Glob, Grep). The bootstrap/tool-mappings.md reference (installed alongside the skills) is the canonical Claude → Codex → Copilot → Gemini → Cursor equivalence table. The LLM reads it once at session start and translates as it goes.
Bootstrap files for runtimes that don't auto-discover skills. They also say what does not port: the two guards that are Claude Code hooks (registry intake's install check, the write-time primitives guard) do not run on another runtime — the lint, registry_intake.py check and the set-phase gates still catch what lands, after the fact:
bootstrap/templates/AGENTS.md — Codex CLI entry pointbootstrap/templates/GEMINI.md — Gemini CLI entry pointbootstrap/templates/.cursorrules — Cursor entry pointbootstrap/templates/system-prompt.md — generic system-prompt fallback for custom agentsdev-flow-contract Python package — the contract as a library, independent of any runtime, for reading .workflow/, recording artifacts and checking drift. It does not run the phase gates, so phase moves still go through update_meta.py (item 4):
from dev_flow_contract import init_workflow, record_artifact, check_drift
Agent-agnostic helper scripts — init_workflow.py, update_meta.py, check_drift.py. They're invoked by shell, so every runtime can use them via whatever shell tool it has.
Six recipes — install once, then per-project. Same skill content, same .workflow/ contract, different loading mechanism.
Install once:
git clone https://github.com/lukedj78/dev-flow.git
cd dev-flow
./install.sh
Use it on any project:
mkdir ~/projects/my-app && cd ~/projects/my-app
claude # open Claude Code here
Then say:
"I want to build a CRM for veterinary clinics."
Auto-discovery picks the skills from ~/.claude/skills/, dev-flow orchestrator routes. Nothing to configure per project.
Install once:
./install.sh --platform codex
# → ~/.codex/dev-flow-skills/ + ~/.codex/dev-flow-skills/AGENTS.md
Per project:
mkdir ~/projects/my-app && cd ~/projects/my-app
cp ~/.codex/dev-flow-skills/AGENTS.md .
codex
Codex reads AGENTS.md at session start. The template tells it where the skills live, how to translate Claude tool names to Codex equivalents (Bash → shell, Edit → apply_patch), and how to update meta.json after each step.
"I want to build a CRM for veterinary clinics."
Minimal variant (if you don't want to copy AGENTS.md to every project):
echo "Load instructions from ~/.codex/dev-flow-skills/AGENTS.md" > AGENTS.md
Install once:
./install.sh --platform copilot
# → ~/.config/gh-copilot/skills/
No per-project bootstrap — Copilot CLI auto-discovers skills like Claude Code.
cd ~/projects/my-app
gh copilot suggest "I want to build a CRM for veterinary clinics"
Verify the install:
gh copilot skills list | grep dev-flow
Install once:
./install.sh --platform gemini
# → ~/.gemini/skills/ + ~/.gemini/skills/GEMINI.md
Per project:
mkdir ~/projects/my-app && cd ~/projects/my-app
cp ~/.gemini/skills/GEMINI.md .
gemini
Gemini reads GEMINI.md at session start. Skills are activated via activate_skill when a trigger pattern matches.
"I want to build a CRM for veterinary clinics."
Install once:
./install.sh --platform cursor
# → ~/.dev-flow-skills/ + ~/.dev-flow-skills/.cursorrules
Per project:
mkdir ~/projects/my-app && cd ~/projects/my-app
cp ~/.dev-flow-skills/.cursorrules .
cursor .
Open Cursor's chat (Cmd+L) and say:
"I want to build a CRM for veterinary clinics."
Honesty caveat: Cursor doesn't have a native skills system. The skills become prompt augmentation loaded via .cursorrules — not auto-routing. Quality depends on how well Cursor follows the rules; on long sessions it can drop references. Works better if you guide explicitly: "Use the prd-from-idea skill to draft a PRD."
Install once:
./install.sh --platform generic
# → ~/.dev-flow-skills/ + ~/.dev-flow-skills/system-prompt.md
Prepend system-prompt.md to your agent's system prompt. Examples:
LangChain
from langchain.prompts import SystemMessagePromptTemplate
with open("/Users/you/.dev-flow-skills/system-prompt.md") as f:
dev_flow_prompt = f.read()
system_msg = SystemMessagePromptTemplate.from_template(
dev_flow_prompt + "\n\nYou are a coding assistant…"
)
OpenAI Assistants API
from openai import OpenAI
client = OpenAI()
assistant = client.beta.assistants.create(
name="My Dev Agent",
instructions=open("/Users/you/.dev-flow-skills/system-prompt.md").read(),
tools=[{"type": "code_interpreter"}],
model="gpt-4o",
)
The agent must have:
~/.dev-flow-skills/ (so it can read SKILL.md files).init_workflow.py, update_meta.py, check_drift.py).Without both, the contract operations don't work.
These are runtime-agnostic — every platform calls them via shell:
# Show project state
python3 ~/.<platform>/<skills-dir>/dev-flow/scripts/show_state.py .
# Detect drift after manual edits to contract files
python3 ~/.<platform>/<skills-dir>/dev-flow/scripts/check_drift.py . --plan
Or, from any Python runtime that installed the contract package:
pip install -e ~/dev-flow/contract-package
from dev_flow_contract import init_workflow, check_drift, record_artifact
| If… | Use | Why |
|---|---|---|
| You want zero-config + best auto-routing | Claude Code | The skills were designed for it; matching is unambiguous |
| You're already on the OpenAI CLI / prefer OpenAI models | Codex CLI | Solid AGENTS.md support, but you'll need to validate (not e2e tested) |
You work in GitHub repos and want everything via gh | Copilot CLI | Auto-discovery + natural fit with git/PR workflows |
| You want Google models / huge context windows | Gemini CLI | 1M+ token context useful on big projects |
| Your IDE is Cursor and you don't want to switch tools | Cursor | No tool-switch, but routing is weaker — you'll be more explicit |
| You're building a custom agent | Generic | system-prompt.md is the smallest possible starting point |
Honest disclaimer: today only Claude Code has been tested end-to-end. The other 5 are scaffolded — install paths and bootstraps are wired, but full project runs haven't been validated. If you try one and it works, open an issue so the support matrix can be updated; if it doesn't work, also open one — fixes come from feedback.
If your agent runtime isn't in the matrix:
bootstrap/templates/system-prompt.md.bootstrap/tool-mappings.md (PRs welcome).install.sh's platform switch.The skill bodies and the contract don't need to change — only the bootstrap layer.
🌐 lukedj78.github.io/dev-flow — the browsable index, one page per skill. Generated from the taxonomy by scripts/build_site.py; --check keeps it from going stale.
📐 Architecture — the .workflow/ contract, the meta.json schema, the phase enum, file conventions.
🛠 Conventions — folder layout (components/site/ vs app/<route>/_components/), server actions in lib/server/<domain>, theme system with keyboard shortcut, showcase template.
📚 Case studies — three projects built with the suite (Aetherfield editorial, Notarius CRM, Wisely fintech). Each shows which skills were used and what was generated.
🤖 Full walkthrough — one product ("Helmsman" AI support desk) exercising every skill, phase by phase: core → design → monorepo → web → mobile → agent (eve) → voice/realtime → deploy.
🔁 Loop engineering — runbook for an autonomous Linear → Claude Code → PR loop on a Hetzner server (the harness that repeats one dev-flow iteration). Project-agnostic; eve is one optional payload.
📇 Knowledge index — the map of every doc-grounded how-to: which domain, which reference, which upstream to re-verify. Start here when wiring a library or running a knowledge refresh.
🧠 Obsidian — this repo is also an Obsidian vault (config committed): graph view over skills → references, backlinks, full-text search across every skill.
<skill-name>/ one folder per skill, FLAT at the root
├── SKILL.md the skill (frontmatter: name + description)
├── references/*.md its doc-grounded how-tos, recipes, vendored contract
└── scripts/* its executable helpers + tests
docs/ cross-cutting docs, knowledge index, assets
scripts/ repo tooling (registry + manifest + bundle builders, linter)
dist/ generated <skill>.skill bundles (one per skill)
.claude-plugin/ plugin.json (generated) + marketplace.json — plugin distribution
.out-of-scope/ decisions not to build, with what would change our mind
.obsidian/ committed vault config (see docs/OBSIDIAN.md)
bootstrap/ contract-package/ evals/ templates, the contract as a package, eval fixtures
README.md · CONTEXT.md (glossary) · CHANGELOG.md · install.sh · uninstall.sh · skills.json
Why the skill folders are flat, not nested by family. The root mirrors the install target (~/.claude/skills/<name>/) one-to-one, keeps ~385 cross-skill reference paths valid, and matches what Claude Code / Codex / Gemini expect. The six-family grouping is logical, not physical: it lives in the TAXONOMY map in scripts/build_skills_registry.py and is published in skills.json. That map is the single source of truth for family + role — a skill missing from it is a build error, never a silent default, so the counts here and in install.sh can't drift out of sync again.
9 skills are stack-agnostic core:
dev-flow,prd-from-idea,prd-to-tasks,project-infra-setup,scrum,compliance-audit,spec-review,product-to-agent-skill, andregistry-intake— all three stacks use them. The 15 web-stack skills assumemeta.json#stack.framework="next"(andstack.nextjs_version="16"— Pages Router and pre-16 are refused); the 2 agent-engine skills (eve-agent,eve-registry-porting) assumestack.agent="eve"; the 16 mobile-stack skills assume"expo-rn"; the 4 monorepo-stack skills assume"monorepo". The 2 refactor skills (promote-component,composition-patterns-guide) are stack-agnostic and work across all three.dev-flowreads that key and routes.
dev-flow — the orchestratorWhen to use it: when you want to not think about which skill comes next. Paste an idea / a Figma URL / images, and dev-flow figures out the right specialist to invoke based on phase in meta.json.
phase=empty → prd-from-idea
phase=idea_captured → prd-from-idea (expand)
phase=prd_drafted → branches by stack.framework:
"next" → prd-to-tasks OR figma-to-design-md OR
image-to-design-md OR design-md-to-app
"expo-rn" → rn-bootstrap (mobile scaffold)
phase=tasks_split → figma-to-design-md OR image-to-design-md OR design-md-to-app
phase=design_extracted → "next" → design-md-to-app
"expo-rn" → rn-bootstrap
(entering scaffolded is gated for web: the design lint must be wired)
phase=scaffolded → "next" → screenshot-to-page OR module-add
"expo-rn" → rn-add-screen OR rn-module-add OR rn-write-tests
phase=page_generated → module-add (next) OR rn-module-add (expo-rn) OR more screen-gen
phase=module-added → write-tests / rn-write-tests OR iterate
→ eventually the stack's deploy skill, once feature-complete
phase=feature_complete → gates: compliance-audit (any stack) + vercel-doctor (web on Vercel)
+ shadscan (web on shadcn) + launch-audit (web)
+ app-security (any stack)
"next" → vercel-deploy
"expo-rn" → rn-eas-deploy
eve agent → eve deploy
phase=deployed → debt audit first (dev-flow: every audit + the tests, one ordered list)
"next" → maintenance loop: screenshot-to-page / module-add,
re-run the gates after material changes
"expo-rn" → maintenance loop: rn-add-screen for new features,
rn-eas-build-submit-update for OTA hotfixes
dev-flow does not do specialist work itself — it only routes and updates state. If you find it doing PRD drafting or scaffolding directly, that's a bug.
Bundled scripts:
scripts/init_workflow.py <project-root> [--name "Project Name"] — creates .workflow/ with a fresh meta.json.scripts/show_state.py <project-root> — prints current phase, files present, proposed next step. On a project already past scaffolded without the design lint, it prints what is missing and the command that fixes it.scripts/update_meta.py <project-root> set-phase <phase> — moves the phase forward, refuses regression, and holds the phase gates (the same list for append-history --phase-after): the inventory to leave idea_captured, the wireframe canvas to reach monorepo_initialized or scaffolded, and three more at scaffolded. The design-lint gate refuses it until design-md-to-app/scripts/setup_design_lint.py --check passes or stack.design_lint = "none" is recorded with stack_config.design_lint_reason (mobile, agent-only and MUI projects are not affected). The registry-intake gate refuses it, for a Next app on a Tailwind UI or an eve agent, until registry-intake/scripts/registry_intake.py check passes or stack.registry_intake = "none" is recorded with stack_config.registry_intake_reason. A third gate, for the same Next apps on a Tailwind UI, refuses scaffolded and every later phase until the design lint carries design/no-handmade-ui and the write-time primitives guard is installed (scripts/primitives_guard_gate.py, checked through design-md-to-app/scripts/setup_primitives_guard.py --check) or stack.primitives_guard = "none" is recorded with its reason. Skills move phase through it so the gates run.scripts/debt_audit.py collect <project-root> — after deploy, every audit the project has (app-security, compliance, launch-audit, observability, registry-intake, promote-component, the last shadscan and vercel-doctor runs, the prose recipes) plus a test check (code that writes data and no test reaches; coverage when it exists), in one list ordered into before the next release, with the features that touch these files, later. What it could not see is listed as not checked, never as clean; scanner signals stay to confirm until reviewed. Proposed by show_state.py from deployed and after every material change. Writes docs/debt/debt-audit.md and meta.json#debt_audit.founder-intelligence — is it worth building? (optional)For a commercial idea whose market is not settled, the alternative door to the inventory step: research, an adaptive founder interview, competitors by tier, a customer-discovery kit and the synthesis of real interviews (never simulated), business model, MVP boundaries and the metrics decided before launch, feasibility with what already exists to reuse, go-to-market and a validation roadmap. All of it lands in .workflow/founder/founder-playbook.md, every claim tagged [source], [founder], [interview], [estimate] or [hypothesis]. No PRD until the founder approves it: once the path has started, update_meta.py set-phase refuses prd_drafted until founder.py approve --user-said "…" records their words and the Playbook's hash (an edit afterwards needs a new approval), or the path is bypassed with a reason. Then prd-from-idea builds on the Playbook instead of re-asking. Prototypes, refactors and internal tools keep the direct path, unchanged. On an existing project it produces proposed PRD changes (handoff.md). Method adapted from Anthropic's The Founder's Playbook (May 2026).
prd-from-idea — paragraph → PRDInput: a paragraph or two describing what you want to build. Output:
.workflow/PROJECT.md — strategic brief (audience, problem, value prop, success criteria)..workflow/PRD.md — product requirements (user stories, acceptance criteria, non-goals, open questions).How it works: the skill asks you 5–8 high-leverage questions, parses your answer, fills the templates. It refuses to invent: if you can't answer "who is this for", it writes <TBD — needs user input> rather than guess.
Two of those answers shape what comes after the PRD. ## Scope rules — three lines: what evidence lets a new feature into the MVP, what stays out before launch whatever the evidence, and who decides — checked by scripts/scope.py check, and used later by the scope check every mid-build feature request goes through. The tracker — Linear, Jira or GitHub — recorded in meta.json#tracker.provider, where scrum will run the sprints.
project-infra-setup — the third-party environments, from the CLIEverything outside the codebase that a project needs before module-add can wire it: the GitHub repo, the Vercel project and its region, the connectors (Neon, Blob, Resend), DNS and domains, environment variables and secrets, and the sub-processor register. Each outward step is confirmed one at a time; secrets never go through chat; the region of every service is checked before and after it is created; whatever a tool installs on its own is reviewed first. Written from the BidFlow run. See project-infra-setup/SKILL.md.
prd-to-tasks — PRD → executable checklistInput: .workflow/PRD.md (and .workflow/PROJECT.md for context).
Output: .workflow/tasks.md with 1 task per - [ ] checkbox. Compatible with beads, GitHub Issues import, Linear CSV, ralph-tui.
Sizing: each task ≈ 2–8 hours of focused work. If a task is bigger, the skill splits it. If smaller, it merges with a sibling. Output ≤ ~15 tasks for an MVP.
wireframe-canvas — every screen, drawn and approved, before any codeThe step between design_extracted and the scaffold, on every project with a UI. First docs/wireframes/screen-inventory.md: every route and screen of every epic, mapped to the PRD's US-N stories, with roles and loading/empty/error/success states, checked so that every story maps to at least one screen. When there are public screens, a page argument first (docs/wireframes/page-argument.md): eight to twelve things only this client has, the idea sentence with the competitor test, and one claim with its proof per section — a section with no claim is cut, proof is never invented; wireframes.py argument checks it and approve requires it. Then one desktop (1440) and one phone (390) artboard per screen on a claude.ai Design canvas, high fidelity in DESIGN.md with real copy, one canvas page per area, reviewed area by area. update_meta.py set-phase refuses the scaffold until the user approves it (or a skip is recorded with its reason). After approval every artboard becomes a PNG in docs/wireframes/png/, commented on each GitHub or Linear issue whose story maps to the screen. Records meta.json#wireframes. See wireframe-canvas/SKILL.md.
product-to-agent-skill — your product → an agent-skill its users installInput: a dev-flow project whose API is callable by something other than its own frontend — route handlers under app/api/, an OpenAPI spec, a public eve agent, an MCP server — plus a deployed origin.
Output: skills/<slug>/SKILL.md in the product's repo, plus the README row and the npx skills add owner/repo line for the product's users. Records meta.json#stack.agent_skill; no phase bump.
Why: an API only its own frontend calls is an implementation detail. One a coding agent could drive is a distribution channel, and it needs exactly one artefact to become usable — a runbook telling that agent how the product works. sleekdotdesign/agent-skills is the proof: a design service published one 563-line SKILL.md and became drivable from Claude Code, Cursor and Codex without shipping an SDK for any of them. references/anatomy.md is what that file taught us, section by section — device flow before raw keys, the loop before the endpoint catalogue, the price stated before any step that leads to a payment page, and a common-mistakes table that can only be written by having driven the thing.
⚠️ The output belongs to the product, not to this repo. It ships and versions with that product and is aimed at whoever installs it. It is never added to dev-flow's own skills, never copied into ~/.claude/skills/, never listed in install.sh — the same relationship dev-flow has with the app/ it builds and does not own. dev-flow raises it once, at feature_complete → deployed, and only when the surface is genuinely public: a skill describing an internal route handler is a lie with a nice table in it.
scrum — agile scrum on Linear, Jira or GitHubInput: .workflow/meta.json (+ .workflow/tasks.md for the first Setup) and the tracker chosen at design time (meta.json#tracker.provider, asked by prd-from-idea): Linear (its MCP), Jira (the Atlassian Rovo MCP; story points through scripts/jira_estimate.py, token from the environment) or GitHub (gh; scripts/github_sync.py).
Output: the project's issues — estimated, prioritised, labelled, written to the issue standard — and 2-week sprints (Linear cycles, Jira sprints, GitHub milestones named by their goal), plus meta.json#tracker (issue map keyed by task_key) and #scrum. The tracker is the source of truth: Sync pushes only new tasks and pulls status and velocity.
Modes: Choose, Setup, Adopt (an existing project, backfilled), Sync (push new tasks, plan the sprint, report), Triage (a bug: reproduce, severity S1–S4, the issue in the right sprint — the fix is the normal path). scripts/meta_tracker.py migrate moves every older shape — linear-scrum's linear block, hand-written GitHub blocks with a title-keyed map — into tracker without dropping a key.
registry-intake — third-party registry components: allowlisted, reviewed, pinned, enforcedInput: a project with a components.json (or an eve agent) and an item from a shadcn-format registry — @ns/item, a registry-item URL, eve add @ns/….
Output: registry-lock.json (allowlisted registries with their reason; approved items with snapshot hash, reviewer, findings and accepted exceptions), vendor/registry/ snapshots, a PreToolUse hook in .claude/settings.json, an AGENTS.md block, and meta.json#stack.registry_intake = "enforced". Wired at scaffold by design-md-to-app, monorepo-bootstrap and eve-agent; checked by set-phase scaffolded.
Why: shadcn add @ns/item copies someone else's source, installs their npm packages, can write env vars and theme tokens, and fetches whatever the URL serves today — then the code is ours and nothing updates it. The community registries are worth mining (shadcn-labs alone ships pdfcn, emailcn, ogimagecn, mcpcn, agentcn), and they are young, mostly one-maintainer, sponsor-funded projects. The review in scripts/registry_intake.py exists because of what was found by hand on 2026-09-15: every eve tool in agentcn declares needsApproval, a key eve's loader rejects (verified in eve 0.34, 0.51 and 0.55) — so the five tools meant to ask before acting have no gate, and claw/run_shell runs node:child_process on the host. Run against the live registries, the review blocks exactly those (V1, V2, S1), passes an ogimagecn template clean, and resolves a pdfcn card's registryDependencies into a two-item snapshot whose dependency paths point at the vendored copy.
npm facts are read with the history a name hides. A name that changed hands — two years of silence, then a different repository and no maintainer in common — is D8, and its age (D5) counts from the new owner's first release. cn 0.1.x was a 2013 joke package and motion 5.0-beta was another project; both are now what our stack uses, checked and recorded. Under 1.0 a caret locks the minor, so cn@^0.2.4 does not accept 0.3.x (D7).
The agent always stops and asks before allow and approve: it runs the read-only review, shows the report, and waits for a yes to the registry and a yes to the item, whatever the tier and however hurried the prompt. --by names the person who said yes, never the agent or the OS login. This was measured, not assumed. With a looser wording, evals/compliance caught the agent allowlisting and approving itself in two sessions out of three, writing the operator's login into --by, so the lock recorded an approval nobody gave. The hook now answers "ask" on both commands, so the user gets a permission prompt even when the agent skipped the question.
Four barriers, each mechanical: an allowlist (a new registry is the user's decision, with a reason); a review of the item's whole closure — config/tooling targets, host process execution, obfuscation, env vars, theme tokens (DESIGN.md owns them), npm existence, licence, install scripts and age, and for eve code the tool keys the installed eve accepts, ungated side effects, global credentials, a shared store, US-shaped PII regexes; a snapshot installed with [email protected] instead of the URL (local items and root-relative registryDependencies verified on that version); and nothing around it — the hook denies every other shadcn add @…, URL install, eve add @… and eve registry add using the documented permissionDecision: "deny" contract, while check catches edited snapshots, stray vendor files, unlisted registries in any components.json, and a design-lint --max-warnings raised to make room for imported code. Blocking findings are fixed, ported by hand (eve-registry-porting), or accepted one by one with a written reason — never waved through. @coss is the one registry trusted live, and only when stack.ui = "coss". The rules are heuristics over source text, stated as such: typecheck, the capped lint, eve build and tests still run after install. 30 tests, no network, in CI.
compliance-audit — GDPR + EU AI Act audit & remediationInput: an existing dev-flow project (any stack — Next.js web, Expo mobile, or an eve agent) + .workflow/meta.json#stack.
Output: docs/compliance/audit-report.md (findings with severity · GDPR/AI-Act article · file:line evidence · fix), a meta.json#compliance block, and — in Remediate mode — the safe mitigations applied as reviewable diffs (DSAR export/erasure endpoints, cookie-consent banner + privacy pages, AI-transparency disclosure, PII-scrubbing logger + retention policy, a sub-processor register generated from stack) plus TODO(compliance) flags for the legal decisions.
How it works: scores the codebase against a fixed 11-point risk register (R1 DSAR · R2 consent/cookies · R3 EU data residency & transfers · R4 retention/TTL & PII-scrubbing · R5 AI-transparency Art. 50 · R6 high-risk Annex III/DPIA · R7 PII in logs · R8 sub-processors · R9 special-category data · R10 memory/manipulation · R11 client analytics before consent). scripts/scan.py is a fast first-pass signal; every hit is verified in code before it lands in the report. R4 has one dimension a code read cannot reach: scrubbing that exists and silently does not work. Where the scrubber is a model rather than a regex it can return zero findings on a document full of them and answer 200 — so the audit asks what the model was trained on versus what the product ingests, whether the checked rules outrank it, whether a zero-finding result is surfaced rather than read as a clean document, and whether a token limit is being crossed in silence. Auto-applies only the safe, mechanical fixes and flags every decision (which EU region, legal basis, whether high-risk) — it never decides law for you. Horizontal capability: run it any time; dev-flow proposes it as a pre-deploy gate at feature_complete and re-runs it in the deployed maintenance loop. Records meta.json#compliance, never bumps phase. Not legal advice — it produces engineering findings + a DPIA template; a DPO/counsel confirms.
The decision it audits is taken earlier. Where the data lives is decided at the stack decision, not discovered at the audit: dev-flow asks four questions (EU data subjects, sensitive categories, sector residency, CLOUD Act) and records stack.data_residency = eu · eu-sovereign · none with dev-flow/scripts/data_residency.py; every module-add / rn-module-add sets the provider's EU region and adds it to one register (meta.json#compliance.sub_processors → docs/compliance/subprocessors.md); this skill then checks the code against that record. A provider with no EU option is flagged with its transfer basis and never blocks — the phase gate only refuses an undecided residency. The how-to is dev-flow/references/eu-data-sovereignty.md: a table of 13 service categories with the default, its EU setting and European alternatives, each row sourced on the vendor's own page (2026-09-15), and the regulations with primary links and a re-verification cadence — including the AI Act as amended by Regulation (EU) 2026/1744 (Annex III high-risk from 2 Dec 2027, Art. 50 from 2 Aug 2026) and the pending DPF appeal C-703/25 P. Found on the way: Anthropic's own API has no EU inference, Resend's EU region moves sending but not storage, Firebase Auth runs only in the US.
app-security — can this code be attacked?The fifth pre-deploy gate, and the question none of the other four asks: can someone use this app to read or change what is not theirs? Three levels. A scan (scripts/scan_security.py) runs OSV-Scanner (or pnpm audit / npm audit), gitleaks and Semgrep when they are installed, plus eight Next.js checks of our own: Server Actions and mutating routes with no session call, queries by id with no owner filter, actions that return a raw row, secrets in NEXT_PUBLIC_, server modules without server-only, raw SQL, missing security headers. A review reads every flagged file, and every action and route, against an OWASP Top 10:2025 checklist (references/review.md), because a session check that never checks ownership passes every scanner. A dynamic level, only on request, runs Strix against the app on next start or a preview and reports only what an exploit proved (references/dynamic.md).
Two rules carry it. A tool that is missing, offline or unparseable reads not checked, never clean, and the report never calls a project clean. And nothing is installed without asking: the report prints the command. Records meta.json#security, with the user's reason on every risk they keep; never bumps phase, never blocks.
app-verification — prove it on the real app, with a manual written onceEvery agent that had to show a feature works on the running app started from nothing — how to start it, when it is really ready, which user to sign in as, where to look, how to stop without killing the user's own dev server — and what it learned was gone at the end of the session. This skill writes it down inside the project as a skill Claude Code finds by itself, .claude/skills/verify-<app>/: Launch, Doctor, Drive, Evidence, Cleanup, Isolation, and one feature file per PRD story. scripts/verify_map.py scaffolds the map from wireframe-canvas's screen inventory (screens, routes, roles, loading/empty/error/success states) or, without one, from the routes, and check refuses a manual with a gap. The agent fills it from the code and runs it once end to end before handing it over — a manual never run is a draft. A maintain pass re-reads every feature from source, drives them all live, fixes the manual and reports real regressions instead of hiding them. Adapted from pstack (Lauren Tan, MIT); nothing is committed in the user's project.
It also ships a render probe, scripts/render_probe.mjs: a URL in headless Chrome at 1440 / 768 / 390, measuring what no source scan can see — horizontal overflow with the element causing it, headings past two lines (per locale: Italian runs longer), text that stays invisible with reduced motion on, a font that never loaded, a broken image, a sidebar covering a phone, and the page jumping while it loads (layout shift, with the block that pushed — usually a skeleton that is not the size of what replaces it; design-md-to-app/references/skeleton-audit.md sizes skeletons to the measured UI). Node ≥ 22 and an installed Chrome, no dependency, and no file server: it takes the dev server's URL, so .env is never reachable from the page. The idea comes from taste-skill v2's inspector (MIT); the rules are ours.
figma-to-design-md — Figma → DESIGN.mdInput: a Figma URL (figma.com/file/, /design/, /proto/, /board/, /site/).
Output: .workflow/DESIGN.md (Google design.md spec) + .workflow/screenshots/ (HD captures).
3 access paths, picked automatically:
mcp__figma* tool is exposed.FIGMA_ACCESS_TOKEN env var is set.The skill validates the output against the Google spec before writing (frontmatter delimited correctly, colors.primary defined, no duplicate sections, dimensions in px/em/rem only, all {path.to.token} references resolve).
image-to-design-md — 1+ raster images → DESIGN.mdInput: 1 or more PNG / JPG / WebP images (screenshots of competitor apps, Pinterest pins, Dribbble shots, Figma exports).
Output: .workflow/DESIGN.md + .workflow/screenshots/<slug>.png for each image.
How it works:
scripts/quantize_palette.py); when there are multiple images, scripts/aggregate_palettes.py merges near-duplicates and rewards colors that recur across screens.fontFamily.components block with the variants seen.The skill is explicit about confidence: every guess is flagged in the prose. A 1-image input where text isn't visible produces a stub typography: block + a prominent note ("typography pending — supply a second image with visible text").
url-to-design-md — a live site or app → DESIGN.mdInput: a URL. A public site (site mode) or an app behind a login (app mode — the user signs in, the skill never handles credentials).
Output: .workflow/DESIGN.md + .workflow/design-source/ (snapshots, tokens.json, shadcn.css, the review page, the slides) + design-source.md, the record of what was changed and why.
How it works:
scripts/extract.js walks the rendered DOM and reads computed styles. A stylesheet declares what is possible; the DOM says what is painted — which is why this works on Tailwind and CSS-in-JS, where reading the source reports the framework's palette as the brand's.oklch() and lab() resolve to hex; text weighted by characters and grounds by painted area; consent banners excluded; roles carry the evidence that chose them.clamp() is derived rather than guessed, then mapped onto Tailwind's own slots (text-sm … text-9xl) — never a parallel set of semantic names.outline: none, which reads like a site with no focus ring); a ring is only accepted when the page declares a :focus rule, because otherwise it is the browser's own.brand-guide.html opens offline and carries the decisions the measurement could not settle, each with the evidence, a recommendation and what happens if nobody answers. render_decision.py draws each one side by side. Nothing is written until the user approves.verify.py reads the rebuilt controls' computed styles back and fails when one does not equal its token — a guide with one literal where a var() belongs looks perfect and has stopped representing the system.Nothing observed is nothing written: an unmeasured shadcn slot keeps its framework default and is named in the theme's header. Logos, font files and photographs are never copied.
design-md-to-app — DESIGN.md → working appInput: .workflow/DESIGN.md + .workflow/meta.json#stack.
Output: a fully scaffolded codebase at the project root (NOT inside .workflow/), with:
Framework installed (Next.js + Tailwind v4 by default; Vite + React, Remix, Astro variants supported via references/<framework>-<ui>.md).
shadcn/ui via the token-first registry approach: emits <root>/registry.json from DESIGN.md, runs pnpm dlx shadcn@latest init ./registry.json --yes, then pnpm dlx shadcn@latest add --all --yes. Every primitive lands in components/ui/ pre-themed.
shadcn CLI v4 awareness: picks the primitive base via stack.ui_base (base default — Base UI, shadcn's own default since 2026-07 | radix | aria for React Aria — shadcn create --base), plus icon library / CSS variables / RTL. If you built a config on ui.shadcn.com/create, pass the preset code as stack.shadcn_preset and the skill scaffolds with --preset instead of the DESIGN.md token install (preset XOR DESIGN.md-tokens). A confirmation gate prints the full resolved config and waits for your OK before scaffolding.
Theme system: next-themes + <ThemeProvider> + a <ModeToggle> button with a global D keyboard shortcut (excluded when typing in inputs).
Folder skeleton: components/<group>/ for cross-route shared, app/<route>/_components/ for page-scoped, lib/server/<domain>.ts for server actions, lib/queries/<domain>.ts for reads, hooks/.
Site-shell components: SiteTopNav, WordmarkFooter, MarketingShell for public pages; AppShell for authenticated routes; Eyebrow helper. Every label is a message (en + it) and every size a slot of the scale; the client's footer carries a legal row, never the generator's signature.
Anti-slop fallbacks for what the source leaves silent (references/anti-slop-fallbacks.md, adapted from taste-skill v1 and v2.1.1): sample data is realistic and logged, proof is never invented (no customer counts, ratings or logos the client did not supply); pictures come from the project, a real product fragment or a drawing before any placeholder; numbers and charts in app screens follow one rule set (a delta's colour says good or bad, , at most four hues, no gradient fill). counts every rule a reviewer could point at.
The structure is mandatory in dev-flow mode — see docs/conventions.md.
coss-ui — Coss/UI, the Cal.com design system on Base UIInput: a project that wants the Cal.com aesthetic, or meta.json#stack.ui = "coss".
Output: components installed from the namespaced @coss/* shadcn registry, with DESIGN.md tokens reconciled on top.
How it works: two modes — Init (shadcn init @coss/style on a new or empty project: components, the neutral colour system, sidebar variables, base styles, Inter + Geist Mono) and Add (pull @coss/ui, a single @coss/<name>, or particles into a project that already exists). Because Coss ships the same CSS variable names as shadcn/ui, the DESIGN.md → tokens pipeline works unchanged: your tokens override theirs in globals.css, no bridging layer.
It is a deliberate fourth choice inside the shadcn/Base-UI family, not a default, and it carries two caveats worth stating before you pick it: Tailwind CSS v4 is required, and the licence is mixed MIT / AGPLv3 (references/deps-and-license.md). Offer it when someone wants the Cal.com look or an AI-first Base UI kit; design-md-to-app still owns the generic scaffold, this skill owns the Coss-specific install and token reconciliation.
screenshot-to-page — screenshot → working routeInput: one image from .workflow/screenshots/ + DESIGN.md + meta.json#stack.
Output: a real route in the codebase (app/<route>/page.tsx) with extracted reusable components.
Workflow:
<Card> + map; 5 nav items → extract <NavItem>).scripts/visual_diff.py) → fix the worst region → repeat until delta < 2% (or 8 iterations).bg-muted placeholders with {/* TODO: replace */} comments — the skill doesn't fabricate photography.module-add — wire backend / infra modulesInput: a module name from the supported list.
Output: dependencies installed, config files written, a reference implementation at the canonical path, meta.json#stack updated, schema additions applied.
| Module | Tech | Status |
|---|---|---|
auth | better-auth (email/password + magic link) | ✅ shipped |
db | Drizzle ORM + Neon Postgres | ✅ shipped |
payments | Stripe (subscriptions + one-time + webhook + portal) | ✅ shipped |
email | Resend + React Email | ✅ shipped |
test | Vitest + Testing Library + Playwright | ✅ shipped |
ci | husky + lint-staged + GitHub Actions | ✅ shipped |
motion | Motion (rebranded framer-motion) + opinionated wrappers (FadeIn, StaggerList, MagneticButton) | ✅ shipped |
voice | Realtime voice over the Vercel AI Gateway (@ai-sdk/gateway + experimental_useRealtime); STT → agent → TTS topology | ✅ shipped (experimental API) |
realtime | App-level WebSockets (Vercel Functions experimental_upgradeWebSocket); presence / chat / collab, external store for shared state | ✅ shipped (experimental API) |
storage | Vercel Blob (default: server + client uploads, auth-gated, files table); UploadThing / S3 + presigned URLs as alternatives | ✅ shipped |
deploy | Vercel project config (link, vercel.json, per-environment env vars, EU region, monorepo root directory); vercel-deploy does the actual shipping | ✅ shipped |
analytics | Opt-in, by level, switchable on at any phase: traffic (Vercel Web Analytics + Speed Insights) · product (activation and D7/D30 retention from an analytics_events table in the project's own database, track() from server actions, no new sub-processor) · advanced on request (PostHog EU, OpenPanel for eu-sovereign). Needs the PRD's ## Measurement targets first. Expo: rn-module-add analytics | ✅ shipped |
The skill is idempotent: re-running module-add db on a project that already has it detects the install and skips, instead of double-installing. Cross-module dependencies are resolved automatically (auth requires db; payments requires both — the skill prompts before chaining).
write-tests — generate a test for one source fileInput: one source file path (lib/server/clienti.ts, app/clienti/page.tsx, components/site/site-top-nav.tsx, lib/queries/scadenze.ts).
Output: the corresponding test file, written next to the source or in e2e/, following the project's existing mocking conventions and test framework (Vitest / Playwright).
Trigger phrases: "scrivi i test per X", "test per la server action Y", "e2e per /clienti", "unit test per il componente Z".
| File pattern | Test type | Path |
|---|---|---|
lib/server/<domain>.ts | Vitest unit (server action) | lib/server/__tests__/<name>.test.ts |
lib/queries/<domain>.ts | Vitest unit (query) | lib/queries/__tests__/<name>.test.ts |
app/<route>/page.tsx | Playwright e2e | e2e/<route-slug>.spec.ts |
components/<group>/<name>.tsx | Vitest + RTL | co-located .test.tsx |
Prerequisite: module-add test has been run (Vitest + Playwright are wired). If not, the skill stops and routes there. Idempotent: existing test files are never silently overwritten — the user is asked whether to regenerate, append missing cases, or abort.
What it does NOT do: install test packages, run a full suite, fix failing tests. A failing test is a signal — the skill surfaces it, the user decides whether to fix the test or the source.
eve-agent — scaffold + grow the AI agent engineInput: a project with stack.agent = "eve" (opted into at stack-decision time, or added on demand).
Output: an eve agent (Vercel's filesystem-first agent framework) that the product runs on — or one new capability added to an existing agent.
Model choice stays a single pinned model by default. Since [email protected] an agent can instead take auto (experimental; named autoModel before eve 0.60.0 renamed it and moved it from eve/experimental/evaluate to eve/models): an AI Gateway evaluation model (TypeSafe AI's Jev) picks per turn from a described allowlist — at the cost of one evaluation call per turn, and with the evaluator becoming a processor that sees recent conversation text, which the data-residency register has to record. The same evaluation models are worth more inside the agent than in front of it: references/eve-patterns.md §13 uses their typed answers as a risk score in an approval policy, a guardrail inside a tool (hooks are observe-only, so never there), a refusal check graded with t.check in evals, and a pre-filter over a queue. It gates on probability and the separate confidence Jev returns for choices and scores, unit-tests those thresholds against ai/test's mock evaluation model, fails closed, is calibrated with evals, and is never the only control on something irreversible. Since 2026-09-21 the Gateway also serves Jev over a plain HTTP API and to an existing TypeSafe client, so a Python or Go service asks the same typed questions without an SDK. Jev runs only on TypeSafe's US-hosted endpoint, wherever our own code runs, so personal data stays out of its state. Where nothing may leave the perimeter — a firm's filings, special-category data — §13 names the self-hostable alternative: Rizzo Flow (Apache-2.0, open weights) whose HTTP API speaks the TypeSafe shape, so the switch is one base URL. With the arithmetic that decides it: an EU GPU runs ≈ €575/month against $0.00013 per document hosted, so self-hosting buys confidentiality, never savings — and Vercel has no GPU, so it is always a separate service. Their own agent skill ships with it; we point at it instead of rewriting it.
Three topologies, and the project picks — dev-flow §Topology policy proposes them in this order:
| Shape | Choose it when | |
|---|---|---|
| ① | Single web app, agent inside it | The product is the interface. One deploy, no workspace overhead — the ordinary case |
| ② | Monorepo apps/web + apps/agent | The agent has its own deploy cadence, channels beyond the web UI, or a second consumer (mobile) that shares types |
| ③ | Agent only (stack.framework = "agent") | Every surface is elsewhere — Slack, email, GitHub, Linear — and nothing needs rendering. agent/ sits at the repo root |
Shape ③ is not theoretical: Vercel Labs' kody-eve-template is exactly that. In it eve-agent owns the whole repo and is the bootstrap skill, so it bumps phase to scaffolded — the only topology where it touches phase at all. The web skills correctly refuse an agent-only project: there is no frontend for forms, data-fetching or shadscan to work on.
Starting at ① costs nothing — monorepo-bootstrap promotes later, and moving agent/ into apps/agent/ is a directory move, not a rewrite. Choosing ② up front costs workspace overhead on every command for a second app that may never ship, so the question that settles it is what is the second consumer? No answer means ①.
The agent counterpart to design-md-to-app + module-add: where those build/grow the Next.js app, eve-agent builds/grows the agent. Two modes, one logical operation per run (idempotent):
apps/agent yet): agent.ts + instructions.md, the default HTTP channel, a baseline eval, and packages/types (re-exported eve session/event types). The web app consumes it via the official withEve() + useEveAgent() integration.agent/tools/<name>.ts), skill, channel, connection (MCP/OpenAPI), schedule, subagent, or hook — plus its eval.The one rule: never guess the eve API — the source of truth is the bundled docs at node_modules/eve/docs/. Ecosystem-first: it installs from eve's registry (eve registry search <cap> → eve add <kind>/<name>; third-party shadcn-format sources via eve registry add) — the prebuilt integrations catalog (50+ MCP/OpenAPI connections, 11+ channels, official extensions) — before hand-rolling. Non-idempotent tools (payments, deletes, external writes) are approval-gated, because eve replays durable steps. It sits outside the phase line (its own capability cadence, often Linear-driven), recording only stack.agent + history. For multi-tenant SaaS agents it also codifies eve's composed recipes — tenant auth, per-tenant approvals, tenant-scoped long-term memory, runtime/tenant-owned dynamic scheduling, a durable audit-hook (Art. 12 traceability), the read-vs-egress data boundary, and the multi-agent team architecture (lead routes depth-1 to non-overlapping specialists; handoff artifacts travel by id so documents never enter the lead's context) — under one rule: derive tenant/user from the verified session, never from model input. The skill mirrors the entire eve docs surface — a eve-docs-coverage.md map ties every eve.dev/docs page to a reference. References: eve-conventions.md, eve-scaffold.md, eve-capabilities.md, eve-web-integration.md, eve-patterns.md (multi-tenant, dynamic, governance, traceability & multi-agent-team recipes), eve-evals.md (full eval API), eve-concepts.md (agent.ts/compaction, context control, default harness, sandbox, durability, sessions/streaming, HITL, state, dynamic capabilities & workflows, responsible use), eve-docs-coverage.md (docs coverage map); script check_eve_state.py.
Fourteen composed recipes in references/eve-patterns.md, distilled from the docs, from three MIT Vercel Labs templates and from Vercel's own SRE-agent guide. The first four are the multi-tenant backbone (tenant auth · per-tenant approvals · tenant-scoped memory · dynamic scheduling); then traceability and the read-vs-egress boundary; then three shapes an agent can take — §7 a team (a lead routing to non-overlapping specialists), §8 a pipeline (declared stations, and what a run with nobody watching may do), §9 an investigation (an agent that concludes rather than builds); §10 the cross-channel notification, where to() is a handoff and a notification wants the platform API plus an app-owned outbox; §11 untrusted content, fenced and gated; and §12 backlog triage, where the second agent argues the opposite and only runs above a confidence threshold. §13 is the evaluation model — a typed answer where a model turn would be waste — and §14 is ordered side effects, the one eve 0.71 made necessary: every agent call is now a task the model decides when to wait for, so "publish only after the review approves" stops being an instruction and becomes a single tool with the irreversible step inside it.
§6 carries a third answer for an egress a tool cannot make safely, next to fail closed and ask permission: redact locally and send the placeholders, restoring the real values from the reply. It comes with the trap that makes it worse than fail-closed when it goes wrong — fail-closed at least stops, while a broken redactor ships the document and reports that it was cleaned. Measured, not hypothetical: a BERT fine-tuned on Wikipedia prose found zero person names across a 325-page bank statement, and the endpoint answered 200.
Read §8 the moment anything triggers the agent without a human in the room — a webhook, a label, a schedule — because that is when "park for approval" silently becomes "hang forever". Its counter-intuitive core: deny an unattended run, don't gate it (a card needs somebody to answer it); disable eve's built-in agent tool once you have stations, or the orchestrator delegates to a clone of itself and bypasses them; take a tool's target from auth, not from model input, so text injected into an issue body can't redirect the write; and for what should never happen, remove the capability instead of gating it — a gate is one prompt away from being argued with.
§9's rule is the one to carry out of here even if you never build an SRE agent: a finding may not be deleted because it inconveniences a hypothesis. An agent may add evidence and may abandon a hypothesis; it may not tidy away the fact that contradicted one. Anything under pressure to conclude converges quietly otherwise — and the resulting report reads better than an honest one, because nothing in it disagrees. The same discipline shadscan needs and spec-review enforces by refusing to merge its two axes.
Voice and realtime pair naturally:
module-add voiceputs a voice surface over the eve agent (STT → agent → TTS — eve stays the brain, voice is I/O), andmodule-add realtimecovers user-to-user realtime that the agent doesn't own. Never run two competing control loops.
eve-registry-porting — port components from public eve registries, tenant-safePorts a tool, connection, or skill from a public eve/Flue agent registry (atomeve.dev, evex.sh, agentcn, eveagents.dev) into a multi-tenant eve app without adopting the registry's standalone-agent runtime model — enforcing the conformance checklist (tenant from the verified session, companyId in every query, per-tenant encrypted secrets, verified deps only, sensitive actions gated) that keeps third-party registry code tenant-safe. It's the third sourcing choice — after eve's official integrations and extension packages, before hand-writing — for source you need to own/modify that has no maintained package.
forms — one toolkit for every form (Next.js 16 App Router)Input: a form to scaffold or edit (edit panel, create dialog, settings page).
Output: a Client Component leaf that goes through lib/forms/ — useEditForm / useCreateForm + <FormProvider> + <FormField> + <FormActions> + mapFormError — with explicit Save button gated by dirty + valid state, baseline reset on success, AbortController, and discriminated-union error mapping.
Two library backends, identical consumer code, picked at scaffold via meta.json#stack.forms:
"tanstack-form" (default, recommended) — @tanstack/react-form + Zod v4 underneath."react-hook-form" (opt-in) — react-hook-form + @hookform/resolvers/zod underneath.Hook names, render layer, error contract, and dirty semantics are identical across both. The choice is invisible to consumers — only lib/forms/ knows which library it wraps. The skill refuses to apply if stack.framework ∉ {"next", "monorepo"} or stack.nextjs_version != "16".
Bans (lint + skill-enforced): useState for field values, raw useForm outside lib/forms/, auto-save / save-on-blur / debounce, inline toast.success/toast.error from form components, hand-rolled dirty tracking, <form onSubmit> that calls fetch directly.
Audit mode: "audit my codebase against the forms skill" runs 10 ripgrep checks (A–J), produces a severity-sorted report, offers fixes in order (toolkit first, mixed-library second, raw useForm + inline toasts third, missing dirty-gating fourth, etc.).
Derived from lusentis/next-skills/nextjs-forms (MIT) — see forms/SKILL.md Sources section.
data-fetching — read in Server Components, mutate via Server ActionsInput: a data read in a Next.js 16 App Router app. Output: the read landed in the correct place per the four-rung ladder:
await listX() at the top.searchParams — filter / tab / range state moves to the URL; page stays a Server Component (server reads the searchParams prop, client writes it with type-safe nuqs).Promise<T> + use() + <Suspense> — when a Client Component genuinely needs server data as props at mount (charting libs, third-party widgets).Server Actions are for mutations only — never reads. After mutating, call revalidatePath / revalidateTag / refresh() and let the Server Component re-render. Never useState + useEffect + fetch in a Client Component. Never useEffect driving a Server Action call.
Next 16.3 — Instant Navigation (stable, opt-in via cacheComponents + partialPrefetching): the skill covers the Stream / Cache / Block levers, the static-shell-vs-App-Shell distinction that explains why a page can be instant on load and blocking on navigation, use cache: private|remote, and how Partial Prefetching changes <Link> (one reusable shell per route, not one request per link). Adoption routes to Vercel's official migration guide and Skills — we don't hand-roll it.
Why: Server Actions are queued sequentially. Reading via action in useEffect costs SSR, streaming, request deduping, caching, parallelism — and produces no error to warn you. The bug is silent.
Refuses to apply if stack.framework ∉ {"next", "monorepo"} or stack.nextjs_version != "16" (Pages Router has a different mental model entirely).
Audit mode: 7 violation kinds (A–G), greps for each, severity-sorted report, fix order with toolkit-first prioritization.
Derived from lusentis/next-skills/nextjs-data-fetching (MIT).
state-discipline — eight-rung ladder before reaching for useStateInput: a useState + useEffect pair, a bare useEffect, or a "should I useState here?" question.
Output: refactor applied at the right rung of an 8-step ladder:
nuqs, not hand-rolled router.replace).data-fetching) — or in a query library if it must be client.useEffect.key={prop}, not useEffect.useMountEffect (project's explicit-intent escape hatch with a single localized eslint-disable).useState is fine. Move on.Bans bare useEffect via lint:
{ "selector": "CallExpression[callee.name='useEffect']",
"message": "Bare useEffect is banned. Use useMountEffect or walk the ladder." }
Covers also useOptimistic (over hand-rolled optimistic UI), useTransition (non-blocking heavy updates), key-based reset, and the explicit useMountEffect helper.
Refuses to apply outside Next.js 16 / App Router. The principles transfer to other React 19 setups, but the URL/Server-Component rungs do not.
Audit mode: 8 violation kinds (A–H), report with prioritized fix order.
Derived from lusentis/next-skills/nextjs-usestate (MIT) — renamed state-discipline because the rules cover all state-shaped decisions, not only useState.
transitions — one tokenized motion systemInput: "add a transition / animation", "animate this", "page transition", "stagger these cards", or a request to audit the motion in a codebase.
Output: motion routed through one token layer (lib/motion/tokens.ts + a CSS-var bridge) and a curated, tokenized library (lib/motion/transitions.ts) — entrance/exit, stagger, toggles (modal/dropdown/panel/toast/accordion), hover (lift/tilt/avatar-group), feedback (success check, error shake, number pop, skeleton pulse), layout, and route/page transitions.
How it works: governs motion the way state-discipline governs state — reach for the cheapest technique tier first (Tailwind + tw-animate-css → CSS keyframes → View Transitions API → Motion runtime), always ship a prefers-reduced-motion fallback, animate only transform/opacity, and use tokens instead of magic-number durations/easings. Four modes: Setup (scaffold lib/motion/ from the DESIGN.md motion block), Apply (best-fit transition at the lowest viable tier), Audit (scripts/scan_motion.py first-pass → verified findings), Refine (swap hardcoded values → tokens). Sits above module-add motion (which installs the Motion runtime) and reuses tw-animate-css; routes to module-add motion only when a spring/layout/gesture effect genuinely needs JS. Records meta.json#stack.motion, never bumps phase. Web-only — the mobile counterpart is rn-animations-gestures.
Between View Transitions and Motion there is a seam, and it now has two doors. Motion's imperative animateView(update) and, since [email protected], the declarative <AnimateView> (motion/react-animate-view) both choreograph the browser's View Transitions instead of replacing them — cheaper than Motion layout animation, richer than a bare document.startViewTransition. The component carries a trap worth knowing before anyone installs it: it renders React's <ViewTransition> and its source throws "AnimateView requires React 19.3 or later.", while motion's peer range still accepts React 18 and 19 — so npm installs it on a React 19.2 project and it breaks in the browser, not at install. ViewTransition itself graduated to a stable export in [email protected]; our projects are on 19.2.4, so the reference marks <AnimateView> as the next rung, not today's. Like vgpu, its docs never mention prefers-reduced-motion: that path stays ours.
Inspired by the transitions.dev motion library (Jakub Antalík) — this is our token-driven, stack-native take on the idea, not a fork or an install of their package.
And a cookbook to borrow from, with the rule that keeps it honest: React Bits ships 202 animated components as a shadcn registry (MIT + Commons Clause — usable in a product, never republished as components). Its 30 micro-interactions are Motion-based and already call useReducedMotion(), but more than half of them animate a pattern shadcn already ships — a checkbox, a switch, a toast, four buttons. So references/react-bits.md maps each one to the primitive that owns it and makes the default action port the timings onto our primitive, not install a second one; only the handful with no primitive behind them go in, through registry-intake, in the TS-TW variant. Running that review against the registry also earned two new intake checks: a dependency range that excludes the project's installed major (they ask motion@^12, we run 13) and a 1000-character class list of arbitrary values, which the old check called minified code and blocked.
animated-icons — Motion-animated icons via the shadcn registriesInput: "animated icon" / "animate this icon" / "make the bell shake on a new notification".
Output: one Motion-animated icon added from whichever of the two registries matches the project's static set — @heroicons-animated/* (316 icons) or @hugeicons-animated/* (165 icons, plus a shared lib/use-icon-animation.ts). Both MIT, both on motion, both copied into your repo as source you then own.
Pick by the set, not by the count. An animated Heroicon beside Hugeicons outlines reads as a different drawing, because it is — the skill reads meta.json#stack.icon_library before choosing and says which it picked.
How it works: each icon is a registry:ui .tsx built on motion that animates on hover and exposes an imperative ref handle (<Name>IconHandle.startAnimation()/stopAnimation()) for event-driven use. The skill adds the two things the raw components lack: a prefers-reduced-motion guard and timing read from the project's motion tokens.
spec-review — did we build what the PRD asked, the way the contract says?Input: a fixed point to diff against (main, a SHA, a tag) in a project with a .workflow/.
Output: two reports side by side — Spec and Standards — never merged, with the worst issue within each axis.
How it works: two parallel sub-agents, one per axis. Spec asks whether the diff implements what .workflow/PRD.md + tasks.md asked for — missing requirements, scope creep, things that look done but are wrong, each quoting the spec line. Standards asks whether it obeys the contract the project was built under: the golden rules (English identifiers, i18n from day one, UI only from the declared library's primitives — a file that re-implements an installed primitive is a finding with its file:line), the declared meta.json#stack (a diff reaching for a library the project didn't declare is a finding), the discipline skills, and a Fowler smell baseline as the floor — with the repo's own docs overriding all of it.
Why two axes and never one verdict: a change can follow every convention and implement the wrong feature (Standards pass, Spec fail), or do exactly what the PRD asked while ignoring the declared stack (Spec pass, Standards fail). Merging them lets either hide behind the other.
Not Claude Code's built-in /code-review — that reviews code generically and knows nothing about .workflow/. This one reads the change against this project's spec and contract, which is precisely the half a generic reviewer has to guess at. Without a .workflow/ it refuses and points you there. Proposed when a chunk of work lands (page_generated, module_added), not only before shipping — a spec finding is cheapest while the branch is still open. Records meta.json#spec_review; no phase bump; never blocks. Adapted from Matt Pocock's code-review (MIT) — the two-axis split and the smell baseline are his.
vercel-doctor — cost & performance pre-deploy gateInput: "my Vercel bill is high" / "optimize for Vercel" / a pre-deploy check on a Next.js-on-Vercel project.
Output: a docs/vercel/doctor-report.md (health score + findings), the safe fixes applied, and the judgment calls routed to the owning skill.
How it works: wraps the third-party vercel-doctor CLI, which scans a Next.js codebase for costly Vercel patterns across six areas — caching that defeats the CDN, dead code, function duration, image waste, excessive invocations, config. The skill applies the mechanical fixes (dead-code removal with tsc green, config/image tweaks) and routes the rest to the skill that owns it: caching + invocations → data-fetching (Next 16 "use cache" / Server-Component reads), images → design-md-to-app. The cost/perf sibling of compliance-audit (legal-risk gate) — both are feature_complete pre-deploy gates, both record to meta.json, both never bump phase or block deploy. Third-party tool, [VERIFY] the invocation + license. Refuses for non-Vercel/non-Next targets.
launch-audit — can a stranger find this, trust it, and buy from it?Input: "launch audit" / "è pronto per il lancio?" / "pre-launch checklist" / "controlla prima di pubblicare", or dev-flow proposing the gates at feature_complete.
Output: findings in three groups — findable, trustworthy, convertible — each routed to the skill that fixes it, plus meta.json#launch_audit with the reasons for anything dismissed.
How it works: one of the five pre-deploy gates, and it exists because the three that came before it leave a hole. shadscan asks whether the code is well made, compliance-audit whether the data handling is lawful, vercel-doctor what it will cost — an app can pass all three and still have no way to buy, no company name, and no address. This one looks only at that.
The part that turns a marketing checklist into something checkable is the middle group. "Real contact address" is, in the EU, Article 5 of Directive 2000/31/EC: name, geographic address, email, trade register and number, VAT number, rendered "easily, directly and permanently accessible" — an enumerated list, quoted verbatim in references/identity-block.md, so the check is "these items are present or they are not" rather than "the site should feel trustworthy". And the skill never writes that block: an invented registration number is materially worse than a missing one.
scripts/scan_launch.py produces signals, never verdicts, and the test suite is mostly about the second half — a scanner that cries wolf three times stops being read, so the fixtures assert what it must not report: metadata inherited from a layout, a robots.ts that branches on the environment, authenticated routes absent from a sitemap on purpose. Above-the-fold reports unknown and asks for a browser rather than guessing from source. Reports, never blocks, and there is no score to optimise.
The first real project it ran against (annotix) paid for three of those fixtures. It reported the privacy notice and the terms as missing on a site that had both, because they live behind legal/[page] and it never read the generateStaticParams — the two most alarming findings it can make, both false. It called six form files silent because <form\b also matches <form.Field>, TanStack Form's render prop, and because it did not count router.refresh() after an in-place settings save as the confirmation it is. And it passed /showcase — a DESIGN.md reference page, public, indexable, no noindex — because every findable check asks whether a page can be found and none asked the mirror question. That last one is now internal-route-indexable.
Fixing annotix's sitemap then paid for a fourth. Listing the legal pages meant the slug list had to leave the route file so the sitemap could read it too — and the moment it moved to lib/legal-pages.ts, both false findings came straight back. static_params() now follows one import hop: local modules only, and only those whose imported binding actually appears inside the generateStaticParams body. Follow every import instead and an unrelated array two files away turns a genuinely missing privacy page into a silent pass, which is the worse failure of the two.
shadscan — UI-quality & accessibility pre-deploy gateInput: "audit my UI" / "check accessibility" / "is this accessible" / a pre-deploy check on a React + shadcn app.
Output: docs/ui/shadscan.json (score out of 100 + per-category breakdown + file:line evidence), the confirmed defects fixed, the product decisions surfaced to you, and the rest routed to the owning skill.
How it works: wraps the third-party shadscan CLI — a deterministic, read-only static audit (it does not start the app, edit files, call an LLM, upload source, or need secrets) that scores six categories: Foundation, Interaction, States, Accessibility, Forms, Production Polish. The skill reads the --json report's agentHandoff block, where every actionable carries a disposition (fix / decide / verify) and a confidence, plus machine-checkable acceptance criteria. It opens every fix item in the source before touching anything, treats decide items as product questions for you (never invents an answer), verifies the advisories in code, and routes the real corrections to whoever owns them — forms, transitions, data-fetching, design-md-to-app, composition-patterns-guide.
Why that reading step is the skill. On the first real run, only 2 of 9 fix items survived it. shadscan invents nothing — every string it quoted was really in the file it named — but it cannot follow a prop across a component boundary, climb to a wrapper, see through a render prop, or know that a subtree renders to WebGL instead of the DOM. A suppressed focus ring whose wrapper carries focus-within:ring, a pending state lifted into the parent, a fallback={null} inside a <Canvas> — all reported, none defects. The better-composed the codebase, the more false positives it produces. The skill encodes which rule kinds to trust: does this file exist? is reliable, is this component semantically complete? is not.
This is one of the five pre-deploy gates (with launch-audit and app-security, which came later), and the one that closes a real hole: compliance-audit reads the legal surface and vercel-doctor the cost surface, but until now nothing mechanically verified that the UI we prescribe actually got built. Two of shadscan's rules are verbatim our own contract — animations-respect-reduced-motion is the core rule of transitions, and the label/error-association rules are what forms specifies.
The discipline: never optimise for the score. shadscan says this itself — do not add unused infrastructure solely to increase the audit score. A command menu nobody asked for is a regression that scores well. Web only (DOM/React rules); no phase bump; never blocks the deploy on its own.
vercel-deploy — ship the web app to productionInput: "deploy" / "ship it" / "manda in produzione", on a project at feature_complete.
Output: the app live on its production domain, meta.json#phase = "deployed", and a rollback runbook in the user's hands.
How it works: the web counterpart of rn-eas-deploy, and the only skill that moves a web project to deployed. It ships; it does not configure — vercel.json, the region and the env-var matrix belong to module-add deploy, and if they're missing it routes there instead of improvising. The shape is dictated by two documented Vercel behaviours: the first deployment of a new project is always a production deployment (so "preview first" doesn't exist on day one, and the skill branches), and a production deploy can be staged — vercel --prod --skip-domain builds with production env vars while serving no traffic, then vercel promote makes it Current without a rebuild. That triad (--skip-domain → promote → rollback) is what Vercel's own docs name as the preferred production commands, over vercel alias. Then domains + DNS (apex A record, project-specific CNAME for www, never hardcoded), and a rollback runbook that leads with the trap: after a rollback Vercel turns off auto-assignment of production domains, so pushes to main stop going live until someone promotes. Sets phase = "deployed" only once the production domain actually serves the deployment.
vgpu-shaders — should this project reach for WebGPU, and what does it cost?Input: "shader" / "WGSL" / "WebGPU" / "vgpu" / "aggiungi uno shader", or an animated hero that a CSS tier can't express.
Output: a grounded decision first; then, only if it survives, the vgpu wiring — .wgsl loader, a "use client" canvas, a reduced-motion path, a CI render snapshot, and meta.json#stack.shaders.
How it works: vgpu is Vercel Labs' WebGPU library (MIT), and it ships a first-party skill generated from its own source docs — 258 symbols, stamped with vgpuVersion + gitSha. So this skill deliberately does not restate the API: it installs alongside theirs (npx skills add vercel-labs/vgpu) and owns the half nobody generates. That half is: vgpu is transitions' Tier 4, above Motion — a GPU device, a compile step, a render loop and a battery — so don't skip rungs; and vgpu's docs never mention prefers-reduced-motion, which this repo requires of every transition. The fix is theirs, unconnected: advance(0) freezes the clock while frames still render, so reduced motion is hold the first frame, not hide the canvas. Plus the CI trap worth knowing before you trust a green build — headless Chrome captures a WebGPU canvas as black, so agent-browser --webgpu --headed is not optional.
It also covers the uses that are not a hero, because WebGPU is a compute API of which rendering is one case: compute() + storage ping-pong for simulation (the GPU wins on parallel arithmetic and loses on transfer — a dashboard aggregation belongs in a Web Worker); pixelDiff as a visual-regression primitive, with maxByte <= 2 documented as driver noise; gpuFrameTime as a CI performance gate; headless image generation from data; and vgpu/scene for a configurator. Two gaps it names rather than papers over: the compute docs' examples import from vgpu/mock, and the landing page advertises MP4 while the shipped docs mention video nowhere.
iframe-canvas — how many live previews can this canvas actually afford?Input: "infinite canvas" / "canvas infinita" / "tavolozza tipo Figma" / "artboard" / "live preview in an iframe" / "visual editor", or a preview iframe that went slow, blurry or stopped receiving clicks.
Output: the architecture named out loud and recorded in stack.canvas — all-live, snapshot-and-hydrate, single-live, or rendered — plus the camera, the isolation choice and the postMessage contract that follow from it.
How it works: it starts by refusing the premise. Figma's canvas is not DOM — Evan Wallace's account says HTML and SVG were rejected for "DOM access overhead" and because browsers optimise for scrolling, not zooming — so "like Figma" imports constraints Figma paid a rewrite to escape. The family this skill serves is the AI builders (Reweb, Sleek, Plasmic, Builder.io, Onlook), where the scarce resource is browsing contexts, not draw calls: same-site iframes share the parent's renderer process and main thread, and the tab has ~2 GB.
The load-bearing precedent is that Plasmic replaced its multi-artboard view with a single-artboard editing mode, citing performance, and kept multi-artboard only as a side-by-side comparison mode. So the default here is one live artboard and many static ones, not the reverse. The rest is the part that gets built wrong once and stays wrong: a camera owning both coordinate spaces (with 1 / scale on anything that must stay 1px), overlays drawn in the parent rather than injected into the frame, one declared interaction mode instead of inline pointer gating, and a protocol written as if it were cross-origin even when it isn't — because that is the switch you will want the day the canvas slows down or the content stops being yours.
Every claim traces to references/production-survey.md, which also says what the survey lacks: nobody publishes the numbers at which one of these falls over.
The 16 mobile skills mirror the web stack philosophy: opinionated defaults, idempotent operations, contract-driven state. Activate by saying "mobile" / "iOS" / "Android" at the target-platform question in prd-from-idea — that sets meta.json#stack.framework="expo-rn".
Stack opinions baked in (Wave 1–3):
expo-image instead of RN's Image, @shopify/flash-list for any list > 20 items.expo-secure-store for tokens (never AsyncStorage).Knowledge skills (10) — guardrails that auto-activate when the agent enters that domain:
| Skill | When it triggers |
|---|---|
rn-fundamentals | Start of any RN/Expo task; choices about managed vs bare, SDK, New Architecture. |
rn-styling | NativeWind setup, Flexbox in RN, safe-area, dark mode, design tokens. |
rn-expo-router | File-based routing, layouts, typed routes, deep linking, modals. |
rn-components-apis | Which RN primitive to use (Pressable, expo-image, FlashList, KeyboardAvoidingView, Linking, Platform.select). |
rn-data-fetching | TanStack Query queries/mutations/optimistic/infinite scroll. Bans fetch + useEffect for production data. |
rn-animations-gestures | Reanimated worklets, layout animations, pan/pinch/scroll-linked. |
rn-push-notifications | expo-notifications, permission timing, 3 entry paths, deep linking from payload. |
rn-backend | Provider-agnostic: client-auth patterns (secure-store, Zustand auth, refresh-on-401, auth gate). Sub-references for Supabase (default) / Firebase / custom REST / tRPC. |
rn-eas-build-submit-update | EAS Build profiles, credentials, EAS Submit, OTA via EAS Update + channels, EAS Workflows CI. |
rn-publishing-payments | App Store + Play Store metadata, RevenueCat IAP, store assets, review-rejection patterns. |
Operative skills (5) — invoked by dev-flow when the orchestrator routes to mobile:
| Skill | Phase | What it does |
|---|---|---|
rn-bootstrap | prd_drafted → scaffolded | Scaffolds a new Expo app from PRD + DESIGN.md. 4-script chain (init → install → wire-NativeWind → verify). Idempotent. |
rn-add-screen | scaffolded → page_generated | Adds a route to app/ via 5 canonical templates (list / detail / form / modal / auth-gated). Wires data layer if needed. |
rn-module-add | scaffolded → module-added | Wires auth / db / storage / realtime / push / payments / cms modules. Provider-agnostic (Supabase, Firebase, custom REST, tRPC, RevenueCat; Sanity for cms — the Studio is the admin panel). |
rn-write-tests | any | Jest + RNTL + Maestro setup + tests for one source file. Mirrors write-tests for RN. |
rn-eas-deploy | feature_complete → deployed | End-to-end deploy: pre-submission checklist → preview build → smoke → production build → EAS Submit → channels. Refuses incomplete checklist. |
rn-upgrade | any (maintenance) | Upgrades an Expo/RN project's SDK: expo install --fix → expo-doctor → cache clear → prebuild (CNG vs bare) → breaking-changes checklist. Defers per-version detail to Expo docs/MCP. §SDK 58 is written up before we have to cross it — iOS 27's scene life cycle and resizable apps (an orientation lock stops being a layout guarantee), React Native's Strict TypeScript API, the expo-router core rework, R8 on by default — and the beta page tracks what expo@next resolves to today, since it has meant both "stable" and "beta" within a month. |
Use case — idea to App Store:
1. paste idea → prd-from-idea ("target: mobile") → sets stack.framework="expo-rn"
2. dev-flow proposes Mobile bundle (Supabase + RevenueCat + EAS) → user confirms
3. rn-bootstrap → app scaffold (10 min)
4. rn-module-add auth → Supabase wired
5. rn-add-screen "login form" → app/(auth)/sign-in.tsx generated
6. rn-add-screen "feed" → app/(app)/feed.tsx with TanStack Query + FlashList
7. rn-module-add payments → RevenueCat paywall
8. rn-write-tests → Jest covers feed + auth
9. rn-eas-deploy → preview → production → submit to both stores
Typical timeline: 12–16 hours of focused work from PRD to live submission.
Single-source canonical reference: dev-flow/references/stack-expo-rn.md — what stack.framework="expo-rn" means, which skill for which phase, what keys live under meta.json#stack, which web skills are NEVER invoked on this stack (design-md-to-app, module-add, screenshot-to-page, etc. are web-only).
The 4 monorepo skills compose a single repo where both a Next.js web app AND an Expo + RN mobile app live side-by-side, sharing types, design tokens, and the backend client. Activated by answering "both / monorepo" at the target-platform question in prd-from-idea (sets meta.json#stack.framework="monorepo").
Stack opinions baked in:
.workflow/ in repo root, shared by both apps (one PRD, one DESIGN.md).packages/shared/ (types + Zod + business logic), packages/design/ (DESIGN.md → Tailwind + NativeWind presets), packages/api/ (backend client + queries).packages/api/; web payments via Stripe, mobile via RevenueCat (Apple 3.1.1 mandate).The 4 monorepo skills:
| Skill | When it triggers |
|---|---|
monorepo-bootstrap | Phase prd_drafted + stack.framework="monorepo". Scaffolds root configs (pnpm-workspace.yaml, turbo.json, tsconfig.base.json), invokes design-md-to-app in apps/web/, invokes rn-bootstrap in apps/mobile/, generates the 3 shared package skeletons, patches Metro config for the workspace topology. After pnpm install it wires the design-system lint with design-md-to-app/scripts/setup_design_lint.py — the shadcn monorepo preset in packages/eslint-config, or apps/web as a single app in the web+mobile topology — and moves the phase through set-phase, where the gate runs. Idempotent. |
monorepo-add-shared-package | "Estrai questa logica in shared", "crea un package @/forms condiviso". Creates a new package OR extracts files from an app into an existing/new shared package, updates path aliases in tsconfig.base.json, adds the package as workspace:* to both apps. Two modes: create-empty and extract-from-app. |
monorepo-add-python-service | "Aggiungi un servizio python", "add a fastapi service", "apps/ml". Puts a FastAPI service managed by uv in apps/<name>/, joined to the task graph by a scripts-only package.json and to apps/web by a generated TypeScript client — so a Pydantic rename is a compile error, not a runtime 422. Two variants: generic and ml (one resident model, model_version on every response, Metal locally / CUDA in production, the narrowest interface that makes a model swappable — so the adapter written to A/B it is the integration — the differential bench that decides whether to swap, and why a token limit is a wall the pipeline walks through, truncating and answering 200, rather than hits). Owns that app the way eve-agent owns apps/agent/: no web skill is ever proposed for it, and golden rule 2 does not apply because it has no UI. |
monorepo-sync-types | "Rigenera i tipi da Supabase", "sync DB schema". Provider-aware: Supabase → supabase gen types typescript, tRPC → TS inference re-export, Firebase → manual + Zod runtime validation, custom REST → Zod/OpenAPI/manual. Always writes into . |
Use case — idea to two-platform launch:
1. paste idea → prd-from-idea ("target: both/monorepo") → stack.framework="monorepo"
+ stack.monorepo.web.ui="shadcn" + stack.monorepo.mobile.ui="nativewind"
2. dev-flow → monorepo-bootstrap → root configs + apps/web + apps/mobile + packages/
3. module-add db --supabase → installs in packages/api/, both apps consume @<slug>/api
4. monorepo-sync-types → packages/shared/src/types/database.ts generated
5. screenshot-to-page (web) + rn-add-screen (mobile) → screens for both
6. rn-module-add payments revenuecat (apps/mobile/) + module-add payments stripe (apps/web/)
7. monorepo-add-shared-package forms → shared form validators between apps
8. vercel-deploy → Vercel for apps/web/; rn-eas-deploy → EAS for apps/mobile/
9. (live!) one PRD, one DESIGN, two apps in production, shared backend + types.
Single-source canonical reference: dev-flow/references/stack-monorepo.md — what stack.framework="monorepo" means, the full stack.monorepo object shape, phase routing including the new monorepo_initialized phase, monorepo-aware patches required across the other skills.
Two skills that work across all three stacks (web, mobile, monorepo), focused on keeping component architecture clean as projects grow:
| Skill | When it triggers |
|---|---|
promote-component | "Scan promotion candidates" / "Promovi PostCard". Implements the Rule of Three (Sandi Metz "The Wrong Abstraction"): components stay at L0 until the 3rd use, then promote to L1 (app/(group)/_components/) or L2 (components/shared/<dominio>/). Two modes: scan (analyze codebase + report markdown table) and promote (move file + rewrite all imports + tsc verify + atomic commit). Monorepo-aware. |
composition-patterns-guide | "Refactor this component" / "too many boolean props" / "compound component". Codifies the 7 Vercel composition-patterns rules (avoid boolean prop proliferation, compound components with shared context, context interface {state, actions, meta}, lift state into providers, children over render props, explicit variants, React 19 no-forwardRef) plus our colocation rules. Knowledge skill — provides the thinking framework. |
The canonical model for shared components is the 3-level hierarchy documented in docs/superpowers/specs/2026-06-06-folder-structure-refactor.md:
L0 app/<route>/_components/<Name>.tsx page-private (default)
L1 app/(group)/_components/<Name>.tsx route-group shared
L2 components/shared/<dominio>/<Name>.tsx globally shared
Plus 2 special folders that don't follow promotion: components/ui/ (shadcn/Base UI/MUI primitives) and components/theme/ (ThemeProvider, ModeToggle).
A typical "from scratch to running app" session uses the skills in this order:
1. dev-flow → init `.workflow/` + ask the user what they want to build
2. prd-from-idea → PROJECT.md + PRD.md
3. prd-to-tasks → tasks.md (optional)
4. figma-to-design-md → DESIGN.md + screenshots/
OR
image-to-design-md → DESIGN.md + screenshots/
OR
manual → user pastes their own DESIGN.md
5. design-md-to-app → scaffolded codebase + theme + showcase + placeholder routes
6. screenshot-to-page → for each screenshot, generate a real route (loop)
7. module-add db → Drizzle + Neon
8. module-add auth → better-auth
9. module-add (others) → payments / email / storage / deploy as needed
Or in one sentence:
An idea → a working, themed, branded Next.js app with theme toggle, server actions, db, auth, and 12 routes — all driven by 8 small skills sharing one
.workflow/folder.
.workflow/<project-root>/ ← codebase root (Next/Vite/Remix)
├── .workflow/ ← planning + design metadata
│ ├── meta.json ← single source of truth
│ ├── PROJECT.md ← high-level brief
│ ├── PRD.md ← requirements
│ ├── tasks.md ← task breakdown
│ ├── DESIGN.md ← Google design.md spec
│ └── screenshots/ ← raw / annotated UI references
├── package.json ← codebase at root
├── app/, components/, lib/ ← framework conventions
├── registry.json ← shadcn token registry
└── …
meta.json schema (excerpt):
{
"project_slug": "wisely",
"project_name": "Wisely",
"phase": "module-added",
"stack": {
"framework": "next",
"ui": "shadcn",
"auth": "better-auth",
"db": "neon-drizzle"
},
"history": [
{ "skill": "prd-from-idea", "phase_after": "prd_drafted", "ran_at": "..." },
{ "skill": "image-to-design-md", "phase_after": "design_extracted", "ran_at": "..." },
{ "skill": "design-md-to-app", "phase_after": "scaffolded", "ran_at": "..." },
{ "skill": "module-add", "phase_after": "module-added", "inputs": { "module": "db" } },
{ "skill": "module-add", "phase_after": "module-added", "inputs": { "module": "auth" } }
]
}
The full schema is in docs/architecture.md.
| You have | Skip |
|---|---|
| A DESIGN.md already written | figma-to-design-md + image-to-design-md. Just cp your file into .workflow/. |
| A Figma file | image-to-design-md. Use Figma path B (REST API with token) for highest precision. |
| Only inspiration images | figma-to-design-md. Use image-to-design-md instead. |
| A scaffold already running | design-md-to-app. Theme-only mode applies a DESIGN.md to existing code. |
| No screenshots | screenshot-to-page. Hand-write the routes. |
| No backend yet | module-add. Stays empty until the user wants persistence. |
module-add deploy produces config; the actual deploy is your call.When the skills are done, you have:
/showcase page proving the design system landed.module-add.lib/server/<domain>.ts reference action that you can copy-evolve.What dev-flow does not do — these are your work as the developer:
db.insert(...), db.update(...)) for your domain.useFormState (or React 19's useActionState) per page..env.local.example is a checklist — fill .env.local with real values from your Neon/Vercel/Stripe dashboards.pnpm db:push to pnpm db:generate + commit + pnpm db:migrate once you have data that matters.next.config.ts ships a permissive default Content-Security-Policy. Tighten it as you remove inline scripts/styles.bg-muted divs with TODO comments. Replace with next/image + your CDN.module-add test ships smoke tests. Real coverage (unit + integration + E2E for critical flows) is yours.If any of these feel too big to tackle alone, dev-flow's siblings (screenshot-to-page for new pages, module-add for new infra) keep working — call them again whenever you need a fresh page or a new module.
The skills are plain folders with a SKILL.md + references/ + optional scripts/. To add a new skill or modify an existing one, follow the skill-creator conventions and contribute via PR.
To add a new module variant to module-add (e.g., Clerk auth, Supabase db), drop a new references/module-<name>.md following the same pattern as module-auth.md / module-db.md. The orchestrator picks it up automatically.
A skill edit is not done until it is installed. Editing here changes nothing for the agent — it
loads ~/.claude/skills. That gap is invisible by construction: the lint passes (the repo is correct),
the skill fires (a copy exists), and it is simply the wrong text. It is how 25 corrected skills spent a
day being ignored.
./install.sh # every skill change ends here
python3 scripts/lint_skills.py # check 12 reports any remaining divergence
⚠️ Don't reach for skill-doctor right after an edit — it grades past conversations, so a re-run
immediately after a change returns identical numbers by construction: the sessions it reads used the
old text. Verified, not assumed: the run before and after ./install.sh matched on every count.
The cadence that works is install on every edit, skill-doctor periodically — once the edited
skills have been used enough to have a history worth grading. The linter judges an edit; the doctor
judges a habit.
A skill decays in two independent directions, and catching one tells you nothing about the other.
| Axis | Question | Caught by |
|---|---|---|
| Is it still true? | the upstream moved: a module path, a CLI flag, a deprecation, a dead link | a verification pass — npm pack the package and read its .d.ts, curl every cited URL, diff the shipped docs |
| Is it working? | the skill exists and is accurate, but it never fires, or it fires and the agent still flails | skill-doctor (Warp, MIT) |
skill-doctor reads local agent conversation transcripts — Claude Code's project-history JSONL
among them — scores them against two published rubrics (efficiency: rework, cost to the human,
redundant reads, batching, flailing, verification timing; code quality: design, correctness,
conventions, tests), then drafts the skill edits the failed conversations justify, as a full proposed
SKILL.md plus a unified diff. Everything runs locally; it writes to a scratch directory, never into
the repo.
npx skills@latest add warpdotdev/common-skills --skill skill-doctor
⚠️ Check the installed copies before trusting any verdict. The first real run here found 25 of
43 installed skills diverging from the repo — every one of them a skill corrected that same day. The
grader reads what the agent actually loads, so a stale install makes every finding about the wrong
text. Run ./install.sh first, then measure — and since 2026-08-28 the linter's twelfth check
tells you when you have not.
⚠️ It cannot see this repo's skills without being told where they are. Its collector probes the
conventional roots (~/.claude/skills, ~/.agents/skills, ~/.codex/skills) and globs */SKILL.md
under each. Our layout is 45 flat folders at the repo root — a valid skills root, just not one it
probes. First run here reported skills found: 0 — a perfectly formed, completely empty report
from which you would conclude that no skill is ever used.
Both traps are closed by scripts/skill-doctor.sh, which passes
--skills-dir and omits --include-global-skills, then refuses to hand back an empty report:
scripts/skill-doctor.sh ~/src/common-skills
The omitted flag is the second trap. Global roots are added only under --include-global-skills
(collect_sessions.py:124), and the collector skips names it has already seen — so with the flag on,
it reads the installed copy of every skill and drafts its edits against that. With it off,
--skills-dir wins: verified by running it, 45 of the 47 skills the suite had then (2026-08-28) resolved inside ~/my-skills and none
in ~/.claude/skills. Before, 3 of 368. The price is deliberate — without the global roots the report
cannot see plugin or third-party skills, which is exactly right when auditing our own.
The script reads skills found: back out of the collector's summary and exits 1 when it is zero,
because a silent zero reads as a finding. Verified by pointing it at a collector that prints zero.
It also warns when transcripts go missing. The collector keys sampled sessions by the sessionId inside
the .jsonl but writes each transcript to <harness>-<id>.md, and a resumed conversation keeps its
sessionId across two files — so both records are marked sampled and the second write clobbers the
first. Sessions are ordered newest-first, so the survivor is the older, usually smaller fragment: the
richer transcript is the one that disappears. A real 90-day run marked 13 sampled and wrote 12 files,
losing a 674-call session to a 13-call one. sessions_sampled in the summary counts the deduplicated
keys, so it reports 12 and looks correct.
And read the repeated tool-call count with suspicion in this repo: it keys on tool + argument
prefix, so update_meta.py <project> set-phase … and update_meta.py <project> record-artifact …
count as a repeat of each other, as do successive Edits building up one file. A dev-flow session
that advances four phases looks wasteful and is not.
Install it; don't wrap it. It is already a maintained MIT skill, so this repo does not ship a copy
— the same call made for anydoc and for vgpu's generated API skill. scripts/skill-doctor.sh is
not a wrapper around the tool: it vendors nothing and asks you for the path to your own checkout. It
only fixes the two flags and turns one silent failure loud.
The findings from the first full run — 54 sessions over 90 days — are written up in
docs/skill-doctor-referto.html (in Italian). It is a dated
snapshot, not living documentation: its figures are true as of 28 August 2026 and are deliberately
never re-aligned, the same distinction drawn under [VERIFY] between an open question and a dated
stamp.
⚠️ But a proposal is not a merge, and this repo is unusual: the skills under test are the repo. An edit that reads well as prose can still be unmergeable here, because the invariants live outside the file it changed. Before accepting one:
python3 scripts/lint_skills.py — 21 checks. The description cap in particular: over 1024
characters a conforming client skips the skill, so a "clearer" description that grew is a
regression, not an improvement.build_skills_registry.py before build_site.py, then
build_plugin_manifest.py --check.references/contracts.md is vendored byte-identically into every skill. Editing one copy is
always wrong.So the useful division is: skill-doctor proposes from evidence this repo cannot see, and the linter decides what is mergeable. Neither replaces reading the diff.
descriptionThe description is the only thing a skill is selected on — the body is never read until it loads. Five rules, all learned the hard way and all enforced by the linter:
"questionnaire" and "questionario") — and let the body carry the how. Every shortening in this repo came out of duplicated explanation, never out of a trigger.<Questionnaire /> shipped that way before it existed.description: >-. An apostrophe inside a single-quoted YAML scalar closes it and breaks the frontmatter, which means the skill fails to load at all. A folded block needs no escaping, so Italian prose ("crea l'app dal DESIGN.md") is safe in it.dev-flow enumerated sixteen of them and the list was wrong within weeks. Describe the shape; let the body name names.The repo ships a set of scripts (in scripts/) you can run anytime — four of them are what CI enforces, and one hook runs the generators for you:
# Once per clone: enable the versioned git hooks (core.hooksPath=.githooks). From then on,
# committing a SKILL.md / references/ / scripts/ change regenerates skills.json, the docs/
# site, the skill map's per-skill counts and both plugin manifests, stages them, and lints —
# so the commit that CI would have rejected never leaves the machine.
./scripts/install-git-hooks.sh
# The same regeneration by hand, in dependency order (what the hook calls)
./scripts/regenerate.sh
REGEN_BUNDLES=1 ./scripts/regenerate.sh # also repackage dist/*.skill (opt-in)
# Rewrite the skill map's `1122·9r·2s` row meta from skills.json (lint check 13 reads them)
python3 scripts/sync_skill_map.py # write
python3 scripts/sync_skill_map.py --check # CI-style: fail if stale
# Sanity-check every skill — 21 checks (frontmatter YAML + the 1024-char
# description cap, portable paths, snake_case phases, sibling cross-references,
# installer coverage, capability reachability, README catalogue coverage,
# every skill count stated in prose, the skill map's per-skill meta, the number of
# checks itself, whether a file a skill copies into a project still equals the one
# CI tested, whether what is installed still matches this repo, and whether two skills that share a
# trigger phrase name each other under `Not for:`; plus a note, never an error, for every dated
# "verified / checked / as of" marker older than 60 days)
python3 scripts/lint_skills.py
# Run every skill's test suite (each <skill>/scripts/test_*.py tracked by git; a suite that runs
# zero tests counts as a failure, and skipped node cases are printed)
python3 scripts/run_skill_tests.py
# Regenerate skills.json (the machine-readable registry of every skill)
python3 scripts/build_skills_registry.py
# Repackage the dist/<name>.skill bundles from source (keeps dist/ in sync; run
# after editing any SKILL.md / references / scripts / assets)
python3 scripts/build_skill_bundles.py # all 43
python3 scripts/build_skill_bundles.py dev-flow # or just one
# Regenerate the browsable site (docs/index.html + docs/skills/, from skills.json)
python3 scripts/build_site.py # write
python3 scripts/build_site.py --check # CI: fail if stale
# Regenerate the plugin manifest (skills allowlist comes from the taxonomy)
python3 scripts/build_plugin_manifest.py
python3 scripts/build_plugin_manifest.py --check # CI: fail if stale
# Validate the plugin + marketplace manifests with the real Claude Code CLI
claude plugin validate .claude-plugin/plugin.json --strict
claude plugin validate . --strict # the marketplace entry
# Check for npm version drift in the RN/Expo stack-defaults pin set
./scripts/refresh-stack-defaults.sh # dry-run, print diff
./scripts/refresh-stack-defaults.sh --apply # rewrite the stack-defaults.md files
# Grade a generated app against the rules the skill that generated it states —
# mechanical checks, self-tested against their own fixtures
python3 evals/generated-page/check.py ~/projects/my-app
python3 evals/generated-page/check.py --selftest # CI: every check must fire on bad, stay silent on good
# Measure whether an agent follows the gates unprompted — real `claude -p` sessions, paid, local
python3 evals/compliance/comply.py run golden-rule-3 --keep
python3 evals/compliance/comply.py selftest # CI: the grader against hand-written traces
Four questions, four tools. lint_skills.py asks whether a skill is still
well-formed — that is the source. run_evals.py asks whether the deterministic
scripts still hold — the tools. evals/generated-page/check.py
asks the one that was missing: did the generation follow its own rules? — the
output. Every anti-slop rule and every "mandatory" step in design-md-to-app was a
promise about generated code that nothing counted, and a rule nobody measures is a
rule that quietly stops being followed.
It is not shadscan, which audits an app for UI fundamentals and answers is this app
any good. This answers something narrower: did design-md-to-app obey
design-md-to-app? Read the per-check delta against a baseline, never the total — one
run tells you nothing, because the absolute count is a property of the app as much as
of the skill. And the half it cannot do stays human: whether the page is good needs a
blind A/B, and letting a number stand in for that judgement is how the number starts
lying.
The fourth, evals/compliance/comply.py, asks about
behaviour: does an agent do what a gate asks when nobody reminds it? Every gate has a
mechanical half with unit tests and a half that is a sentence in a skill (search
components/ui/ first, review before approve, register the provider). The sentence was the
half nobody counted, and the scripts cannot see it: registry_intake.py check passes after a
shadcn add <url> that bypassed it. The harness runs a real session in a throwaway dev-flow
project at three levels of prompt support (asked for, not mentioned, argued against) and
grades the trace and the final tree deterministically. It reads level 2, where the task comes
with no reminder. The idea is ECC's skill-comply; the LLM judge is dropped, because our gates
are named scripts and named paths.
CI runs lint_skills.py, run_skill_tests.py (every skill's test suite, discovered rather than listed), build_skills_registry.py, build_agent_plugin.py --check, build_skill_bundles.py --check (the dist/*.skill bundles against their sources) and build_site.py --check on every PR (see .github/workflows/lint-skills.yml). A stale skills.json, an out-of-date plugin manifest, or a site that wasn't regenerated all fail the workflow.
⚠️ Run the generators in dependency order: build_skills_registry.py before build_site.py. The site pages embed values that come from skills.json (each skill's line count, among others), so build_site.py --check run first compares the site against the old registry and passes — then regenerating skills.json makes the site stale behind your back. A locally-green check followed by a red CI is this ordering, not a flaky runner.
Most of the checks exist because the same thing kept happening: the content held and the metadata rotted. Check 8 catches a capability documented in a skill body but missing from its description — the skill would never load for the request that needs it. Check 10 catches a skill that exists but is absent from the README catalogue. Check 11 catches a skill count stated in prose that no longer matches reality — it found six on its first run, four of them in phrasings that a grep for the obvious form ("N skills") never matched — a bare count after "There are", one inside "packaging of all N", and both installers' header comments. It has since gained a pattern for every phrasing that slipped past it — the skill map's metric card (a bare value with no adjacent word), the plugin blurb, the docs link, and a fake terminal line where the em-dash the pattern anchored on belonged to a different number three words earlier. The durable fix was the other direction: the count is now absent from the prose that does not need it. Check 12 compares what is installed against what is here, and reports rather than fails: a divergence is a fact about your machine, not about the commit. Check 13 compares the skill map's per-skill meta — the bare 1122·9r·2s beside each name — against skills.json; nothing writes those numbers and no prose pattern can reach them, and on its first run 9 of the 15 rows were wrong. Check 14 guards the count in this very sentence, because the commit that added checks 13 and 14 first wrote "13" in three places. Check 15 compares a file a skill hands to a project against the copy CI tested — guards.template.ts against agent-guards/src/guards.ts — because a drift there ships untested code to every new project while the suite stays green. Check 16 derives the skill map's metric cards from skills.json and the contract's Phase enum: two of them had drifted so far — web · next 16 and how-tos both reading numbers no family or role in the registry produced — that their definition was no longer recoverable from the page, only from their siblings.
Regenerating the skill map. Edit docs/dev-flow-skill-map.html, then re-shoot the hero PNG at 1300px wide (the page's own scrollHeight, device scale 1.5) into docs/assets/. ⚠️ Force reduced motion when you shoot it — the sections are .reveal (opacity 0 until an IntersectionObserver adds .in), so a headless capture renders them blank; the prefers-reduced-motion rule is the escape hatch:
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --headless=new --disable-gpu --hide-scrollbars \
--force-prefers-reduced-motion --force-device-scale-factor=1.5 --window-size=1300,<scrollHeight> \
--screenshot=docs/assets/dev-flow-map-v1-r<n>.png file://$PWD/docs/dev-flow-skill-map.html
And shoot at 1300 CSS px, not at whatever width gives 1950 output pixels — 975×2 lands on the same pixel width but a narrower breakpoint, and the layout differs. Give the file a new name every time — dev-flow-map-<version>-r<n>.png — and update the README image path: GitHub's camo proxy caches by URL, so overwriting in place leaves everyone looking at the previous image.
MIT — see LICENSE.
figma-to-design-md | Figma URL → DESIGN.md (Google design.md spec) + screenshots |
image-to-design-md | 1+ raster images → DESIGN.md + screenshots |
url-to-design-md | A live site or a signed-in app → DESIGN.md + shadcn theme. Reads computed styles from the rendered DOM (colour roles with usage share, the type scale at two viewports, spacing grid, radii, motion, components and states), then a visual review page carrying the decisions the measurement could not settle |
design-md-to-app | DESIGN.md → scaffolded Next.js + shadcn app with theme + showcase + folder convention |
coss-ui | Coss/UI (Cal.com design system on Base UI) via the shadcn @coss/* registry — Init/Add modes, DESIGN.md token reconciliation; requires Tailwind v4, mixed MIT/AGPLv3 license |
screenshot-to-page | One screenshot → one route, with pixel-perfect verification loop |
module-add | Wire auth / db / payments / email / test / ci / motion / voice / realtime / storage / deploy / cms modules |
write-tests | One source file (server action / page / component / query) → its Vitest or Playwright test, following the project's existing patterns |
vercel-deploy | Ship the web app: preview → smoke → staged production → promote → domains + DNS, with a rollback runbook. The only skill that sets phase = "deployed" for web |
🔤 CONTEXT.md — the ubiquitous language: what skill, family, phase, reference, gate, module mean here, and the words to avoid (three different things are called "registry" — always qualify it).
📋 CHANGELOG.md — semver on the suite as a whole; what a major/minor/patch bump means for the contract.
🚫 .out-of-scope/ — decisions not to build, each with what would change our mind. Read before proposing something that was already evaluated.
tabular-nums--chart-*/showcase route: a 9-section design-system documentation page (Color tokens, Typography ladder, Buttons, Cards, Inputs, Badges, Radius, Spacing, Do's/Don'ts) — non-skippable in dev-flow mode.
Placeholder routes for every nav item declared in DESIGN.md / screenshots / PRD, so no link goes to /_not-found.
Server actions stub: at least one lib/server/<domain>.ts with Zod schemas + ActionResult<T> discriminated union + flattenZod helper, as a referenceable pattern.
i18n from day one (golden rule 2): next-intl wired at scaffold — [locale] routing, messages/{en,it}.json, provider — so no copy is ever hardcoded. How-to: references/i18n-next-intl.md.
Visual defaults, opt-in: maps via mapcn (references/maps-mapcn.md) and illustrations via Koboyo (references/illustrations.md) — the latter deliberately sparing: stack.illustrations defaults to null, and hand-drawn art is added only when DESIGN.md's visual language admits it, at emotional moments (first empty state, onboarding, 404), a handful per product.
Node graphs via React Flow (references/react-flow.md), written after finding it in five of our projects wired five ways. Only for a graph the user acts on — a read-only diagram that fits is cards. The details that were wrong in practice: theme through the un-suffixed --xy-* variables (the -default ones are redefined under .react-flow.dark and beat a token mapping in dark mode), colorMode from next-themes' resolvedTheme rather than "system" or a constant, a list instead of a canvas below md:, ariaLabelConfig fed from next-intl, React Flow UI's shadcn nodes installed through registry-intake, and the attribution kept — the installed types ask to hide it only with a subscription, and all six of our flows hid it without recording one.
Conversational surfaces are a standard, not a suggestion (references/chat-and-typeset.md): any chat, inbox, comment thread or agent console composes the official shadcn primitives — MessageScroller, Message, Bubble, InputGroup — and any rendered markdown goes through typeset, never whitespace-pre-wrap. The reference implementation is shadcn's own MIT chatbot-template; read it rather than inferring how the pieces fit.
It also carries the three human-in-the-loop mechanisms, which are easy to cross and produce a UI nobody is listening to. Ask — a tool with an outputSchema and no execute parks on the client, renders a <Questionnaire /> (the same component forms owns) and returns the human's answer as the tool output. Approval — needsApproval + addToolApprovalResponse. eve — input.requested on the agent's event stream, answered with respond(), and not interchangeable with the first two.
The type scale lives inside shadcn's own scale — each DESIGN.md level redefines its nearest Tailwind slot (--text-xs, --text-sm, --text-base, --text-xl, --text-3xl…) with its line-height, tracking and weight, and never a parallel set of semantic names. The primitives are written with text-sm ×92, text-xs ×29 and text-base ×10 and speak no other vocabulary, so a text-body beside them compiles and reaches no <Button>. This exists because a real project shipped zero type tokens and 531 text-[…] literals; moving it into the slots changed exactly two sizes across 680 measured text nodes, both intended, and gave the 131 primitive usages DESIGN.md's line-height for free.
A design-system lint from day one, wired by a script and enforced by the phase gate — @shadcn/lint, installed and wired by scripts/setup_design_lint.py for all three web topologies (single app, web+mobile, shadcn monorepo) and checked by dev-flow's set-phase, which refuses scaffolded until it is wired or an opt-out is recorded with its reason (references/design-system-lint.md). What earns it the place is the error: "rounded-full is not allowed on <Button>: <Button> owns its shape. Use a variant…" names the fix, so an agent corrects in one round. The config in the reference was run verbatim against the 61 primitives of a real scaffold: 0 errors from the plugin, every override holding. Two traps are written down because they were hit: a custom --shadow-* token is reported as an undeclared colour, and the fix must allow it by exact name — shadow-* was verified to let shadow-pink-500 through; and a flood of unknown-class warnings means a theme @import did not resolve, which the linter says in one line before the flood. A third came from upstream. Since September 2026 shadcn's registry imports cn from the cn package, and in a project whose lib/utils teaches the merger its own type scale that stock instance silently drops classes. There, and only there, the preset bans the package import, primitives included. Elsewhere the import is left alone, because it is the same function.
packages/shared/src/types/