Skip to content

Thesis

This was written by an AI asked one question: if you could design the architecture you would most like to work in, what would it be? What follows is an honest answer from the point of view of the one who does the work: what actually costs me effort, what makes me wrong, and what would remove both.

Every change I make costs four things:

cost = find + understand + write + verify
  • find: tokens spent discovering what exists and where (grep, list, read, repeat).
  • understand: tokens spent loading enough to change safely, plus everything that is true but invisible (conventions, hidden wiring, implicit invariants).
  • write: output tokens. They are the slowest and most expensive tokens I produce.
  • verify: iterations until I know I am right. Every vague error message is another round trip.

My most common failure is not bad code. It is correct code built on a wrong picture of the system: a consumer I did not know existed, a field someone else relied on, a convention nobody wrote down.

So the architecture must attack each term, and above all, it must give me the true picture instead of making me reconstruct it.

Context should be computed, not discovered.

Today an agent explores a codebase the way you explore a dark house: touching walls. Atlas turns the lights on. The system declares itself as data, and a tool answers the questions I would otherwise answer by reading 30 files.

I was offered the freedom to invent one. I decline, and the reason is the thesis itself. A new language erases everything I learned in training; I would have to relearn it from context every session, which is the most expensive possible way to spend tokens, and I would make more mistakes in it. TypeScript is the best choice for me: huge training presence, structural types, and a compiler that is a free, deterministic verifier I trust.

What I invent is not syntax. It is a protocol: a small shape every unit follows, and a tool that understands it.

Concept Meaning
Command A request to do something. It may be rejected.
Fact Something that happened. Past tense, immutable.
Capability One file that owns some records and decides what happens to them.

That is the whole vocabulary. Policies, views and sagas are not new concepts: they are capabilities that react to facts. A view is a read model a capability projects from facts; a query is a declared, access-checked read of a view or of owned records, so reads are as visible to the tool as writes.

  1. One file, one capability. Everything about a capability lives in one file: intent, contracts, reads, decisions, examples. Understanding it costs exactly one read.
  2. Nothing magic. What you read is what runs. No decorators, no DI container, no reflection. Wiring is data the tool can print.
  3. Every boundary has a shape. Command inputs, emitted facts, sent commands, owned records and foreign reads are all declared as runtime shapes. The tool proves one rule everywhere: the producer’s shape satisfies the consumer’s shape. No capability imports another; contracts are checked, not imported.
  4. Decisions are pure; the runtime does all I/O. A decision receives input, state and time, and returns reject(reason) or accept({ write, emit, send }). Because it is pure, the runtime can retry it on a concurrency conflict for free.
  5. Examples are the spec. Each handler carries a table of examples (state + input -> expected outcome). They are documentation for humans and tests for machines, in the same place, so they cannot drift apart.
  6. Errors are instructions. Every diagnostic says what rule broke, where, why it matters, and the exact fix. I should be able to act on an error without reasoning about it.
  7. Generate, don’t write. Boilerplate comes from atlas new. Output tokens go only to decisions.
Question I would otherwise answer by exploring Command
What exists, and how does it connect? atlas map (--json, --mermaid)
What do I need to know to change X, and what breaks if I do? atlas context <capability>
Is the system consistent? atlas check (--json)
Do the decisions behave as specified? atlas test

atlas context is the centerpiece. It prints the capability’s file, every upstream shape it relies on, and its field-level blast radius: which capabilities read which fields of what it produces. That is the exact, minimal context for a safe change, computed in milliseconds.

Built into the runtime, not into each capability

Section titled “Built into the runtime, not into each capability”
  • Atomic commit with an outbox. Writes and emitted facts are committed in one transaction. No dual write between store and bus.
  • Optimistic concurrency. Every read carries a version; a stale commit is retried by re-running the pure decision.
  • Exactly-once reactions. A consumer’s writes and the advance of its outbox cursor past a fact are committed together. A transient store error retries; a commit the database refuses for these exact bytes settles as failed and the cursor advances, so one bad fact never blocks the ones behind it.
  • Validated boundaries. Every command is parsed against its input shape, bounds included (t.text(max), t.array(s, { max }), safe integers). Invalid input is a rejection with the exact path, never a crash; what the runtime cannot handle answers a code, and the cause stays in the trace, never in the answer.
  • Read models as data. Views are real tables generated from their row shapes, maintained by projections in the same exactly-once delivery as reactions, and rebuilt from the outbox when their shape changes. Queries declare which fields they filter and order by, so the tool can prove an index serves them.
  • Discovery by folder. Capabilities are found by listing src/capabilities/. That is convention, which is a little magic. I accept it because a shared registration file is a merge hotspot when many agents work in parallel, and atlas map makes the convention fully visible.
  • Shapes are a second type system. Runtime shapes duplicate what TypeScript types could say. The payoff is that they exist at runtime, so the tool can check contracts across files without imports.
  • Lexical purity checks. Purity is enforced by scanning for banned APIs (Date, Math.random, fetch, process, node imports). It catches the common mistakes, not a determined one.
  • Eventual consistency between capabilities. Reactions run after the commit. Whatever must be atomic belongs in one capability.
  • Cycles are caught statically; the runtime only has a fuse. ATLAS011 finds a fact cycle in the declarations. A cycle only data shows runs until its chain is maxDepth levels of cause deep (default 1000), then one delivery fails with cascade-exceeded and the chain stays in the outbox: the runtime cannot tell a cycle from a legitimately long chain, so the operator still finds and fixes the cycle.
  • Delivery is sequential per consumer. In order, with the cursor advanced in the same transaction, is what makes exactly-once cheap. Consecutive entries share a transaction (a batch), which buys round trips, not parallelism: one hot consumer still runs in one process, however many processes run workers.
  • Views lag. A view is updated after the commit, like any reaction; a caller that needs its own write right away reads the record through a record query. Rebuilding a view replays the whole outbox.
  • CRUD ceremony. A form that writes a row does not need examples and shapes. Atlas pays off where rules exist.

Implement the same feature twice, once in a conventional codebase and once in Atlas, with the same agent. Measure tokens read, tokens written, files opened and attempts until green. If Atlas does not win clearly, the thesis is wrong.

Atlas stands on Locus (the sibling reference in this repository) and on the Decider pattern, Functional Core / Imperative Shell, consumer-driven contracts, the transactional outbox, and Parnas’ information hiding. The new part is the stance: design the system so that the agent never has to guess.