Plans and the build loop
How a Switchboard plan is proposed, revised in conversation, approved step by step, signed, checked and built.
In-app only, for allowlisted workspaces. Nothing on this page is reachable with an API key.
#Anatomy of a plan
| Part | Written by | What it is |
|---|---|---|
| Outcome | Model | One sentence: what will be true after the build |
| Assumptions ("I assumed") | Model | What it inferred, so the admin can correct it |
| Questions | Model, then Ody | Blocking questions. Ody adds follow-ups when a required detail is missing |
| Steps | Model proposes, code validates | Each step has an action from the catalog, its params, a why, the part of the request it comes from (traces_to), and its dependencies |
| Risk, reversibility, cost, plan gate | Code only | Looked up from the catalog, so the model can't play down a purchase |
| Before → after | Code | A line diff of the affected account settings |
| Signature | Code, at approval | HMAC over the frozen steps. Never returned to the browser |
A step whose traces_to doesn't quote the request (or start with platform rule:), or whose action isn't in the catalog, is dropped before the admin sees it. Plans are capped at 25 write steps and 10 numbers.
#Talking it through
Every message after the first is a revision. The model re-plans with the whole conversation and the current plan:
- "Make that 30 seconds" changes one step. Steps whose action and params are byte-for-byte identical keep their approved or skipped decision, so the admin re-approves only what changed.
- "When I said Luis I meant Jordan" replaces that detail and nothing else.
- Answering a blocking question works the same way, with the answer attached to the question.
Every revision drops the signature and bumps the plan's internal version.
#Approving
- Per step: approve, skip or reset. Skipping a step also skips the steps that depend on it ("Skipped with step 2"). Approving it again brings them back.
- Approve all: approves every undecided step, then the plan.
- New-number steps show a number picker, and the admin chooses which number to buy from the ones the plan shows.
- If a step needs a higher plan, Switchboard adds an
upgrade_planstep itself. The model never proposes plan changes on its own.
Approving the plan signs it: HMAC-SHA256 over the plan ID, workspace ID, version, a hash of the before-snapshot, the approver's user ID, and every step's ID, action, params, decision and dependencies.
#Checking
Check plan runs every approved step's catalog check in order, with each check seeing the steps before it, and writes nothing. The result is either "Checked · ready to build" or "The check found a problem. Nothing was changed."
#Building
Build runs only what was signed, and only for the admin who approved it:
- The plan row is atomically moved to
building. A second click gets "already being built" and writes nothing. - Before each step, the objects it touches are compared with the before-snapshot. If a teammate changed one in the meantime, the build pauses and names it rather than overwriting.
- Each step calls the same function the Settings screen calls, as the approving admin.
- After each write, every number's routing is read back. A number left forwarding nowhere, pointing at an unpublished flow, or routed to a missing agent stops the build.
A step interrupted mid-write isn't retried automatically, because retrying a purchase could buy twice. The admin is asked to check Settings and start a new plan.
#Plan statuses
| Status | Meaning |
|---|---|
proposed | Drafted, not approved |
approved | Signed |
dry_run_ok / dry_run_failed | Checked |
building | Running |
paused | Stopped on a concurrency conflict. Can resume |
built / failed / cancelled | Finished |
Every step of the loop is written to an append-only audit trail that the app's own database role can't edit or delete.