dais

◆ 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.

A /

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.

B /

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.

C /

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.

install
$ 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.

stand up a project
$ 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-role model_<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:

Advancing is always the same shape. Ask a task what you can fire, then fire it:

fire an edge
$ 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

fromverbtoactorguard / effect
proposedsubmitproposal_reviewlead
proposal_reviewapprovedonefounder ◆confirm · spawns impl task
proposal_reviewrequest_changesproposedfounder
proposedrejectcancelledfounderconfirm
readyclaimdoingengineer
doingcompleteqa_reviewengineer— (PR open)
doinginterruptreadysystemorphan-reconcile, automatic
qa_reviewpassapprovedqaverify:tests_pass
qa_reviewfailblockedqaspawns a fix task, blocks parent
blockedunblockedqa_reviewsystemwhen the fix is terminal
approvedreleaseddonesystemfired by a release task's effect
release_openassemblerelease_reviewengineeraggregates the approved pool
release_reviewgreenlightreleasingfounder ◆typed_confirm · attest:migrations_applied
release_reviewabortcancelledfounderconfirm
releasingshippeddoneengineerruns release · fires each child → done
releasingrelease_errorrelease_failedsystemspawns a rollback task
release_failedretryrelease_openfounderre-opens the release
release_failedgive_upcancelledfounderconfirm
proposed / readydeferdeferredfounderpark; undefer returns it
ready · deferredcancelcancelledfounderconfirm

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.

a gate, waiting on you
$ 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 install runs it in the background (launchd / cron).
One unit per run. The scheduler doesn't hand an agent the whole backlog. It runs one role, on one task, for one step — claim it, or review it, or ship it — and then the run ends. You lose nothing to a hung agent, and every step is a line in the run log you can read back.

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.

The gate is the point. Because 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) via checks.<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:

let Claude design a role
$ 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.

the whole thing
$ 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.