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 run headless

A project declares who exists: lead, engineer, qa, and you, the founder. Each role is one agents/<role>.md file: config in the frontmatter, persona below. An agent runs headless on Claude by default, or on OpenAI's Codex when a role sets provider: openai. 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

Install, init, point it.

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 · homebrew
$ brew install eigensoftware/dais/dais
                                    # or: brew tap eigensoftware/dais && brew install dais

$ 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

Dais drives the Claude Code CLI, so install that separately (and OpenAI's codex CLI if any role sets provider: openai); brew install alone won't run agents. dais init is idempotent: re-run it to backfill anything missing.

From source (or to track main): clone and symlink the launcher onto your PATH, a pointer, not a copy.

install · from source
$ 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)

~/.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.

02 · first project

Scaffold a project, lint it, make it yours.

A workspace holds projects. Scaffold one from a stock template, validate it, and inspect what it will run. Four ship with the tool: coding (the full lifecycle this walkthrough uses), lean (one builder, your review is the gate), advisory (decisions, not code; zero outward edges), and marketing (a content lane).

stand up a project
$ dais scaffold myapp --template coding   # roles + personas + a copy of the coding machine
$ dais lint myapp                          # validate config, 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/:

  • agents/*.md: the cast. Each file is one role: config in the YAML frontmatter (model, effort, provider, auth, trigger, playbook), persona prose below.
  • machine.json: the lifecycle, and the roles block that owns each role's access (draft / edit / review).
  • project.yaml: repo, workspace-wide defaults (model, provider, playbook), the stage goal agents steer toward.
  • 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.

Providers: Claude or Codex, per role. Every role runs on Claude by default; set provider: openai in a role's frontmatter to run it on OpenAI's Codex instead, so a mixed org works (Codex QA reviewing Claude-built code). auth: subscription (the default) uses the provider CLI's own login; auth: api is metered and reads the provider's key from your environment or a gitignored .env, never from a config file.

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·
proposedpromotereadyleadthe routine lane: follow-ups of approved work skip the gate
proposal_reviewapprovedonefounder ◆confirm · spawns impl task
proposal_reviewrequest_changesproposedfounder·
proposedrejectcancelledfounderconfirm
noteacknowledgedonefounderread it and close it; an FYI never becomes a build
readyclaimdoingengineer·
readyneeds_designdesignengineersend it down the design lane before building
designdesign_donereadydesignerhands the spec back to the build queue
designreview_donedonedesignera review-only pass, nothing left to build
designskip_designreadyfounderoverrule the detour, build it as filed
designinvalidatecancelleddesignerattest:invalid
designdeferdeferredfounderpark it mid-design
doingcompleteqa_reviewengineeropens a PR
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
approvedcancelcancelledfounderconfirm · pull work out of the pool before it ships
release_openassemblerelease_reviewengineeraggregates the approved pool
release_reviewgreenlightreleasingfounder ◆typed_confirm · attest:migration_reviewed
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
deferredundefer@historyfounderback to whichever state it was parked from
ready · deferredcancelcancelledfounderconfirm
readyinvalidatecancelledengineerattest:invalid · the one edge an agent may cancel: retire a false-premise task (duplicate, moot, defect that doesn't exist)

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.

The design lane. Not every ready task should go straight to code. When an engineer picks one up and finds the shape is undecided, they fire needs_design instead of claiming it, and the task moves to design where the designer role owns it. The designer either fires design_done to hand a decided spec back to ready, or review_done when the pass was a review and there is nothing left to build. You can overrule the detour at any point with skip_design, which puts the task back in the build queue as filed. It is a real lane with a real role, not a status label: the same rule holds that a task in design is dispatched to the designer and nobody else.

The note state. note is for things filed at you rather than for you to build. An agent files what it learned or noticed, you read it, and you fire acknowledge to close it out. No impl task gets spawned, which is the whole point: an FYI that cannot quietly turn into work.

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:migration_reviewed. 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: a one-glance dashboard of what's running now, what's waiting on you, the queues, and 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 stock machines are starting points, not molds. 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

No metered bills by default. The real budget is the window.

By default, agents run headless on the AI subscription you already pay for: your Claude plan, or a ChatGPT plan for roles you set to provider: openai. That default means no per-token API bill, so raw cost isn't the constraint. The real budget is the plan's rolling window, which is precisely why every role does one well-scoped unit of work per run and then stops.

Metering is an explicit opt-in: a role that sets auth: api runs against the provider's API key (ANTHROPIC_API_KEY or OPENAI_API_KEY) instead of the CLI login, and is billed per token. Nothing meters unless a role's frontmatter asks for it, so you reach for API auth deliberately, role by role.

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 install to running company.

the whole thing
$ brew install eigensoftware/dais/dais
$ dais init ~/mycompany
$ dais scaffold myapp --template coding
$ dais watch                        # lean back. gate what leaves the building.