Data model
Status: draftSQLite, single file, WAL. An append-only events table is the source of truth; state tables are projections the daemon maintains in the same transaction. Rebuildable by replay.
projects id, root, common_dir, name, discovered, sort_order, icon, color, created_at
sessions id (CC session id), project_id, kind (interactive|spawned|subagent), parent_id,
cwd, worktree, model, started_at, ended_at, last_seen_at, tokens_in/out, cost_usd
claims id, project_id, task, owner_session_id, owner_label, worktree, branch,
acquired_at, expires_at, released_at, state (held|expired|released|reaped|orphaned)
handoffs id, claim_id, done, remaining, files_json, verify, created_at
resources name, project_id, kind (port|process|custom), owner, session_id, pid, port,
acquired_at, expires_at, released
processes pid, start_time, project_id, session_id, kind, port, cwd, cmd_label, started_at, ended_at
gates id, project_id, task, gate, verdict (pass|fail), rubric, evidence, session_id, created_at
events seq, ts, project_id, session_id, type, payload_json -- append only
incidents id, project_id, session_id, kind, detail, created_at, acked_at
Actor (M8.2a). Every ledger row above (claims, resources, processes, handoffs, gates, incident_acks, sessions) and every events row carries actor_kind (human | agent | run | daemon) + actor_id (OS user / OIDC subject · session id · run id · daemon); events expose it as actor: {kind, id, session?}. Until the daemon authenticates callers (M8.2b) it derives the actor from the owner/by string and session id the client sends (core/src/actor.ts actorFrom); the same rule back-filled existing rows in schema migration v1. Schema changes that need a back-fill go through the versioned migrate() list in the store (meta.schema_version, reported by /v1/health and swarm doctor).
Rules of the ledger:
- A
taskmay have at most oneheldclaim. Claiming a held task fails with the holder's details. expires_atadvances on renew and on any hook activity from the holder session.- The reaper moves expired claims to
reapedonly if the worktree is clean and pushed; otherwise toorphanedand opens an incident. Orphaned claims still block re-claim until a human resolves. - A gate's latest run decides. Failed runs are never deleted. A run without
rubricis rejected. - A resource is a named singleton per project (
web) or per machine (port:3000). Acquiring a held resource fails with holder details.
Task sources: a task is just a string; Swarm does not own the backlog. A project may declare a task source in .swarm.toml (tasks = "docs/planning/52-implementation-plan.md") with a parser (markdown-table first), so the dashboard can show titles/status and the "pick next unclaimed task whose deps are ✅" query can be answered. Without a source, tasks are free-form.
Source: docs/03-data-model.md · v0.8.0.