Software Factory Build Plan · Decisions Locked
A workshop where agents propose & deterministic code disposes
Atelier marries the determinism of the Super-Simple Software Factory (ADW engine) with the operator-console cockpit of FounderOS. Agents propose inside bounded phases; deterministic Python decides sequencing and acceptance; and every event streams to a UI you can watch, launch, and steer.
The whole plan rests on one lucky coincidence I found reading both repos: both systems already treat SQLite as the single source of truth. That shared seam is what makes this a marriage, not a rewrite.
The Engine - from SSSF Python
"Agent proposes, code disposes." Non-deterministic agents live as bounded nodes inside a deterministic Python graph.
MAX_FIX_LOOPS=3, MAX_REVISION=2 as constants, not agent judgmentThe Cockpit - from FounderOS Next.js
A terminal-grade command center: "Monolith Signal" aesthetic - bare black, JetBrains Mono, color only ever means status.
terminal.tsx primitives + tokens, liftable wholesaleThis very document is rendered in FounderOS's own Monolith Signal tokens - so it doubles as a preview of Atelier's target look.
The cockpit and the engine never call each other directly at runtime. They meet at one SQLite file. The engine writes the live trace; the cockpit polls it on a rowid cursor (exactly the contract SSSF's tracer already ships, and exactly the way FounderOS's repo layer already reads). The only net-new plumbing is a control channel - a run_queue table - so the cockpit can launch runs, not just observe them.
sssf.db is the seam both sides already speak; run_queue and the cockpit's launch path are the only net-new pieces.
Both sides already speak it. SSSF's tracer writes 7 tables in WAL mode (readers never block the writer); FounderOS reads SQLite through a Zod-validated repo layer. Point that layer at SSSF's schema and observation is nearly free.
SSSF is CLI-launched. To launch from the UI we add one table + a tiny worker (or thin FastAPI). Cancel reuses the processes table - pids are already tracked.
The one risk to design around
Python (engine) and TypeScript (cockpit) must agree on the schema forever. Mitigation: generate the TS row types from the Pydantic/SQLite definitions so they can't drift.
Nearly every ADW primitive already has a FounderOS view waiting for it. The unified column is what we actually build.
| Engine concept (SSSF) | Cockpit view (FounderOS) | Unified in Atelier |
|---|---|---|
| adw_id session | Activity feed row | Run - one line in the run log, click to open |
| Phases (engineer/agent/code) | WorkflowMap process map | Process Map - live phase pipeline w/ owner lanes |
| sssf.config.yaml roster | Real Agents runtime page | Agents - roster cards, tier, model, tools, last-run |
| Deterministic gates | - (none yet) | Gate panel - pass/fail w/ per-check evidence |
| tracer.py · 7 tables | AgentCostAnalysis table | Observability - tokens, $, latency, success rate |
| UsageBreakdown | Cost tiles + spark | Cost - per-run & per-model spend, "thousandth run" |
| cookbooks / recipes | Skills capability library | Skills - card grid read live from the factory |
| - (CLI launch only) | Tasks Kanban + Conductor | Queue - enqueue/steer runs, NL launch via Conductor |
The cockpit is a window and a launch button - it observes and enqueues. It must never reach in and mutate a run's acceptance. SSSF wraps every non-deterministic agent call in five deterministic checkpoints inside agents.execute(); we keep all five and simply render them.
Envelope must parse as its declared Pydantic type. 2 same-session JSON-fix retries.
Verify the envelope's assertions against disk & git. Violations feed back into the live session.
Before/after repo diff; roll back anything outside the agent's writes allowlist.
Envelope status == "success" or the phase raises.
Defaults to fail. Success must be earned; one run.finish() reconciles db + banner + exit code.
Mocked below in the target design system. These are the v1 / Phase-1 deliverables - everything else is elaboration on top of them.
Run log - from events + sessions. Live, newest-first.
Process map - FounderOS WorkflowMap re-skinned to ADW phase lanes.
Run detail - phase timeline + envelope + gate evidence + cost.
Per your call, v1 = Phases 0-1 (observe-first): prove the seam over real, CLI-launched runs before building the control plane.
/engine (SSSF install) + /cockpit (Next.js w/ FounderOS design system)terminal.tsx primitives, tokens, shell, nav.ts, ⌘K palettesssf.dbShips
Empty cockpit renders; engine runs; shared db proven.
sssf.db via the rowid polling contractShips
Kick an ADW from the CLI, watch it end-to-end in the cockpit. ← v1 done
run_queue table + a small worker (or thin FastAPI) that the engine drainsprocesses pid trackingShips
Start & stop runs entirely from the cockpit.
Ships
Full observability - you can measure, therefore improve.
sssf.config.yaml (agents, models, prompts, writes/tools), validated, from the UImake_adw.py to compose phase chains visuallyShips
Create/modify agents & workflows without leaving the cockpit.
Ships
Live streaming, parallel runs, real queue management.
| # | Decision | Locked |
|---|---|---|
| D1 | Coding-agent backend | Both - Pi + Claude Code behind the coding_agent abstraction; CC driven by the Agent SDK (see below) |
| D2 | The seam | Hybrid - cockpit reads sssf.db directly; control via a run_queue table + small worker |
| D3 | Repo layout | Monorepo - /engine + /cockpit sharing generated schema types |
| D4 | v1 scope | Observe-first - Phases 0-1, over real CLI-launched runs |
| D5 | Name | Atelier |
You asked whether to drive CC through Herdr or the Agent SDK. For the engine backend, the Claude Agent SDK (claude-agent-sdk, Python) is the right tool. Herdr is a terminal multiplexer for driving/observing interactive agent panes - a great operator UX, but the wrong seam for a deterministic engine that needs typed, parseable, resumable output. The SDK is purpose-built for exactly SSSF's contract and maps 1:1 onto machinery the engine already has:
| SSSF mechanism (exists today) | Agent SDK primitive |
|---|---|
| tracer events (agent_start · tool_call · agent_end) | typed async message stream - SystemMessage · AssistantMessage · ToolResultMessage · ResultMessage |
| agent_map session resume | resume="<session_id>" - id from ResultMessage.session_id |
| permissions.enforce (write boundary) | can_use_tool callback + permission_mode + allowed_tools=["Edit(//src/**)"] |
| UsageBreakdown ($ + tokens) | ResultMessage.total_cost_usd + usage deltas |
| model stack per phase | model= per call - Claude models via SDK, non-Claude (GPT) via Pi |
| Phase | Model | Backend |
|---|---|---|
| Planner | Opus 5 / Fable 5 - routed per-run by task complexity | Claude Agent SDK |
| Builder | GPT-5.6 Sol | Pi |
| Reviewer · Documenter | your call (TBD) | SDK or Pi, by model |
This split is exactly why D1 = both: Claude planners (Opus 5 / Fable 5) run through the Agent SDK; GPT-5.6 Sol builds through Pi. The engine picks the model per ph.call(), so "Opus vs Fable by complexity" is just a per-run branch on the planner phase.
This turns SSSF's stubbed agent_cc.py into a real integration and keeps Pi behind the same abstraction. Herdr can ride along later as an optional way to watch live runs in a terminal - orthogonal to the engine. Verified against the Agent SDK docs (Python: claude-agent-sdk; TS: @anthropic-ai/claude-agent-sdk). The headless CLI (claude -p --output-format stream-json) is the fallback only if the engine ever needs a non-Python driver.
| Risk | Sev | Mitigation |
|---|---|---|
| Python ↔ TS schema drift | HIGH | Generate TS row types from the Pydantic/SQLite schema; the db definition is the single source. This is the #1 thing Phase 0 must nail. |
| Web process launching subprocess agents | HIGH | Local-only; auth middleware already fails closed; decouple via run_queue so the cockpit never spawns processes itself. (Deferred to Phase 2 - not in v1.) |
| Claude Code backend is a stub in SSSF | MED | Resolved direction: build agent_cc.py against the Agent SDK (claude-agent-sdk), reusing its native resume / permission / cost primitives. Budget real integration work; keep Pi behind the same abstraction. |
| SQLite write contention | LOW | Already handled - WAL + synchronous=NORMAL + busy_timeout. Cockpit only writes to run_queue. |
| Polling latency vs true real-time | LOW | 500ms rowid polling is fine through Phase 4; SSE is a deliberate Phase 5 upgrade, not a rewrite. |
Decisions locked - D1 both backends (CC via Agent SDK) · D2 hybrid seam · D3 monorepo · D4 v1 = observe-first · D5 name = Atelier. · Design source: #2 - matched the subject product - rendered in FounderOS's real "Monolith Signal" tokens so the plan previews Atelier's look. · Claims verified against super-simple-software-factory, FounderOS-DEMO, a live walk of the app, and the Claude Agent SDK docs. · Next: Phase 0 scaffold - say the word and I'll start.