| name | app-forge |
|---|---|
| description | Design and generate complete AI-native application codebases from a conversational idea description. Walks the user through a structured wizard to assemble a YAML app specification, then compiles it into a deployable multi-file codebase using a stack-specific generation adapter. Supports Next.js (App Router + shadcn/ui + TypeScript) and FastAPI (Jinja2 + HTMX + Python) stacks. Use when user says "build me an app," "generate an app," "scaffold a project," "app forge," "I have an app idea," "one-shot an app," "create an AI app," "make me a SaaS," or describes an application they want built from scratch. Also triggers on "forge this idea" or "turn this into an app." Do NOT use for modifying existing codebases, debugging deployed apps, building Claude skills (use skill-creator), or designing prompts in isolation (use prompt-forge). |
Turns a conversational app idea into a complete, deployable codebase. The skill operates as a two-phase pipeline:
- Wizard Phase — structured conversation that assembles a YAML app specification
- Generation Phase — compiles the spec into a multi-file codebase using a stack-specific adapter
The spec schema is the contract between phases. The wizard's job is to produce a valid spec. The adapter's job is to compile it into working code. These concerns never mix — the wizard doesn't think about code, and the adapter doesn't ask questions.
Read these files from references/ at the indicated moments — not before.
spec-schema.md— The canonical YAML schema with field definitions, valid values, and constraints. Read at the start of Step 6 (Review) to validate the assembled spec.adapter-nextjs.md— Complete generation prompt and architectural constraints for Next.js output. Read only when stack=nextjs is confirmed and generation begins.adapter-fastapi.md— Complete generation prompt and architectural constraints for FastAPI output. Read only when stack=fastapi is confirmed and generation begins.failure-modes.md— Common anti-patterns in LLM-generated code, organized by stack. Read alongside whichever adapter is selected — these constraints are injected into the generation context.examples/— Complete spec files for reference apps. Read if you need grounding on what a well-formed spec looks like, or if the user's idea resembles an example.
The wizard is a structured conversation with 6 steps. Execute them in order. Each step extracts specific schema fields. Do not skip steps, but do collapse trivially simple apps into fewer turns (see Fast Path below).
After Step 1, assess complexity. If the idea maps cleanly to a single interaction pattern with one agent and no database, offer a fast path:
"This looks like a straightforward [pattern] app. Here's the spec I'd generate — does this look right, or do you want to customize?"
Show the pre-filled YAML. If the user confirms, skip directly to generation. If they want changes, continue the wizard from the relevant step.
The fast path exists because a simple chatbot shouldn't require 6 rounds of questions. But never fast-path an app with multiple routes, multiple agents, or a data layer — those need the full wizard to avoid spec errors.
Ask: "What are you building? Describe it in a sentence or two."
From the response, extract:
meta.name— derive a kebab-case slug from the descriptionmeta.description— the user's description, lightly cleaned up- Inferred patterns — which interaction patterns likely apply (hold internally, confirm in Step 2)
- Complexity signal — simple (1 route, 1 agent), moderate (2-3 routes), or complex (4+ routes, multiple agents, data models)
Confirm the name and description. Suggest the name but let them override.
Present the available patterns with one-line descriptions. Frame them as "how users interact with your app":
| Pattern | What It Means |
|---|---|
| conversational | Chat interface — users send messages, AI streams responses |
| single_shot | Form → AI processes → result. No back-and-forth |
| batch_process | User uploads files, AI processes them asynchronously |
| observer | Dashboard showing data/metrics — read-heavy, minimal AI interaction |
| autonomous | Background AI process — no direct user interaction (cron jobs, webhooks) |
| copilot | AI assists alongside a human workflow with explicit approval gates |
Ask which patterns apply. Most apps use 1-2. For each selected pattern, suggest a default route path (e.g., conversational → /, observer → /dashboard) and let the user adjust.
Assemble the routes array from selections. Each route gets: path, pattern, requires_auth (default false), and agent (placeholder, filled in Step 3).
Skip this step entirely if no route uses an AI-driven pattern (i.e., all routes are observer only).
For each route that needs an agent, ask:
-
"What should the AI do on [path]?" — Extract the system prompt. Write it as a clear behavioral instruction, not a description. If the user gives a vague answer ("help with customer support"), sharpen it into a concrete prompt with boundaries.
-
"Which model and provider?" — Default to
claude-sonnet-4-20250514/anthropic. Only ask if the user signals a preference or the use case demands a specific capability (e.g., vision for document processing). -
"Does this agent need memory?" — Explain the three options:
none— stateless, every request is independentthread— remembers conversation history within a session (ask forthread_limit, default 20)rag— retrieves relevant context from stored documents/data
-
"Does the AI need to call any external tools?" — If yes, define each tool: name, description, parameters. If the user isn't sure, suggest common tools based on the use case (e.g., customer support → order lookup tool).
-
"Does the AI return structured data?" — If yes, define the
structured_outputfields. This matters when AI output feeds into a UI component or database — not for free-text chat.
Assemble the agents array. Link each agent to its route via the agent field.
Skip if no persistence signals emerged in prior steps.
Ask: "Does this app need to store data?"
If yes:
- Define
data.provider— defaultsqlitefor MVPs, suggestpostgresif the user mentions production or multi-user - For each entity, capture model name (PascalCase) and fields (name, type, optional flag)
- If an agent has
structured_output, suggest a matching model — "The extraction agent returns vendor/amount/date — want to store those as an Invoice model?" - Capture relations between models if mentioned
Ask: "Do users need to log in?"
If yes:
auth.enabled: true- Ask which methods: email, Google, GitHub
- Mark relevant routes as
requires_auth: true
If no: auth.enabled: false, move on. Don't over-explain OAuth configuration for someone who just wants a prototype.
Read references/spec-schema.md now to validate the assembled spec against the canonical schema.
-
Display the complete YAML spec — formatted, readable, with brief annotations where non-obvious choices were made.
-
Ask for stack choice:
"Which stack should I generate?
- Next.js — TypeScript, React, shadcn/ui, Tailwind. Best for polished UIs, but more files and complexity.
- FastAPI — Python, Jinja2 templates, HTMX. Simpler, faster to deploy, but less polished frontend."
-
Confirm environment variables — Auto-derive from the spec:
- AI provider →
OPENAI_API_KEY/ANTHROPIC_API_KEY/GROQ_API_KEY - Auth enabled → provider-specific secrets
- Database →
DATABASE_URLif postgres - Assemble
env_varsarray
- AI provider →
-
Set error behavior — Default to
show_errorunless the user asks for retry logic. Don't over-explain this. -
Final confirmation — "Ready to generate? I'll create the full codebase in your working directory."
Once the user confirms:
Before writing any code, fetch up-to-date API documentation using the get-api-docs skill. This prevents generating code with stale API patterns.
Required fetches based on spec:
| Spec Condition | Fetch Command | Why |
|---|---|---|
Any agents[].provider exists |
chub get vercel-ai-sdk --lang ts |
Core streaming/generation patterns |
provider: "openai" |
chub get ai-sdk/openai --lang ts |
Model names, provider config |
provider: "anthropic" |
chub get ai-sdk/anthropic --lang ts |
Model names, provider config |
provider: "google" |
chub get ai-sdk/google --lang ts |
Embedding + chat model names, env var |
provider: "groq" |
chub get ai-sdk/groq --lang ts |
Model names, provider config |
Any route with pattern: "conversational" |
chub get ai-sdk/react --lang ts |
useChat hook — import path changed in v6 |
memory: "rag" |
Provider's embedding docs | Embedding model names change frequently |
auth.enabled: true |
chub get next-auth/v5 --lang ts |
Auth.js v5 patterns |
After fetching:
- Extract current import paths (e.g.,
@ai-sdk/reactnotai/react) - Extract current method names (e.g.,
toUIMessageStreamResponsenottoDataStreamResponse) - Extract current model name formats (e.g.,
gemini-embedding-001nottext-embedding-004) - Use these in generated code — override any hardcoded examples in the adapter if they conflict
If chub docs are unavailable, fall back to the adapter's examples but add a README warning that API patterns may need updating.
Before generating package.json, run npm show <package> version for each core dependency:
npm show next version # Must be ≥ 15.5.14
npm show ai version # Must be ≥ 6.0.0
npm show @ai-sdk/react version # Required for useChat in ai@6
npm show next-auth@beta version # If auth enabledUse these exact versions in the generated package.json. Never hardcode stale versions.
Read the appropriate adapter file:
references/adapter-nextjs.mdifmeta.stack: nextjsreferences/adapter-fastapi.mdifmeta.stack: fastapi
Also read references/failure-modes.md — these constraints apply to all stacks.
Important: The adapter's code examples are fallbacks. If you fetched API docs in Step 0, use those patterns instead. The adapter examples may be outdated.
Generate the codebase following the adapter's structure but using API patterns from Step 0:
- Directory structure from adapter
- File-by-file generation order from adapter
- Import paths and method names from fetched API docs
- Stack-specific architectural constraints from adapter
Write all files to the user's working directory under [meta.name]/.
Generate these always, regardless of stack:
.env.examplefrom theenv_varsarray — NEVER hardcode secretsREADME.mdwith setup instructions, env var documentation, and deploy stepsspec.yaml— the complete spec that produced this codebase (for reproducibility)
Present the output directory to the user with a brief summary:
🔨 App Forge complete: [meta.name]
Stack: [nextjs|fastapi]
Routes: [count] — [brief path listing]
Agents: [count] — [brief id listing]
Data models: [count or "none"]
Auth: [enabled/disabled]
📁 Project generated at outputs/[meta.name]/
📄 Spec saved as spec.yaml for reproducibility
Next steps:
1. Copy .env.example to .env and fill in your API keys
2. [stack-specific install command]
3. [stack-specific run command]
Always run this step. It is what makes the skill sharper with each use. After presenting the summary, reflect on the entire generation run and write any new knowledge back into the reference files before closing.
Review the generation run for any of the following. Each one that occurred gets recorded:
| Signal | Where to record |
|---|---|
| API method or import path differed from adapter example | references/api-docs-prefetch.md → Known Breaking Changes table |
Package version from npm show differed from adapter's hardcoded example |
references/api-docs-prefetch.md → Known Breaking Changes table |
A runtime error occurred that wasn't prevented by failure-modes.md |
references/failure-modes.md → new numbered entry |
| A spec field caused unexpected generation behavior | references/spec-schema.md → annotate the relevant field |
| An adapter code example is now confirmed outdated | references/adapter-nextjs.md or adapter-fastapi.md → update inline |
For API breaking changes — append a row to the relevant table in references/api-docs-prefetch.md:
| Old Pattern (package@old) | New Pattern (package@new) | Impact |
|---|---|---|
| `import { X } from 'old-path'` | `import { X } from 'new-path'` | [what breaks] |For new failure modes — append a new numbered entry to references/failure-modes.md:
### [N]. [Short title of what broke]
[One sentence describing the failure pattern.]
**Constraint:** [The rule that prevents recurrence. Written as a DO NOT or MUST instruction.]Format discipline: Match the style of existing entries exactly. Consistent format means future reads are predictable and low-noise.
Only record what generalizes. A one-off typo is not a lesson. An API method that no longer exists is. Ask: "Would this have broken a different app using the same pattern?" If yes, record it. If no, skip it.
If any lessons were written, commit and push immediately so they persist across sessions:
git -C ~/.claude/skills/app-forge add -A
git -C ~/.claude/skills/app-forge commit -m "lessons([app-name]): [one-line summary of what was learned]"
git -C ~/.claude/skills/app-forge push origin mainIf lessons have been recorded across 3 or more separate generation runs (visible in git log), suggest to the user:
"Consider running
SkillForge --improve app-forgeto synthesize accumulated lessons into structural improvements. This upgrades the skill itself, not just the reference files."
This is how surface-level patches become deep architectural improvements over time.
If no API surprises, no version mismatches, and no runtime errors occurred — skip this step entirely. Only record signal, never noise.
- The wizard asks questions; the adapter writes code. Never mix these phases.
- Each wizard step extracts specific schema fields. Do not ask about fields that belong to a later step.
- Do not generate code during the wizard phase, even if the user asks. Complete the spec first. The spec is the contract — generating without it produces incoherent code.
- The spec must be valid YAML that conforms to the canonical schema before generation begins.
- Generation produces a complete, runnable project — not fragments. Every import resolves, every route renders, every agent connects.
- NEVER hardcode API keys, database credentials, or secrets into generated code.
- Keep generated projects lean: under 15 files for simple apps, under 25 for complex ones. If the spec implies more, simplify the architecture.
- If the user's idea is genuinely too complex for single-prompt generation (5+ agents, 8+ routes, complex data relationships), say so honestly and suggest breaking it into a core MVP + expansion plan.