How it works
ai-app-factory turns an idea into a real, working app -- built and hosted using GitHub. Nothing gets built without a person approving it first: the project owner approves the initial plan, then the requester themselves approves or rejects each change as the app gets built.
The workflow
- 1
Request a new app
Describe what you want, submitted from your GitHub account.
- 2
Approve it
The project owner reviews the plan and approves it before anything gets built.
- 3
AI agent builds it
An AI coding agent works with GitHub to write the code and open pull requests.
- 4
You approve or redirect each change
The requester -- not the project owner -- approves or rejects each pull request on this site, and can comment @claude any time to give feedback or direct a change mid-build.
- 5
Host it on GitHub
The finished app is published and hosted using GitHub.
- 6
Fork or clone it to take it further
Fork on GitHub to keep it connected and optionally keep the pipeline running under your own account; clone it if you just want the code with no strings attached.
- 7
Original archived after 7 days
The project owner manually archives or deletes the original app about a week later.
Technical detail: the real commands
Curious what actually runs behind each step above? Every command below is sourced from a file that exists in this repo today, grouped by stage.
Triggering a run
gh issue edit <n> --add-label claude-go -R <owner>/<repo> Human β Hands an issue to Lane B β matches the `issues: labeled` trigger in claude.yml.
Source: .github/workflows/claude.yml
@claude <comment> (posted on an issue or PR) Human β a repo collaborator, or the projectβs own recorded requester (parsed from README.mdβs "Requested by" line, not just OWNER/MEMBER/COLLABORATOR as of 2026-08-18) β A comment containing "@claude" re-fires the workflow via its issue_comment trigger; the commentβs own text is read into the prompt (a real bug, fixed the same day it was found: the text used to be discarded, the comment only ever acted as a re-trigger signal), so this is also how a requester gives feedback or redirects work mid-build, not just approve/reject on something already drafted.
Source: .github/workflows/claude.yml
gh workflow run claude.yml -f issue_number=<n> -R <owner>/<repo> Human β Manual workflow_dispatch run; overrides the lane:interactive / lane:manual exclusions.
Source: .github/workflows/claude.yml
Monitoring runs
gh run list -R <owner>/<repo> Human β Lists recent claude.yml runs and their status.
Source: operational use β not embedded in a script
gh run view <run-id> -R <owner>/<repo> Human β Inspects the logs/output of one run in detail.
Source: operational use β not embedded in a script
gh issue view <n> --repo <owner>/<repo> --json title,body,labels,milestone Workflow (claude.yml) β Reads the target issue's labels (to resolve model + lane exclusions) and injects its title/body into Claude's prompt β a workflow_dispatch run has no event payload to fall back on.
Source: .github/workflows/claude.yml
gh pr list --repo <owner>/<repo> --search "linked:issue-<n>" Workflow (journal-entry.sh) β Resolves the PR that references this issue, to record in the journal entry.
Source: .github/scripts/journal-entry.sh
Ask β design doc
gh issue create --repo mmorrow24work/ai-app-factory --title "[new-project-ask] <name>" --body "<ask>" Human, via the `/new` page (a pre-filled link to this exact GitHub issue form β no token, no account setup on the site itself) β M5 β draft-design-doc.yml triggers on issues: opened, filtered to the [new-project-ask] title prefix rather than a label (GitHub silently drops labels= on this URL for non-collaborators β found via a real end-to-end test on 2026-08-18). Opus drafts docs/proposals/<slug>.md and opens a "Design: <name>" PR against main for review; the issue author's GitHub login is stamped onto the doc and PR as the authenticated requester identity, then the intake issue is closed.
Source: .github/workflows/draft-design-doc.yml
Review β provisioning plan
gh pr merge <n> --repo mmorrow24work/ai-app-factory Human β approval gate #1 β Reviews/edits the drafted design doc in GitHub's normal PR review UI, then merges it. The merge (a push to main touching docs/proposals/*.md) is what fires generate-issues.yml next.
Source: GitHub PR review UI β no script
gh workflow run generate-issues.yml -R mmorrow24work/ai-app-factory -f path=docs/proposals/<slug>.md Workflow (generate-issues.yml) β auto-fired on merge; this is the manual re-run form β M6 β reads the merged design doc and opens a "Provision mmorrow24work/<slug>" issue in ai-app-factory with the exact commands to run next. Creates nothing else and touches no other repo.
Source: .github/workflows/generate-issues.yml
Provision the repo
scripts/factory-new.sh <type> <repo-name> --ask "<summary>" [--set KEY=VALUE ...] Human β approval gate #2, own gh auth β M2 β scaffolds the repo from a template, runs `gh repo create`, applies templates/_shared/labels.json, and appends the project to projects.json (locally β does not push).
Source: scripts/factory-new.sh
scripts/factory-secrets.sh <repo-name> Human β same gate as above β M2 β sets CLAUDE_CODE_OAUTH_TOKEN (from the local .env store) and a freshly minted, never-persisted GH_PAT (prompted interactively) as Actions secrets on the new repo.
Source: scripts/factory-secrets.sh
git add projects.json && git commit -m "Register mmorrow24work/<slug>" && git push Human β same gate as above β Pushes the projects.json entry factory-new.sh wrote locally, so the dashboard picks up the new project.
Source: scripts/factory-new.sh writes projects.json; this command pushes it
Seed milestones & issues
gh workflow run seed-milestones.yml -R mmorrow24work/<repo-name> Human β manual trigger, no inputs (Actions tab β seed-milestones β Run workflow works the same way) β M6 β fetches the approved design doc from ai-app-factory's public main over an unauthenticated raw.githubusercontent.com request, then creates one milestone per doc milestone and one or more claude-go-labeled issues per milestone, using the new repo's own secrets.
Source: templates/<type>/.github/workflows/seed-milestones.yml
gh api repos/<owner>/<repo>/milestones -f title=... -f description=... Workflow (seed-milestones.yml) β Creates one GitHub milestone per "## Milestones" bullet in the design doc; skips any title that already exists.
Source: templates/<type>/.github/workflows/seed-milestones.yml
gh issue create --title ... --milestone "M<n>: <title>" --body ... Workflow (seed-milestones.yml) β Files one or more issues per milestone with an acceptance-criteria checklist; applies claude-go only to issues concrete enough for the unattended pipeline.
Source: templates/<type>/.github/workflows/seed-milestones.yml
Review & decisions during the build
gh issue create --repo <owner>/<repo> --title "[review-approve] PR #<n>" Human β the projectβs own recorded requester, or the repo owner (via the "Pending decisions" section on that projectβs dashboard page, a pre-filled link β or hand-constructed) β Implemented 2026-08-18. review-decision.yml triggers on issues: opened, filtered to a [review-approve]/[review-reject] title prefix (not a label β same labels=-is-dropped-for-non-collaborators reasoning as intake). Parses the referenced PR number from the title and merges (squash + delete branch) if authorized.
Source: templates/<type>/.github/workflows/review-decision.yml
gh issue create --repo <owner>/<repo> --title "[review-reject] PR #<n>" Human β same authorization as above β Same mechanism, opposite action: closes the referenced PR without merging and deletes its branch.
Source: templates/<type>/.github/workflows/review-decision.yml
grep -oE '\[@[A-Za-z0-9-]+\]\(https://github\.com/[A-Za-z0-9-]+\)' README.md Workflow (review-decision.yml and claude.ymlβs Authorize step) β Recovers the projectβs recorded requester login from its own README "Requested by" line β the only source of truth for who besides a collaborator is allowed to approve/reject a PR or direct changes via @claude. A repo predating that line (no match) falls through to collaborator/owner-only, not an error.
Source: templates/<type>/.github/workflows/review-decision.yml