ai-app-factory-v2

How it works

ai-app-factory-v2 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. 1

    Request a new app

    Describe what you want, submitted from your GitHub account.

  2. 2

    Approve it

    The project owner reviews the plan and approves it before anything gets built.

  3. 3

    AI agent builds it

    An AI coding agent works with GitHub to write the code and open pull requests.

  4. 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. 5

    Host it on GitHub

    The finished app is published and hosted using GitHub.

  6. 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. 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 on this repo itself, or (in a generated project) the project’s own recorded requester, parsed from README.md’s "Requested by" line rather than being limited to OWNER/MEMBER/COLLABORATOR — A comment containing "@claude" re-fires the workflow via its issue_comment trigger. The comment’s own text is fetched via `gh api .../issues/comments/<id> --jq .body` and read into the prompt, not just used as a re-trigger signal (DESIGN.md’s "Lessons carried forward" records this as a bug found in the predecessor’s own root claude.yml) — this is 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-v2 --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) — 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 anyone who isn’t already a repo collaborator with label-write access, which is exactly the non-collaborator requester this flow serves. Opus drafts docs/proposals/<slug>.md and opens a "Design: <name>" PR against main for review; a script step (never the LLM step) stamps the issue author’s authenticated GitHub login onto the doc and PR as the requester identity.

Source: .github/workflows/draft-design-doc.yml

Review → provisioning plan
gh pr merge <n> --repo mmorrow24work/ai-app-factory-v2

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-v2 -f doc_path=docs/proposals/<slug>.md

Workflow (generate-issues.yml) — auto-fired on merge via a push-triggered dispatch job; this is the manual re-run form — Reads the merged design doc and opens a "Provision <owner>/<slug>" issue in ai-app-factory-v2 itself with the exact commands to run next. Creates nothing else and never touches another repo — provisioning the new repo stays a human step with the human’s own gh auth.

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 — 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 — Sets CLAUDE_CODE_OAUTH_TOKEN (from the local .env store) and a freshly minted, never-persisted GH_PAT (prompted interactively, input hidden) as Actions secrets on the new repo.

Source: scripts/factory-secrets.sh

git add projects.json && git commit -m "Register <owner>/<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 <owner>/<repo-name>

Human — manual trigger, no inputs (Actions tab → seed-milestones → Run workflow works the same way) — Fetches the approved design doc from ai-app-factory-v2'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) — 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 || true

Workflow (review-decision.yml and claude.yml’s Authorize step, in every generated project) — 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. The trailing `|| true` tolerates zero matches so a repo predating that line falls through to collaborator/owner-only instead of killing the step under `set -e`/`pipefail`.

Source: templates/<type>/.github/workflows/review-decision.yml