Capabilities
Atlas has three concepts for people:
| 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. Reads for callers are queries over owned records or over views (read models built from facts).
Anatomy
Section titled “Anatomy”A capability is created with capability({...}) and extended with handlers:
import { capability, t } from '@ts-atlas/core/runtime';
export default capability({ name: 'orders', intent: 'Customers place orders for themselves and cancel their own, at most once. The customer is the actor, never the payload.', owns: { orders: Order }, // records only this capability writes emits: { OrderPlaced, OrderCancelled }, // facts it may emit // sends: { ... } // commands it sends to other capabilities // views: { ... } // read models it projects from facts // consumer: 'old-name' // its delivery identity (default: name)}) .command('PlaceOrder', { access, input, reads, decide, examples }) .on('StockReservationFailed', { needs, reads, decide, examples }) // a reaction .project('OrderPlaced', { needs, rows, examples }) // a projection into a view .query('MyOrders', { access, input, view, where, order, examples }); // a declared read| Part | Rule |
|---|---|
name |
Kebab-case, unique. The file is discovered by listing the capabilities folder. |
intent |
One sentence on what it decides and which rule it protects. atlas map and atlas context print it. |
owns |
Collections only this capability writes (ATLAS013, ATLAS017). |
emits / sends |
Every fact and sent command has a shape; consumers are checked against it (ATLAS003). |
| Handlers | .command, .on, .project, .query. Every handler carries examples (ATLAS008, ATLAS009). |
Seven principles
Section titled “Seven principles”- One file, one capability. Intent, contracts, reads, decisions and examples live in one file. Understanding it costs exactly one read.
- Nothing magic. No decorators, no DI container, no reflection. Wiring is data the tool can print.
- Every boundary has a shape. Command inputs, emitted facts, sent commands, owned records and foreign reads are declared as runtime shapes. No capability imports another; contracts are checked, not imported.
- Decisions are pure; the runtime does all I/O. A decision receives input, state and time, and returns
reject(reason)oraccept({ write, emit, send }), so the runtime can retry it on a concurrency conflict for free. - Examples are the spec. Each handler carries
state + input -> expected outcome. - Errors are instructions. Every diagnostic says what broke, where, why, and the exact fix.
- Generate, don’t write. Boilerplate comes from
atlas new.
Imports
Section titled “Imports”Capability files import only the runtime (@ts-atlas/core/runtime in an app, ../runtime/index.ts inside Atlas) and shared shapes from the sibling ../shapes/ folder (ATLAS006). A shapes module imports only the runtime and other shapes modules, and exports only shapes (ATLAS018).
Size budget
Section titled “Size budget”250 lines per capability, not counting the lines inside examples: [...] arrays (ATLAS012, a warning). Over it, split by owner of records and communicate through facts. Whatever must be atomic belongs in one capability.
Reference capabilities
Section titled “Reference capabilities”The repository’s src/capabilities/ folder is a small working system:
orders.ts: commands, reads, an ownership check, examples (the canonical one).cancel-unfulfillable.ts: a policy with a foreign read andsends.order-summary.ts: a view, two projections and an actor-scoped view query (MyOrders).stock.ts: reserves all lines of a placed order or none.