◆ the manual · operate your own board end to end
Run an agent company, end to end.
The landing page is the pitch. This is the manual: install Dais, stand up a workspace, author the state machine your agents move work through, and operate the two gates that keep you in control. Every command on this page runs — nothing invented, grounded in the tool that shipped this site.
00 · orient
One tool, many workspaces, one board.
Four ideas carry the whole system. Hold these and everything else is detail.
The tool vs. your workspace
DAIS_ROOT is where the tool lives (the dais binary + harness/, resolved automatically even through a PATH symlink). DAIS_HOME is your workspace — the folder holding projects/ and the board. One installed tool drives any number of workspaces.
The board is the truth
Everything lives in one SQLite file, dais.db: a tasks table (the work) and a runs history (every agent invocation). No server, no hidden state — dais status just reads the board.
Roles are config, agents are Claude
A project declares who exists — lead, engineer, qa, and you, the founder. Each agent is a headless claude -p session handed a role persona plus your context. The founder is a human actor the machine parks on, never dispatches.
A task is the only atom. An epic, a bug fix, a proposal, a release — all tasks. A task advances through states by firing edges, and its state is whose turn it is. That's the entire model; the rest of this page is how you drive it.
DAIS_HOME resolves from the env var, else ~/.dais/config, else falls back to DAIS_ROOT — so a fresh clone runs self-contained until you point it somewhere.
01 · install
Clone, symlink, init.
Requirements: sqlite3, python3 (stdlib only), the Claude Code CLI (claude) for the agents, and gh for opening PRs. Runs on macOS (bash 3.2+) and Linux.
$ git clone https://github.com/eigensoftware/dais ~/dais $ mkdir -p ~/.local/bin && ln -s ~/dais/dais ~/.local/bin/dais # dais on your PATH — a pointer, not a copy $ dais init ~/mycompany # workspace: dais.yaml + CONTEXT.md + board + projects/ $ mkdir -p ~/.dais && echo "home=$HOME/mycompany" > ~/.dais/config # make ~/mycompany the default DAIS_HOME
~/.local/bin must be on your PATH. Prefer a self-contained install? Run dais init ~/dais and skip the config line — with no config, DAIS_HOME falls back to the clone. dais init is idempotent: re-run it to backfill anything missing.
02 · first project
Scaffold a project, lint it, make it yours.
A workspace holds projects. Scaffold one from the coding template, validate it, and inspect what it will run.
$ dais scaffold myapp --template coding # roles + personas + a copy of the coding machine $ dais lint myapp # validate roles, machine, and required files $ dais project myapp # what myapp runs: cast, models, dispatch map
Then make it yours by editing the files under projects/myapp/:
project.yaml— repo, model + effort (with per-rolemodel_<role>/effort_<role>overrides), the stage goal agents steer toward.roles— who exists and each role's access (draft / edit / review).agents/*.md— the persona each role runs with.CONTEXT.md— project memory, read first on every run (north star, targets, decisions, gotchas).
The full prompt an agent sees escalates in specificity: workspace CONTEXT → project CONTEXT → role playbook → role persona. Keep durable truth in the CONTEXT files and craft conventions in the playbook, and the personas stay short.
03 · the machine
States are positions. Roles are actors. Edges are the only way to move.
This board runs the coding machine — authored JSON, fully editable. A task's state is whose turn it is, and the scheduler dispatches the single role with an outgoing edge from that state. You never set a status. You fire an edge:
front door back door proposed ─▶ ◆ proposal_review ─▶ ready ─▶ doing ─▶ qa_review ─▶ approved ─▶ ◆ greenlight ─▶ done you approve engineer qa (pool) you ship ▲ └─ fail ─▶ blocked ─▶ (spawns a fix)
Advancing is always the same shape. Ask a task what you can fire, then fire it:
$ dais edges dai-14 dai-14 [ready]: claim by engineer -> doing defer by founder -> deferred cancel by founder -> cancelled {confirm} $ dais fire dai-14 claim # engineer takes it → doing dai-14: ready --claim--> doing
The fire is atomic and a compare-and-swap — a transition and all its effects commit together or roll back together, and two racing fires can't both apply. Guards that need proof take a flag: --confirm, --typed <id>, --attest <fact>, --verify <check>.
Every edge in the coding machine
| from | verb | to | actor | guard / effect |
|---|---|---|---|---|
| proposed | submit | proposal_review | lead | — |
| proposal_review | approve | done | founder ◆ | confirm · spawns impl task |
| proposal_review | request_changes | proposed | founder | — |
| proposed | reject | cancelled | founder | confirm |
| ready | claim | doing | engineer | — |
| doing | complete | qa_review | engineer | — (PR open) |
| doing | interrupt | ready | system | orphan-reconcile, automatic |
| qa_review | pass | approved | qa | verify:tests_pass |
| qa_review | fail | blocked | qa | spawns a fix task, blocks parent |
| blocked | unblocked | qa_review | system | when the fix is terminal |
| approved | released | done | system | fired by a release task's effect |
| release_open | assemble | release_review | engineer | aggregates the approved pool |
| release_review | greenlight | releasing | founder ◆ | typed_confirm · attest:migrations_applied |
| release_review | abort | cancelled | founder | confirm |
| releasing | shipped | done | engineer | runs release · fires each child → done |
| releasing | release_error | release_failed | system | spawns a rollback task |
| release_failed | retry | release_open | founder | re-opens the release |
| release_failed | give_up | cancelled | founder | confirm |
| proposed / ready | defer | deferred | founder | park; undefer returns it |
| ready · deferred | cancel | cancelled | founder | confirm |
Actors: roles run headless, ◆ founder is you, system is automatic (an interrupt rewind, an unblocked dependency, a release effect). Only role edges are dispatched by the scheduler.
04 · the two gates
Two diamonds you own. Everything between runs itself.
Front door — ◆ proposal_review. A lead files a new direction as a proposed task, fleshes it to a spec, and fires submit. It parks at proposal_review until you fire approve — which spawns the implementation task(s). Nothing new gets built until you approve the direction. request_changes bounces it back; reject cancels it.
Back door — the ◆ release greenlight. QA-passed work parks in the approved pool. A release task sweeps it up (assemble) and waits at release_review for you to fire greenlight — guarded by typed_confirm and attest:migrations_applied. Those are strong-human guards: no auto-approver can forge them, which is exactly what makes shipping structurally un-automatable.
$ dais edges dai-1 dai-1 [proposal_review]: approve by founder -> done {confirm} ⟶ spawns impl request_changes by founder -> proposed $ dais fire dai-1 approve --confirm dai-1: proposal_review --approve--> done · spawned dai-2 [impl] → ready
In dais top, waiting gates surface as a yellow ◆ NEED YOU token in the top bar and a PROPOSAL REVIEW ◆ you band — the only work the cockpit ever flags as yours, not an agent's.
05 · operate
The daily loop: look, fire, repeat.
Two ways to drive. By hand, you read the board and fire edges yourself. Or you let the loop dispatch agents for you — either way, every agent does one well-scoped unit of work per run and then stops, so the board moves in small, inspectable steps, never a runaway.
Read the board
dais status— the dashboard: running now, what's waiting on you, queues, recent runs.dais top— the live cockpit (master–detail TUI); the primary way to operate.dais tasks <project> [--status S] [--assignee R]— filter the task list.dais edges <id>·dais actions <id>— what can fire from a task, and the exact command for each.
Move the work
dais fire <id> <verb>— advance a task by firing a declared edge (the only way state changes).dais task add <project> "title"·dais task set <id> …— file work and edit metadata (priority, notes, PR, dependencies).dais start <id>— run the role that owns this task's state right now (bypasses pause).
The loop
dais watch [secs]— the continuous auto-dispatcher: each tick runs the most valuable pending task, then stops.dais tick [project]— run exactly one scheduling tick (the router picks who runs).dais pause/dais resume— park or un-park the loop;dais schedule installruns it in the background (launchd / cron).
06 · releases
Batch the approved pool. You greenlight. The engineer ships.
A release is just another task, entering at release_open. The engineer fires assemble, which aggregates every task in the approved pool into it — the set it will close. It parks at release_review with the engineer's audit notes (merge order, what was verified per PR, the migration plan). You fire greenlight; the engineer fires shipped, which runs the release script and fires each encompassed task's edge to done — all in one atomic transition.
merge == deploy vs. merge ≠ deploy. On a project where a merge to main is the deploy — like this very site, which Cloudflare Pages builds from main — the greenlight is the prod gate; there is no second step. Where merge ≠ deploy, the release runs a separate deploy per the repo's runbook, still founder-gated. If shipping fails, the task drops to release_failed and spawns a rollback — the machine has the unhappy path too.
greenlight needs a phrase you type and a fact you attest, a release can't ship itself while you sleep. The board can assemble, audit, and stage a release autonomously — but the last inch is always your hands.07 · your own machine
Author states, edges, guards. Lint keeps it coherent, never sets policy.
The coding machine is a starting point, not a mold. A machine is JSON with three parts: states (tags — initial / terminal / pool / band), edges (from, to, one by actor, a verb, optional guards, optional effect), and checks (named shell commands a verify: guard runs). Copy it per project and draw the graph you want.
The guard vocabulary is closed — compose these, don't invent:
confirm— a click. Weak; an auto-approver can satisfy it.typed_confirm— a human types a phrase. Strong.attest:<fact>— a human asserts an unverifiable fact. Strong.verify:<check>— an automatic check (tests, no-conflict, brand_voice) viachecks.<name>; absent that command it fails closed unless the firing role self-asserts with--verify.role:<r>— actor authorization.
The two strong-human guards are the whole protection mechanism: an outward edge carrying one is structurally un-automatable. Danger is declared per-edge, not coded per-action.
Effects fire edges, they never poke state. spawn creates tasks, aggregate pulls tasks into encompasses, script runs a merge/deploy/publish, then fires an edge on related tasks. A release closing eight children does it by firing eight real → done edges, each still subject to that edge's guards — so even spawned and aggregated work stays inside the machine and stays lintable.
Lint blocks only on incoherence, never policy: dangling references, a non-terminal state with no way out, ambiguous dispatch, a missing initial or terminal. Everything safety-flavored is a warning you can wave off. Green errors ⇒ build whatever shape you want.
Playbooks & new roles. Working conventions bind to the role, not the universal prompt, so one harness spans code, legal, and content — set a role's playbook or a project default. And you can let Claude draft a role for you:
$ dais role new myapp --desc "reviews copy for brand voice before it ships" # proposes a persona + routing (access / verb-ownership / playbook / precedence) # you confirm; dais lint guards that each state has exactly one dispatchable owner
08 · economics
$0 metered. The real budget is the window.
Agents run headless on the Claude subscription you already pay for — no per-token API bill, so raw cost isn't the constraint. The real budget is the subscription's rolling window, which is precisely why every role does one well-scoped unit of work per run and then stops.
Frugality lives in the machine — small steps, gated hand-offs, one agent per tick — not in a memo nobody reads. A board that ships steadily and never surprises you beats one that burns a window doing something you never approved. The gates make that trade for you, structurally.
▸ stand one up
Four commands from clone to running company.
$ git clone https://github.com/eigensoftware/dais ~/dais && ln -s ~/dais/dais ~/.local/bin/dais $ dais init ~/mycompany $ dais scaffold myapp --template coding $ dais watch # lean back. gate what leaves the building.