Plans as code: why your project plan deserves a programming language
Here is an uncomfortable observation about every drag-and-drop planning tool: the plan in it is already a program. It has entities, dependencies, conditions, loops, and an execution semantics (what happens when tasks complete). The tool just stores that program as rows in a database and lets you interact with it only through a mouse.
Programs you cannot read have a familiar set of problems. You cannot diff them, so nobody knows what changed before the deadline slipped. You cannot review them, so structural mistakes ship silently. You cannot copy meaningful chunks between projects, version them, or hand them to another tool. Software engineering solved these problems decades ago with a radical idea: keep the source as text.
TOL (Total Orchestration Language) is that idea applied to plans. Every Topolog plan is a TOL program, and the text is yours to read and edit:
plan "Feature release" {
agent dev { type: internal }
outcome review_ok: boolean { default_prior: 0.75 }
task t_design "Design the API" { agent: dev; estimate: 6h cv 0.3 }
task t_build "Implement it" { agent: dev; estimate: 16h cv 0.5 }
task t_review "Code review" {
agent: dev
estimate: 3h cv 0.3
produces: [review_ok]
}
sentinel s_shipped "Shipped" { end_state: success }
sentinel s_rework "Back to the bench" { end_state: partial }
edge e1 t_design -> t_build { carries: null }
edge e2 t_build -> t_review { carries: null }
edge e3 t_review -> s_shipped { carries: null; gate: review_ok = true }
edge e4 t_review -> s_rework { carries: null; gate: review_ok = false }
}
Nothing here is exotic. Agents do tasks; tasks have uncertain durations; edges declare order; gates branch on outcomes; sentinels are the ways the plan can end. The interesting design decisions are in what the language refuses to let you write.

Total, on purpose#
TOL is a total language: every well-formed plan provably terminates. There is no while (true), no unbounded recursion, no way to express a plan that runs forever. Loops exist ("revise until the client approves") but every iteration construct carries a hard ceiling, so even a "repeat until" is a bounded object with a known worst case.
Totality sounds like a restriction, and it is one, deliberately. The benefit is what it makes possible: exhaustive analysis. Because every plan halts, the engine can simulate the entire plan thousands of times, enumerate its reachable endings, compute the full probability distribution over completion dates, and check structural invariants, all without ever worrying about the halting problem. A Turing-complete planning language would be strictly more expressive and strictly less knowable. For plans, knowable wins. (We make the same trade in other domains without noticing: SQL, regular expressions, and spreadsheet formulas are all deliberately less than Turing-complete, and all the more analysable for it.)
This is also why the forecast can be deterministic. Same plan text, same seed, same forecast, byte for byte. The schedule and the odds are computed from the program; no model is guessing them.
A compiler for plans#
Text alone is not the win. Text plus a checker is. TOL ships with a validator that runs on every keystroke and enforces, at last count, around eighty structural invariants before a plan is allowed to execute: every task must reach a terminal state (no work that contributes to nothing), branches on an outcome must be exhaustive and mutually exclusive, dependency cycles are rejected with the offending loop named, container-level views must agree with task-level edges, and decomposition that exceeds working-memory limits gets flagged (we cap siblings at seven per container, after the 7 plus or minus 2 result from cognitive psychology; the validator literally lints for Miller's law).
If that sounds like a compiler, it is the same job: catch the class of error that is cheap to fix at authoring time and expensive to discover three weeks into execution. A drag-and-drop tool cannot do this, not because the vendors are lazy, but because pictures do not have formal semantics. Programs do.
The error messages behave like compiler errors too: they point at a line, they name the invariant, and fixing them is a local edit. There is a reason this matters beyond comfort, and it is the subject of the next section.
Text is the interface AI already speaks#
The quiet, compounding advantage of plans-as-text arrived with large language models. An LLM cannot drag nodes around your canvas. It can absolutely read a 700-line plan, notice that your launch has no rollback branch, and write the three edges that fix it.
Because TOL is text with a public specification (the full handbook is one markdown file, free to download), any capable model can author it: ours, or the one you already pay for. And because the validator is deterministic, you do not have to trust the model. It drafts; the engine checks; errors go back to the model; the loop converges to a plan with zero structural errors. The AI never touches the math. That workflow, bring your own AI, gets its own article, and it only exists because the plan is a program.
"I am not going to write code to plan my week"#
You do not have to. This is the part people miss about plans-as-code: the text being there does not mean the text is the only interface. Topolog's IDE is a full visual editor; the graph view, the inspector panels, and the AI builders all read and write TOL for you, the same way a design tool writes vector files you never open. Most users never type a line.
The text matters the way your contract matters: not because you read it daily, but because when something important is at stake, there is a precise artifact to consult. The day you want to know exactly what changed since the version that forecast March instead of May, the diff is right there:
| Without source | With source |
|---|---|
| "Someone changed something in the plan last month" | A two-line diff: an estimate went from 12h to 30h, and a new dependency appeared |
| Plan review = squinting at a screenshot | Plan review = reading the gates and edges, like code review |
| Reuse = rebuild it by hand in the new project | Reuse = copy the block, rename the agents |
| Tool migration = export to CSV and weep | The plan is a text file; it is already portable |
The deepest claim of plans-as-code is not about tooling at all. Writing a plan in a language with semantics forces the ambiguity out: every dependency is explicit, every branch covered, every loop bounded, every ending named. Half the value is that the engine can then forecast the plan. The other half is what you learn about the plan while making it expressible at all.