|
| 1 | +# Builder: architecture |
| 2 | + |
| 3 | +How Builder is structured and why. What it does for a person is in |
| 4 | +[PRODUCT.md](https://github.com/corbitsdev/corbits-builder/blob/main/docs/PRODUCT.md); |
| 5 | +the concrete technology and layout are in |
| 6 | +[IMPLEMENTATION.md](https://github.com/corbitsdev/corbits-builder/blob/main/docs/IMPLEMENTATION.md). |
| 7 | + |
| 8 | +## Overview |
| 9 | + |
| 10 | +Builder is a control plane (the hub) on top of an agent runtime (Interchange). |
| 11 | +The runtime owns agents, workflows, mail between them, approvals, credentials, |
| 12 | +sandboxed workers and run lifecycles. The hub adds what is specific to |
| 13 | +Builder: projects, versioned documents, the tools agents use to file and hand |
| 14 | +off work, the app repository and live preview, preferences, and an API for the |
| 15 | +interface. |
| 16 | + |
| 17 | +``` |
| 18 | +person -> interface -> client API -> hub -> runtime (workflows, mail, approvals) |
| 19 | + | | |
| 20 | + | +-> sidecars running the agents |
| 21 | + | |
| 22 | + +-> documents, app repository, live app |
| 23 | +``` |
| 24 | + |
| 25 | +## Components |
| 26 | + |
| 27 | +### The hub |
| 28 | + |
| 29 | +The hub is the server and the system of record. It: |
| 30 | + |
| 31 | +- signs people in and holds tenancy: an install has workspaces, and each |
| 32 | + project is a tenant of its own under its workspace, holding the project's |
| 33 | + principals, documents, approvals and runs; |
| 34 | +- creates projects and starts each project's coordinator; |
| 35 | +- stores documents and their versions, and records which versions an approval |
| 36 | + covered; |
| 37 | +- provides the tools agents call to read and file documents, hand off work and |
| 38 | + ask the person things; |
| 39 | +- hosts each project's app repository and runs its live preview; |
| 40 | +- answers the interface's API and streams run progress to it. |
| 41 | + |
| 42 | +It embeds the runtime's control plane in the same process and composes it |
| 43 | +directly. There is no separate embedding layer. |
| 44 | + |
| 45 | +### Agents and roles |
| 46 | + |
| 47 | +Each role is a workflow package: an agent definition (prompt, tools, |
| 48 | +capabilities, model tier) and a workflow definition (trigger, steps, lifetime). |
| 49 | + |
| 50 | +- **Coordinator**: one per project, long-lived. Talks to the person, writes the |
| 51 | + problem brief, hands off work and asks for decisions. |
| 52 | +- **Writer**: one bounded write of one document of a named kind. |
| 53 | +- **Reviewer**: one bounded review of one document; its findings are advice |
| 54 | + mailed to the coordinator. |
| 55 | +- **Designer**: long-lived, one per design concept. Builds a clickable HTML |
| 56 | + and CSS mockup in its workspace. |
| 57 | +- **Coder**: long-lived, one per project. Builds the whole app in its |
| 58 | + workspace and takes later changes there. |
| 59 | + |
| 60 | +All roles are triggered by mail. The writer and reviewer take exactly one |
| 61 | +message and end. The coordinator, designers and coder keep their warm agent |
| 62 | +and workspace and take each later message as another turn on the same state. |
| 63 | + |
| 64 | +Only the coordinator talks to the person. Specialists put questions in their |
| 65 | +mail to it, and it decides whether to ask the person. |
| 66 | + |
| 67 | +### Documents and versions |
| 68 | + |
| 69 | +A document has a kind, a title and a sequence of versions. Each version has |
| 70 | +content and a content hash, and may carry open questions for the person and, |
| 71 | +for the approaches, structured options for side-by-side comparison. The kinds |
| 72 | +are the problem brief, constraints, approaches, product requirements, build |
| 73 | +plan, design options, the design and the app. |
| 74 | + |
| 75 | +- Text documents are written whole by the coordinator or a writer. |
| 76 | +- A design option is filed from a designer's workspace once the design check |
| 77 | + passes; the design is filed when the person chooses an option. |
| 78 | +- The app is filed from the coder's workspace each time the app check passes. |
| 79 | + |
| 80 | +The hub assigns each version's id, number and hash. Writing a version is never |
| 81 | +an approval. A writer gets the documents it builds on in full inside its |
| 82 | +assignment and has no read tool, so it works only from what it was given. |
| 83 | + |
| 84 | +### Approvals |
| 85 | + |
| 86 | +Approvals are the runtime's own human approvals. A tool that needs a person's |
| 87 | +go-ahead (`request_approval`, `design_app`, `instruct_coder`, adding a package) |
| 88 | +is declared as asking, so the runtime parks the call until a person resolves |
| 89 | +it. After it resolves, the hub records the exact document versions and hashes |
| 90 | +it covered, and only those whose hash still matches storage. |
| 91 | + |
| 92 | +- Versions and hashes come from the hub, never from model input, so an |
| 93 | + approval cannot be pointed at a version the person did not see. |
| 94 | +- Choosing a design option and importing a project as approved are the |
| 95 | + person's own acts; the hub records that person as the approver. |
| 96 | +- Hand-off tools check approvals before they start the next writer. |
| 97 | + |
| 98 | +### Questions |
| 99 | + |
| 100 | +`ask_questions` puts a structured card (up to five questions with options and a |
| 101 | +recommended answer) in front of the person and returns at once. The answers |
| 102 | +reach the coordinator as the person's next message. A document's open |
| 103 | +questions carry over into such a card. Questions are never modelled as |
| 104 | +approvals. |
| 105 | + |
| 106 | +### The app repository and live preview |
| 107 | + |
| 108 | +Each project has one git repository for its app. A coder run gets push access |
| 109 | +to its main branch, scoped to that run and revoked when the run ends. A new |
| 110 | +coder workspace starts from main when main holds a version, else from the last |
| 111 | +filed app, else from the app starter. |
| 112 | + |
| 113 | +The live preview runs the project's app in its own sandboxed process per |
| 114 | +project. While a coder works, it follows the coder's workspace; afterwards it |
| 115 | +runs the latest filed app. It installs packages when they change, restarts on |
| 116 | +file changes, restarts a crash once and then waits for the next change, and |
| 117 | +stops when no one has had the project open for a short while. Each project's |
| 118 | +app is served from its own origin, and a request reaches it only when the hub |
| 119 | +would show that person the project; the hub's cookies never reach the app. |
| 120 | + |
| 121 | +### Sandboxes |
| 122 | + |
| 123 | +The designer and coder run on sidecars that offer a POSIX runtime. Their shell, |
| 124 | +file and browser tools run inside a sandbox with a file policy (the workspace |
| 125 | +is writable, filed inputs and the design are read-only) and a network policy |
| 126 | +(the package registry only, or the public internet when the person allows it). |
| 127 | +Browser tools reach only the app running in the same sandbox. |
| 128 | + |
| 129 | +### Preferences |
| 130 | + |
| 131 | +Preferences are a registry of named choices, each with options and a default, |
| 132 | +and the roles it guides. A person's choices live in their settings; a project |
| 133 | +freezes its creator's choices and model profile when it starts. The coordinator |
| 134 | +reads the resolved preferences as guidance; the hub reads them where they |
| 135 | +change behaviour (approval gating, package installs, network access, design |
| 136 | +concept count). |
| 137 | + |
| 138 | +### The client API and interface |
| 139 | + |
| 140 | +The client API is a typed library over the hub's HTTP API. The interface uses |
| 141 | +only that library and the shared contract types; it never imports server code |
| 142 | +or the database. Every action in the interface is an authenticated API call |
| 143 | +that other clients can make too. |
| 144 | + |
| 145 | +## Control flow and data flow |
| 146 | + |
| 147 | +1. The person creates a project. The hub creates its tenant, installs the role |
| 148 | + packages on the project's model bindings and deploys the coordinator. |
| 149 | +2. The person's messages are mail to the coordinator. Its replies are mail |
| 150 | + back, shown as the conversation. |
| 151 | +3. The coordinator files the brief itself, then hands work off with hub tools: |
| 152 | + `deploy_writer` and `review_artifact` for documents, `design_app` for design |
| 153 | + concepts, `deploy_coder` once for the app and `instruct_coder` for later |
| 154 | + changes. |
| 155 | +4. The hub builds each assignment from its own templates: the task, the |
| 156 | + documents it builds on in full and pinned by version and hash, and the kind |
| 157 | + to write. The tool checks prerequisites first: earlier documents exist and |
| 158 | + are approved, and no coder is already running. |
| 159 | +5. The specialist works, files its result as a document version and mails a |
| 160 | + short summary back on the assignment's thread. |
| 161 | +6. The coordinator reads the filed document, judges it and either has it |
| 162 | + revised, asks the person, or asks for approval. |
| 163 | +7. The interface reads documents, approvals, run state and the live app |
| 164 | + through the API, and progress through a run event stream. |
| 165 | + |
| 166 | +Work is handed off by mail and results are filed as documents. Mail carries |
| 167 | +the conversation; documents carry the work. |
| 168 | + |
| 169 | +## Design decisions |
| 170 | + |
| 171 | +- **No fixed stages.** The coordinator decides the order of work from the |
| 172 | + document list and the conversation. The order documents build on each other |
| 173 | + is enforced as prerequisites in the hand-off tools, not as a stage machine. |
| 174 | +- **Agent behaviour lives in agent definitions and tools.** Prompts describe |
| 175 | + the task and the domain. Turn order, reply termination and loop detection are |
| 176 | + the runtime's job. Hub code covers human decisions and tenant state. |
| 177 | +- **Use the runtime's machinery.** Loops, retries, waits, timeouts, mail, |
| 178 | + approvals and failure records come from the runtime rather than being |
| 179 | + rebuilt in the hub. |
| 180 | +- **Native state over model output.** Progress, the person's next step, |
| 181 | + in-flight specialists and decisions are read from run status, run events and |
| 182 | + approval records, never from parsing what a model wrote. |
| 183 | +- **Deterministic code over model turns.** Anything code can do, code does: |
| 184 | + assignment messages, design and app checks, starting the app, filing |
| 185 | + snapshots, notices when a specialist ends. |
| 186 | +- **Exact versions everywhere.** Assignments pin documents by version and |
| 187 | + hash; approvals bind to the hash the hub computed. |
| 188 | +- **Model-agnostic.** Roles are bound to tiers, and a profile maps tiers to a |
| 189 | + provider's models, so any connected provider can run any role. |
| 190 | +- **Configuration holds wording.** User-visible names and text live in |
| 191 | + configuration, so a rename is a configuration change. |
| 192 | + |
| 193 | +## Failure handling |
| 194 | + |
| 195 | +- **Refusals are results.** A tool that cannot act returns the reason and what |
| 196 | + to do instead (a missing or unapproved document, a coder already running), |
| 197 | + and the underlying error code passes through unchanged. |
| 198 | +- **Run outcomes come from the run.** A failed run's cause is read from its |
| 199 | + own terminal events. |
| 200 | +- **A specialist that ends without answering** is noticed by a reconciler, |
| 201 | + which mails the coordinator once with the reason so it can start the work |
| 202 | + again. |
| 203 | +- **A coordinator that ended** is replaced with a fresh run when the project is |
| 204 | + next opened; the earlier runs and filed documents are carried to it as |
| 205 | + context with the person's next message. |
| 206 | +- **Coordinator upgrades** wait for a safe point (parked on input, nothing |
| 207 | + pending, no specialist at work) before replacing the run. |
| 208 | +- **Runaway model output** that repeats one passage is cut off, and long |
| 209 | + histories are compacted to fit the model's context. |
| 210 | +- **Unavailable is a state.** A project with no usable model provider says |
| 211 | + why and waits; nothing falls back silently to another provider. |
| 212 | +- **Capacity.** Work is placed on a sidecar with room; a placement refused for |
| 213 | + room is retried by the runtime. |
0 commit comments