Autonomously build an app from staged plans created by /launch-app. Reads plans/active/ stage files and builds each stage with verification, commits, and Slack notifications. Designed for unattended execution via build-app-runner.sh.
Autonomously build an app from staged plans. Picks up where /launch-app leaves off — reads stage plans from plans/active/, executes tasks in dependency order, runs verification, commits each task, and tracks progress in plans/build-state.json.
Designed for unattended execution. The companion build-app-runner.sh script re-invokes this skill across context windows until all stages are complete.
CRITICAL — NON-INTERACTIVE: Execute all phases without pausing. Never ask questions, request confirmation, or wait for input. Read state, build, verify, commit, update state, repeat. If something fails, fix it or mark it failed and move on.
Check if a command argument was provided:
status: Read plans/build-state.json, display a formatted progress summary, then stop.resume: Read plans/build-state.json, clear "failed" status on the current stage (set it back to "in_progress"), reset retry counter, then continue to Step 1.reset: Delete plans/build-state.json if it exists, confirm deletion, then stop.Read plans/build-state.json. If it exists and status is "complete", report completion and stop.
If it exists and status is "failed", report the failure details and stop (user should run /build-app resume to continue).
If it exists and status is "in_progress", skip to Step 2 (resume building).
If plans/build-state.json does not exist:
plans/active/ for files matching stage-*.mdstage-N-...)CLAUDE.md (first heading or project description)CLAUDE.md (Agent Team section)plans/build-state.json:{
"version": 1,
"project": "[project-name]",
"team": "[team-preset]",
"status": "in_progress",
"current_stage": 0,
"total_stages": N,
"iteration_count": 0,
"started_at": "[ISO timestamp]",
"updated_at": "[ISO timestamp]",
"stages": [
{
"stage": 0,
"title": "[from stage plan frontmatter]",
"file": "plans/active/stage-0-[title].md",
"status": "pending",
"started_at": null,
"completed_at": null,
"tasks": {},
"verification": {},
"retries": 0,
"error": null,
"preview_url": null
}
]
}
plans/build-state.jsoniteration_countstatus is not "complete""complete", send Slack notification, stop (exit 0)current_stage to that stage's numberplans/build-state.jsonIf the current stage's status is "pending":
Refresh the plan — Invoke /plan-next-stage [stage-file] to update the stage plan against the actual codebase state. This ensures file paths, imports, and interfaces match what prior stages actually built.
Mark stage as in_progress — Update the stage entry in plans/build-state.json:
{
"status": "in_progress",
"started_at": "[ISO timestamp]"
}
Send Slack notification — Stage starting (use temp file to avoid Windows Git Bash quote issues):
if [ -n "$SLACK_WEBHOOK_URL" ]; then
tmpfile=$(mktemp)
cat > "$tmpfile" <<EOFSLACK
{"text":"Building *[project]*: Stage [N]: [Title] starting ([M] tasks)"}
EOFSLACK
curl -s -X POST "$SLACK_WEBHOOK_URL" \
-H "Content-type: application/json" \
--data-binary @"$tmpfile" 2>/dev/null || true
rm -f "$tmpfile"
fi
If the stage is already "in_progress" (resuming), skip the refresh and notification — just continue from the next incomplete task.
Read the stage plan file to get the task list. Parse the task sections (Task NA, NB, NC, etc.).
Read the Parallelization section of the stage plan to understand dependencies:
Build an ordered list of tasks respecting dependencies.
Check plans/build-state.json for tasks already marked "complete" in this stage. Skip those.
Also cross-reference with git history — if a task's expected commit message exists in git log --oneline, mark it as complete in state even if state says otherwise (drift correction).
For each pending task in order:
git add -A
git commit -m "$(cat <<'EOF'
[commit message from stage plan's Commits section]
Co-Authored-By: Claude Opus 4.6 <[email protected]>
EOF
)"
plans/build-state.json:
{
"status": "complete",
"commit": "[short hash from git log -1 --format=%h]"
}
If a task fails verification after 3 retry attempts:
{ "status": "failed", "error": "[error description]" }
retries counterretries >= 3:
"failed" with error detailsplans/build-state.jsonretries < 3:
After all tasks in the stage are complete:
Read the Stage Checkpoint: Success Criteria section from the stage plan. Run each criterion:
Run /verify-work to check for security vulnerabilities, code quality issues, and convention adherence. Auto-fix what can be fixed, commit fixes.
Update stage status in plans/build-state.json:
{
"status": "complete",
"completed_at": "[ISO timestamp]",
"verification": {
"tier1": true,
"tier2": true,
"checkpoint": true
}
}
Move the stage plan to archive:
mkdir -p plans/archive
mv "plans/active/[stage-file].md" "plans/archive/[stage-file].md"
Update the stage plan frontmatter:
status: completed
completed: [YYYY-MM-DD]
Deploy preview (if Netlify CLI is available):
if command -v netlify &> /dev/null; then
# Deploy a draft/preview build
DEPLOY_OUTPUT=$(netlify deploy --dir=. --message="Stage [N]: [Title] complete" 2>&1)
PREVIEW_URL=$(echo "$DEPLOY_OUTPUT" | grep -o 'https://[^ ]*\.netlify\.app' | head -1)
# Update state with preview URL
# Add "preview_url": "$PREVIEW_URL" to the stage entry in build-state.json
# If this is the final stage, deploy to production
if [[ no more stages remain ]]; then
netlify deploy --prod --dir=. --message="Build complete: [project]"
PROD_URL=$(echo "$DEPLOY_OUTPUT" | grep -o 'https://[^ ]*\.netlify\.app' | head -1)
fi
fi
Note: The deploy directory should match the project's build output (e.g., .next, dist, build, out). Read the project's framework config to determine the correct directory. Run the build command first if needed (e.g., npm run build).
Send Slack notification: stage complete with preview URL (use temp file pattern as shown in Step 3)
"Stage [N]: [Title] complete — Preview: [PREVIEW_URL]"After completing a stage:
"complete" in plans/build-state.jsonAll Slack notifications are optional — they only fire if $SLACK_WEBHOOK_URL is set.
Use this pattern for all notifications (temp file avoids Windows Git Bash quote mangling):
if [ -n "$SLACK_WEBHOOK_URL" ]; then
tmpfile=$(mktemp)
cat > "$tmpfile" <<EOFSLACK
{"text":"[MESSAGE]"}
EOFSLACK
curl -s -X POST "$SLACK_WEBHOOK_URL" \
-H "Content-type: application/json" \
--data-binary @"$tmpfile" 2>/dev/null || true
rm -f "$tmpfile"
fi
| Event | Color | Message |
|---|---|---|
| Build started | #2196F3 (blue) | "Building [project]: [N] stages planned" |
| Stage starting | #2196F3 (blue) | "Stage [N]: [Title] starting ([M] tasks)" |
| Stage complete | #36a64f (green) | "Stage [N]: [Title] complete" |
| Stage failed | #ff0000 (red) | "Stage [N]: [Title] FAILED — [error]" |
| Stage retrying | #ff9800 (yellow) | "Stage [N]: Retrying (attempt [M] of 3)" |
| Build complete | #36a64f (green) | "Build complete: [project] — [N] stages, [M] commits" |
| Build failed | #ff0000 (red) | "Build FAILED at Stage [N]: [error]" |
| Rate limited | #9e9e9e (gray) | "Build paused (rate limit) — will resume" |
The state file lives at plans/build-state.json. It is the single source of truth for build progress. The runner script reads it between iterations to decide whether to continue, and the skill reads it on startup to know where to resume.
Key invariants:
iteration_count is incremented once per skill invocation (tracked by runner)| Scenario | Recovery |
|---|---|
| Task fails verification | Fix + retry up to 3 times per task |
| Stage fails after max retries | Mark failed, notify Slack, exit 1. User runs /build-app resume |
| Context window exhausted | Runner re-invokes; skill reads state and resumes |
| Rate limit hit | Runner detects, waits, re-invokes |
| Git conflict | Resolve conflict, commit, continue |
| Missing dependency | Install it, retry the step |
/build-app # Start or continue building
/build-app status # Show progress
/build-app resume # Resume after failure
/build-app reset # Clear state and start over
# Run locally, get Slack updates on your phone
./scripts/build-app-runner.sh --slack-webhook $SLACK_WEBHOOK_URL ../my-app
# Run via GitHub Actions (trigger from GitHub UI)
# See .github/workflows/build-app.yml
1. /launch-app "expense tracker SaaS" # Creates project with stage plans
2. cd ../expense-tracker
3. /build-app # Builds it autonomously