Factory
@bonsai/factory is a nightly human-in-the-loop code factory. It surveys the repository, selects a small set of high-value ideas, implements and verifies each idea in isolation, and opens pull requests for review.
It never merges. Failed verification discards the attempted change and opens no PR for that idea.
Pipeline
ideate -> select -> branch -> implement -> verify -> commit -> push -> PR
The production loop is built from injectable seams:
| Seam | Production runner | Backed by |
|---|---|---|
IdeationAgent | makeClaudeIdeation | Claude Agent SDK with read-only tools. |
ImplementationAgent | makeClaudeImplementation | Claude Agent SDK with write tools. |
Verifier | makeShellVerifier | bunx turbo run typecheck test build by default. |
Git | ShellGit | Git CLI. |
Forge | GhForge | GitHub CLI. |
Ledger | FileLedger | JSON at .factory/ledger.json. |
The orchestration in src/factory.ts is pure and unit-tested with fakes. Side-effecting implementations live in src/runners/.
Prerequisites
- Bun workspace dependencies installed.
ANTHROPIC_API_KEYfor Claude Agent SDK ideation and implementation.- Authenticated GitHub CLI (
gh) for PR creation. - A clean enough working tree for factory branches, commits, pushes, and PRs.
Read-only ideate and plan require the API key but do not need GitHub write access.
Install and Develop
cd apps/factory
bun install
bun run build
Development checks:
bun test
bun run typecheck
bun run build
Commands
factory ideate [options]
factory plan [options]
factory run [options]
factory ledger [--limit n]
factory --version
factory --help
From source:
bun apps/factory/src/cli.ts ideate
bun apps/factory/src/cli.ts plan
bun apps/factory/src/cli.ts run --max 3
bun apps/factory/src/cli.ts ledger
Command behavior:
ideate: ask Claude for ranked ideas and print JSON. No code changes.plan: show which ideas would be built after ledger and branch de-duplication. No code changes.run: ideate, select, implement, verify, commit, push, and open PRs.ledger: print recent attempts from the factory ledger.run --dry-run: aliases toplan.
Options and Environment
Flags override FACTORY_* environment variables, which override defaults.
| Env | Flag | Default | Meaning |
|---|---|---|---|
FACTORY_MAX_PRS | --max <n> | 3 | Maximum PRs to open per run. |
FACTORY_IDEA_COUNT | --ideas <n> | 8 | Ideas to request from ideation. Always at least maxPrs. |
FACTORY_BASE_BRANCH | --base <branch> | main | Branch to cut from and target. |
FACTORY_GUIDANCE | --guidance <text> | unset | Extra steering for ideation. |
FACTORY_DRAFT | --draft | false | Open PRs as drafts. |
FACTORY_VERIFY_COMMAND | none | bunx turbo run typecheck test build | Verification gate command. |
FACTORY_LEDGER_PATH | none | .factory/ledger.json | Ledger path. |
FACTORY_BRANCH_PREFIX | none | factory/ | Branch prefix. |
Claude runner env:
| Env | Default | Meaning |
|---|---|---|
FACTORY_CLAUDE_TOOLS | Read,Glob,Grep,Edit,Write,Bash | Tool list for implementation. |
FACTORY_CLAUDE_PERMISSION_MODE | bypassPermissions | Claude SDK permission mode. |
Ledger and De-duplication
The factory avoids repeating work by consulting:
- Recent ledger entries.
- Existing branches with the configured factory branch prefix.
Each attempt records status, title, timestamp, optional PR URL, and notes. Use:
factory ledger --limit 20
Scheduling
.github/workflows/factory.yml runs the factory nightly at 07:00 UTC and supports manual dispatch with max, guidance, and dry_run inputs.
Repository secrets:
ANTHROPIC_API_KEYis required.FACTORY_GH_TOKENis optional. Use a PAT if PRs opened by the workflow need to trigger downstream CI; PRs opened by the defaultGITHUB_TOKENdo not trigger every workflow.
Safety Model
plangives a no-change preview of selected work.runverifies each implementation before opening a PR.- Red verification means no PR is opened for that idea.
- The factory opens reviewable PRs and stops. Humans own review and merge.
- Verification defaults to the full monorepo gate:
bunx turbo run typecheck test build