Turns a sentence into a typed, frozen, self-hashing contract. Fills the gaps that do not change the shape of the system and names every one of them out loud.
Spec into a DAG of bounded nodes. Each declares its dependencies, its capabilities and its outputs before it runs. Cycles die here, not mid-build.
Four states per action. Two pinned so no config can delegate a credential or a payment. Everything held is batched into a single review, never drip-fed.
Walks the plan, asks the provider for bytes, checks the gate before every write. A node that writes a file it never declared is an error, not a warning.
Checks the tree against the contract — never against the plan. A plan that completed only tells you the agent did what it decided to do, which nobody asked.
Append-only, hash-chained. Stopping a run does not undo it, so the next best thing is that nothing it did can be quietly rewritten afterwards.
A developer reading the always-on agent launches put it in one line: my throughput is limited by my approval. If that is true, a faster agent does not help you. A second does not help. Fifty do not help. They deepen the queue in front of the same bottleneck.
Every approval point is a wake-up you scheduled for yourself. Eleven of them in a routine is eleven interruptions, and by the tenth you are clicking without reading — including the one that mattered.
So DOTS does not compete on speed. It produces one artifact worth exactly one review, and it is built so that review can be short: the contract is explicit, the assumptions are listed, the bounds are enforced, and the result is reproducible enough that reading the diff is the whole job.
prompt │ ├─ RESOLVE sentence → typed, frozen, self-hashing contract ├─ PLAN DAG of nodes, each declaring what it may touch ├─ GATE one pass over the plan, before the first write ├─ BUILD content-addressed, every write checked ├─ VERIFY against the spec, never against the plan └─ LEDGER append-only, hash-chained, replayable
Each stage is a separate object, a separate command and a separate failure class, because the interesting failures happen between stages.
An approval list has a hard limit before it stops working as one. Past a handful of prompts per run, people approve on reflex — so DOTS reports its own overuse rather than waiting to be noticed:
! 5 approval points in one run (ceiling 3). Move the routine ones to allow or to handoff — a long queue gets approved on reflex.
Pick the two or three moments where human judgement changes the outcome. Everything else goes up into allow or down into handoff. A gate you actually obey beats a gate you merely have.
# dots.toml [gate] ceiling = 3 preapproved = ["secrets.read"] [policy] "fs.write" = "allow" "net.http" = "allow" "notify.outbound" = "ask" "shell.exec" = "ask" "secrets.rotate" = "handoff" # pinned "funds.transfer" = "handoff" # pinned
Try to move a pinned class and the config is rejected at load time, not ignored at run time.
| file | does |
|---|---|
| hashing.py | Canonical JSON, four digest kinds, directory walk |
| spec.py | Resolver, Spec, Check, Assumption, ambiguity budget |
| planner.py | DAG, stable topological order, wave grouping |
| gate.py | Four states, pinned classes, batch review, ceiling |
| builder.py | Content-addressed cache, output enforcement |
| verifier.py | Five check kinds, AST parse pass, manifest match |
| ledger.py | Append-only JSONL with a hash chain |
| config.py | dots.toml, with a reader fallback for 3.10 |
| cli.py | Eight commands, --json on all of them |
| providers/ | Pluggable emitters behind one determinism contract |
| code | class |
|---|---|
| 0 | sealed and verified |
| 1 | DotsError — generic |
| 2 | ResolveError |
| 3 | AmbiguityError — strict mode |
| 4 | PlanError — cycle or dangling need |
| 5 | BuildError — node failed or over-reached |
| 6 | VerifyError — or replay drift |
| 7 | GateError — blocked or handed off |
| 8 | LedgerError — chain broken |
Distinct per failure class so CI branches on what went wrong instead of grepping stderr.
# no dependencies, no keys, no build step git clone https://github.com/0xwast3/dots.git cd dots && pip install -e . dots build "poll the odds api every 5 minutes and alert me on a 10% swing" ●●●● odds-watch run a0eaf93ee021 spec e67b2937a40b plan bb533e6d12f1 (9 nodes, 0 cached) tree c43ae69ed5ef checks pass 8/8 review ask 1 · handoff 0 sealed reproducible # the only honest test of determinism dots replay a0eaf93ee021 recorded c43ae69ed5ef replayed c43ae69ed5ef identical
| boundary | what it buys |
|---|---|
| spec digest | a lock cannot be edited into saying something else |
| node outputs | a node cannot write outside what it declared |
| pre-flight gate | a refusal costs nothing instead of a tree |
| pinned classes | no config delegates a credential or a payment |
| tree digest | "the same build" is measured, not claimed |
| hash chain | a quiet change becomes a loud one |