A blog app, the software factory that builds it, and the throwaway sandbox that runs both. For engineers who want agents shipping code without a human in the loop.
πΊ Watch this video to get the full breakdown of this codebase: Factory In A Box on YouTube
Three tiers nest here: Inkwell (a minimalist blog-writing app), the Super Simple Software Factory (deterministic Python owns the graph, coding agents are bounded phases inside it), and the sandbox mount system (six host-side phases that stand the other two up on a disposable VM in about 10 seconds). The app is the payload. The point is the loop that ships it without you in the middle.
You can get value from this repo two ways, and both are first-class:
claude # boot Claude Code in the repo root
/install # set up toolchain, deps, and .env, then run the preflight
/prime # orient on all three tiers (out-loop orchestrator, in-loop orchestrator, software factory), check live state
/install and /prime live in .claude/commands/. /install checks the toolchain, installs app deps, verifies .env, and runs the just sbx manage doctor preflight without starting anything. /prime then walks the agent through the command surface, the specs, and the measured gotchas.
Once oriented, you operate the whole system by talking to the agent. Two skills carry the knowledge, so you describe intent and the agent runs the right recipes:
/sssf-sandbox-orchestrator drives the out-of-sandbox loop from plain English: mount a box, put work in, watch it, fan out best-of-N, harvest the XYZ sandbox, tear down. Thin skill, fat recipes: every action it takes is a just sbx command you could type yourself./sssf drives the factory from inside a box: create, run, and observe the ADWs, and manage the agent roster.cp .env.sample .env # add OPENROUTER_PROVISIONING_KEY (host-only, never leaves)
cd apps/inkwell && bun install # app deps
just sbx manage doctor # six-check preflight: ssh, key, helpers, rates, adw layer
just inkwell test # 30 tests green = the payload works
Every resource this system leans on, what it does, and whether you actually need it. The right two columns matter: running the full loop asks for a bit of setup, but reading and understanding the system asks for almost nothing.
| Tech | Role in the system | Run the loop | Just read + observe |
|---|---|---|---|
git | clone the repo; the factory commits its own work | required | required |
bun | serves Inkwell (:4501) and the observability UI | required | optional (only to boot the UI locally) |
uv | runs the PEP-723 Python ADW scripts | required | not needed |
just | the whole command surface (all four namespaces) | required | helpful (to read the recipes) |
| exe.dev account | the disposable VMs the factory runs inside | required to mount | not needed |
| OpenRouter provisioning key | mints and revokes the per-run inference keys | required to mount | not needed |
| Claude Code + Pi | the coding agents that do the work | preinstalled on the VM | not needed |
Two credentials are the entire reason the sandbox is safe: the exe.dev account and the OpenRouter provisioning key live only on your host. Everything else is a fast, free toolchain install. If you only want to understand the design, clone the repo and read: no account, no key, nothing to spend.
A system that needs you at every step does not scale, and you become the key-man risk in your own factory. The goal is the right side of that diagram: the loop orbits, you read the trace. Isolation is what makes it safe to let go.
The controversial call, stated plainly: the coding agents run inside the sandbox, not outside it driving a remote shell. Claude Code and Pi are installed on the VM, in the same room as the codebase. The host keeps only a thin orchestrator and two credentials that never leave.
Three command tiers, and each one commands only the tier inside it:
| Tier | Lives | Does |
|---|---|---|
| Out-sandbox super orchestrator | your machine | mounts, fills, observes, harvests, tears down sandboxes |
| In-sandbox orchestrator agent | the VM, a resumable Claude Code session | receives delegated work, launches the factory, watches it, reports |
| ADW agents | bounded phases inside the factory | scout, plan, build, review, document |
Work crosses the boundary on one of two paths, and the difference is who pulls the trigger inside:
| Path | Verb | Mechanism |
|---|---|---|
| Direct | a command | just sbx lifecycle execute detaches the factory process itself: reproducible, pid-tracked, zero orchestration tokens |
| Agent-mediated | a delegation | just sbx run agent briefs the in-sandbox orchestrator, and it launches the factory: judgment at the kickoff, conversational, resumable |
Every delegation opens with the equip line, so the in-box agent routes instead of improvising:
just sbx run agent <id> "If you have not already: READ and EXECUTE .claude/skills/sssf/SKILL.md. Then: <work>"
A blog-writing app: drafts, a markdown editor with live preview, one-click publish. Bun plus bun:sqlite, zero dependencies, vanilla JS front end, port 4501. It is small on purpose: small enough to rebuild end to end, over and over, by agents. The 30-test suite is what the factory's test phase runs, by name, as code rather than an agent decision.
just inkwell run # boot on :4501
just inkwell dev # reload-on-save
just inkwell test # the suite the factory runs
Twelve ADWs (AI Developer Workflows) under adws/, each a thin uv run script whose docstring is its chain: adw_simple_sdlc runs plan, build, test, review, document with three separate commits. Typed envelopes carry context between phases; gates validate every claim, and a failure re-enters the same session as a correction, never a restart. Agent proposes, code disposes.
Under every phase is the same primitive: an agent is a model, a harness, tools, and a prompt. The factory holds those four constant and swaps only the prompt and the model per phase. Staffing is one config file, swappable per run: five rosters ship in adws/adw_sssf_config/, the cheap default, the frontier roster, pure DeepSeek, open-weights, and top-speed. Every model is openrouter/<id>, so the ids are identical on your laptop and inside every box.
The factory has its own standalone codebase at disler/super-simple-software-factory, the skill that stamps it into any repo. This repo just runs it.
Six phases take a blank exe.dev VM to a health-checked, running factory in about 10 measured seconds: create, fill, setup, execute, observe, teardown. Every phase is a just recipe a human could type; the run record on disk is the only state they share, so any crash leaves teardown a handle.
The whole repo ships to the VM. What a sandbox cannot do is use the orchestration half, because the exe.dev account and the OpenRouter provisioning key never leave the host. Each run gets a disposable sbx- key with a $50 cap, revoked at teardown. One level of nesting, enforced by credentials rather than by deleting files.
Fan-out is a loop over configs: one prompt, N rosters, N boxes. Teardown is never automatic, and harvest never merges: a run's commits come home as refs/sandbox/<run-id>, parked for a human to compare and choose the winner.
The main flow, top to bottom. Every command is a just recipe you could type by hand.
# 0. one-time: credentials + preflight
cp .env.sample .env # add OPENROUTER_PROVISIONING_KEY (host-only)
just sbx manage doctor # must end with: sbx doctor: OK
# 1. mount a throwaway VM into a running factory (~10s)
just sbx mount my-feature # prints the resolved run id and two URLs
# 2. put work in (pick one path)
just sbx lifecycle execute <run-id> "add a word-count badge to the editor footer" # direct, detached
just sbx run agent <run-id> "READ and EXECUTE .claude/skills/sssf/SKILL.md. Then: <work>" # delegated
# 3. watch from outside
just sbx manage list # every run: state, VM alive, spend
just obs sessions # the ADW runs inside your boxes
just obs tail <adw_id> # live event stream for one run
# 4. bring the commits home (safe, non-destructive, run any time)
just sbx manage harvest <run-id> # commits land in refs/sandbox/<run-id>
# 5. tear it down (always an explicit human decision)
just sbx lifecycle teardown <run-id>
Or just ask. With /sssf-sandbox-orchestrator loaded, the same flow runs conversationally: "mount a sandbox and add a word-count badge," "spin up three and give me best-of-N," "harvest the winner." The skill picks the recipes; the typed just commands above stay the deterministic ground truth underneath.
Two handles, do not confuse them: <run-id> names the sandbox (it is also the VM name and the public hostname), while <adw_id> names one factory run inside that box. just sbx manage list counts sandboxes; just obs sessions counts the runs within them. A single box can host many ADW runs.
just sbx mount stops at observe on purpose: nothing chains into teardown, because a destroyed VM is the evidence and the artifacts, gone. Harvest is the exception you can run freely, because it only reads the box and only writes refs/sandbox/.
You watch from outside; you never reach in. Every phase, tool call, complete thought, and complete response streams into sssf.db as it happens (agents to sqlite to you, WAL so reads never block writers), and the visualizer polls it.
That trace is also the answer for the read-only audience: you do not have to run anything to understand the system, because every run it ever did is recorded. Query adws/adw_data/sssf.db directly, or boot the UI.
Each sandbox exposes two ports: the app is public, the agent view stays auth-gated to you. Ship the app; keep the factory floor private.
just obs ui # boot the observability UI
just obs sessions # recent runs
just obs tail <adw_id> # live event tail
just sbx manage list # every sandbox: state, VM alive, spend
Five namespaces, and the namespace answers where the work happens:
justfile
βββ inkwell boot and test the app itself: run / dev / test
βββ adw the workflows: sdlc, build-test, scout, simple-sdlc β¦ (runs IN a sandbox)
βββ sbx sandbox orchestration: mount, lifecycle, run, manage, orch (host-only)
βββ obs read the trace: sessions, phases, tail, procs, ui
βββ local boot an orchestrator agent on THIS machine: cc / pi / ipi
just sbx mount my-feature # blank VM β running factory, ~10s
just sbx run cmd <id> 'tail -f run.log' # look inside, synchronously
just sbx manage harvest <id> # commits home β refs/sandbox/<id>
just sbx lifecycle teardown <id> # human decision, always
TREE.md is the file-by-file map of the whole repo, grouped by tier, if you want the full territory.
Every one of these was measured on live hardware, and each cost a debugging cycle:
pi --list-models exits 0 while printing "No models available." Health checks assert on output, never $?.apt in the mount path. About 35s per package from the dal region; bun and just come from their own CDNs in about a second.The deep list lives in .claude/skills/sssf-sandbox-orchestrator/references/gotchas.md.
MIT β see LICENSE.
Want to a clear hands on guide to building your software factory?
Master tactical agentic coding patterns with Tactical Agentic Coding.
Don't want to pay for stuff? No problem: Follow the IndyDevDan YouTube channel to improve your agentic coding advantage.
Stay Focused and Keep Building
1 commits
Python
46.4%
TypeScript
16.6%
Just
11.2%
Vue
9.4%
HTML
8.8%
CSS
2.6%
Shell
2.4%
JavaScript
2.3%
A blog app, the software factory that builds it, and the throwaway sandbox that runs both. For engineers who want agents shipping code without a human in the loop.
πΊ Watch this video to get the full breakdown of this codebase: Factory In A Box on YouTube
Three tiers nest here: Inkwell (a minimalist blog-writing app), the Super Simple Software Factory (deterministic Python owns the graph, coding agents are bounded phases inside it), and the sandbox mount system (six host-side phases that stand the other two up on a disposable VM in about 10 seconds). The app is the payload. The point is the loop that ships it without you in the middle.
You can get value from this repo two ways, and both are first-class:
claude # boot Claude Code in the repo root
/install # set up toolchain, deps, and .env, then run the preflight
/prime # orient on all three tiers (out-loop orchestrator, in-loop orchestrator, software factory), check live state
/install and /prime live in .claude/commands/. /install checks the toolchain, installs app deps, verifies .env, and runs the just sbx manage doctor preflight without starting anything. /prime then walks the agent through the command surface, the specs, and the measured gotchas.
Once oriented, you operate the whole system by talking to the agent. Two skills carry the knowledge, so you describe intent and the agent runs the right recipes:
/sssf-sandbox-orchestrator drives the out-of-sandbox loop from plain English: mount a box, put work in, watch it, fan out best-of-N, harvest the XYZ sandbox, tear down. Thin skill, fat recipes: every action it takes is a just sbx command you could type yourself./sssf drives the factory from inside a box: create, run, and observe the ADWs, and manage the agent roster.cp .env.sample .env # add OPENROUTER_PROVISIONING_KEY (host-only, never leaves)
cd apps/inkwell && bun install # app deps
just sbx manage doctor # six-check preflight: ssh, key, helpers, rates, adw layer
just inkwell test # 30 tests green = the payload works
Every resource this system leans on, what it does, and whether you actually need it. The right two columns matter: running the full loop asks for a bit of setup, but reading and understanding the system asks for almost nothing.
| Tech | Role in the system | Run the loop | Just read + observe |
|---|---|---|---|
git | clone the repo; the factory commits its own work | required | required |
bun | serves Inkwell (:4501) and the observability UI | required | optional (only to boot the UI locally) |
uv | runs the PEP-723 Python ADW scripts | required | not needed |
just | the whole command surface (all four namespaces) | required | helpful (to read the recipes) |
| exe.dev account | the disposable VMs the factory runs inside | required to mount | not needed |
| OpenRouter provisioning key | mints and revokes the per-run inference keys | required to mount | not needed |
| Claude Code + Pi | the coding agents that do the work | preinstalled on the VM | not needed |
Two credentials are the entire reason the sandbox is safe: the exe.dev account and the OpenRouter provisioning key live only on your host. Everything else is a fast, free toolchain install. If you only want to understand the design, clone the repo and read: no account, no key, nothing to spend.
A system that needs you at every step does not scale, and you become the key-man risk in your own factory. The goal is the right side of that diagram: the loop orbits, you read the trace. Isolation is what makes it safe to let go.
The controversial call, stated plainly: the coding agents run inside the sandbox, not outside it driving a remote shell. Claude Code and Pi are installed on the VM, in the same room as the codebase. The host keeps only a thin orchestrator and two credentials that never leave.
Three command tiers, and each one commands only the tier inside it:
| Tier | Lives | Does |
|---|---|---|
| Out-sandbox super orchestrator | your machine | mounts, fills, observes, harvests, tears down sandboxes |
| In-sandbox orchestrator agent | the VM, a resumable Claude Code session | receives delegated work, launches the factory, watches it, reports |
| ADW agents | bounded phases inside the factory | scout, plan, build, review, document |
Work crosses the boundary on one of two paths, and the difference is who pulls the trigger inside:
| Path | Verb | Mechanism |
|---|---|---|
| Direct | a command | just sbx lifecycle execute detaches the factory process itself: reproducible, pid-tracked, zero orchestration tokens |
| Agent-mediated | a delegation | just sbx run agent briefs the in-sandbox orchestrator, and it launches the factory: judgment at the kickoff, conversational, resumable |
Every delegation opens with the equip line, so the in-box agent routes instead of improvising:
just sbx run agent <id> "If you have not already: READ and EXECUTE .claude/skills/sssf/SKILL.md. Then: <work>"
A blog-writing app: drafts, a markdown editor with live preview, one-click publish. Bun plus bun:sqlite, zero dependencies, vanilla JS front end, port 4501. It is small on purpose: small enough to rebuild end to end, over and over, by agents. The 30-test suite is what the factory's test phase runs, by name, as code rather than an agent decision.
just inkwell run # boot on :4501
just inkwell dev # reload-on-save
just inkwell test # the suite the factory runs
Twelve ADWs (AI Developer Workflows) under adws/, each a thin uv run script whose docstring is its chain: adw_simple_sdlc runs plan, build, test, review, document with three separate commits. Typed envelopes carry context between phases; gates validate every claim, and a failure re-enters the same session as a correction, never a restart. Agent proposes, code disposes.
Under every phase is the same primitive: an agent is a model, a harness, tools, and a prompt. The factory holds those four constant and swaps only the prompt and the model per phase. Staffing is one config file, swappable per run: five rosters ship in adws/adw_sssf_config/, the cheap default, the frontier roster, pure DeepSeek, open-weights, and top-speed. Every model is openrouter/<id>, so the ids are identical on your laptop and inside every box.
The factory has its own standalone codebase at disler/super-simple-software-factory, the skill that stamps it into any repo. This repo just runs it.
Six phases take a blank exe.dev VM to a health-checked, running factory in about 10 measured seconds: create, fill, setup, execute, observe, teardown. Every phase is a just recipe a human could type; the run record on disk is the only state they share, so any crash leaves teardown a handle.
The whole repo ships to the VM. What a sandbox cannot do is use the orchestration half, because the exe.dev account and the OpenRouter provisioning key never leave the host. Each run gets a disposable sbx- key with a $50 cap, revoked at teardown. One level of nesting, enforced by credentials rather than by deleting files.
Fan-out is a loop over configs: one prompt, N rosters, N boxes. Teardown is never automatic, and harvest never merges: a run's commits come home as refs/sandbox/<run-id>, parked for a human to compare and choose the winner.
The main flow, top to bottom. Every command is a just recipe you could type by hand.
# 0. one-time: credentials + preflight
cp .env.sample .env # add OPENROUTER_PROVISIONING_KEY (host-only)
just sbx manage doctor # must end with: sbx doctor: OK
# 1. mount a throwaway VM into a running factory (~10s)
just sbx mount my-feature # prints the resolved run id and two URLs
# 2. put work in (pick one path)
just sbx lifecycle execute <run-id> "add a word-count badge to the editor footer" # direct, detached
just sbx run agent <run-id> "READ and EXECUTE .claude/skills/sssf/SKILL.md. Then: <work>" # delegated
# 3. watch from outside
just sbx manage list # every run: state, VM alive, spend
just obs sessions # the ADW runs inside your boxes
just obs tail <adw_id> # live event stream for one run
# 4. bring the commits home (safe, non-destructive, run any time)
just sbx manage harvest <run-id> # commits land in refs/sandbox/<run-id>
# 5. tear it down (always an explicit human decision)
just sbx lifecycle teardown <run-id>
Or just ask. With /sssf-sandbox-orchestrator loaded, the same flow runs conversationally: "mount a sandbox and add a word-count badge," "spin up three and give me best-of-N," "harvest the winner." The skill picks the recipes; the typed just commands above stay the deterministic ground truth underneath.
Two handles, do not confuse them: <run-id> names the sandbox (it is also the VM name and the public hostname), while <adw_id> names one factory run inside that box. just sbx manage list counts sandboxes; just obs sessions counts the runs within them. A single box can host many ADW runs.
just sbx mount stops at observe on purpose: nothing chains into teardown, because a destroyed VM is the evidence and the artifacts, gone. Harvest is the exception you can run freely, because it only reads the box and only writes refs/sandbox/.
You watch from outside; you never reach in. Every phase, tool call, complete thought, and complete response streams into sssf.db as it happens (agents to sqlite to you, WAL so reads never block writers), and the visualizer polls it.
That trace is also the answer for the read-only audience: you do not have to run anything to understand the system, because every run it ever did is recorded. Query adws/adw_data/sssf.db directly, or boot the UI.
Each sandbox exposes two ports: the app is public, the agent view stays auth-gated to you. Ship the app; keep the factory floor private.
just obs ui # boot the observability UI
just obs sessions # recent runs
just obs tail <adw_id> # live event tail
just sbx manage list # every sandbox: state, VM alive, spend
Five namespaces, and the namespace answers where the work happens:
justfile
βββ inkwell boot and test the app itself: run / dev / test
βββ adw the workflows: sdlc, build-test, scout, simple-sdlc β¦ (runs IN a sandbox)
βββ sbx sandbox orchestration: mount, lifecycle, run, manage, orch (host-only)
βββ obs read the trace: sessions, phases, tail, procs, ui
βββ local boot an orchestrator agent on THIS machine: cc / pi / ipi
just sbx mount my-feature # blank VM β running factory, ~10s
just sbx run cmd <id> 'tail -f run.log' # look inside, synchronously
just sbx manage harvest <id> # commits home β refs/sandbox/<id>
just sbx lifecycle teardown <id> # human decision, always
TREE.md is the file-by-file map of the whole repo, grouped by tier, if you want the full territory.
Every one of these was measured on live hardware, and each cost a debugging cycle:
pi --list-models exits 0 while printing "No models available." Health checks assert on output, never $?.apt in the mount path. About 35s per package from the dal region; bun and just come from their own CDNs in about a second.The deep list lives in .claude/skills/sssf-sandbox-orchestrator/references/gotchas.md.
MIT β see LICENSE.
Want to a clear hands on guide to building your software factory?
Master tactical agentic coding patterns with Tactical Agentic Coding.
Don't want to pay for stuff? No problem: Follow the IndyDevDan YouTube channel to improve your agentic coding advantage.
Stay Focused and Keep Building
1 commits
Python
46.4%
TypeScript
16.6%
Just
11.2%
Vue
9.4%
HTML
8.8%
CSS
2.6%
Shell
2.4%
JavaScript
2.3%