https://github.com/arjia-labs/clu
Local-first SQLite issue tracker for coordinating AI coding agents β atomic claim, dependency graphs, workflows & checkpoints, audit log. No daemon, no network.
https://github.com/arjia-labs/clu
agent-orchestration ai-agents cli developer-tools go golang issue-tracker local-first multi-agent sqlite task-management workflow-engine
Last synced: about 23 hours ago
JSON representation
Local-first SQLite issue tracker for coordinating AI coding agents β atomic claim, dependency graphs, workflows & checkpoints, audit log. No daemon, no network.
- Host: GitHub
- URL: https://github.com/arjia-labs/clu
- Owner: Arjia-Labs
- License: mit
- Created: 2026-05-26T04:36:43.000Z (2 months ago)
- Default Branch: main
- Last Pushed: 2026-07-17T07:20:45.000Z (21 days ago)
- Last Synced: 2026-07-25T10:18:42.646Z (12 days ago)
- Topics: agent-orchestration, ai-agents, cli, developer-tools, go, golang, issue-tracker, local-first, multi-agent, sqlite, task-management, workflow-engine
- Language: Go
- Homepage: https://arjia-labs.github.io/clu/
- Size: 8.15 MB
- Stars: 7
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Security: SECURITY.md
- Agents: AGENTS.md
Awesome Lists containing this project
- awesome-cli-coding-agents - clu - backed issue tracker for coordinating fleets of AI coding agents. Atomic task claim, dependency graphs, workflows & checkpoints, and an audit log. CLI-native with clean `--json` output, built to be driven by agents. Go. (Harnesses & orchestration / Agent infrastructure)
README
clu
π€ SQLite-backed issue tracker for coordinating AI coding agents on a single machine.
Named after Tron's Codified Likeness Utility.
Docs Β·
Quickstart Β·
Multi-agent Β·
Bulk graphs Β·
Workflows Β·
Agent guide Β·
Design
---
## π€ Why?
When you run more than one AI coding session against the same project, they need a shared, durable place to:
- π€ pick up work without stepping on each other (atomic claim),
- π record what they tried, what worked, what didn't,
- π¦ gate risky steps behind human approval,
- π surface what's unblocked vs. waiting on something else.
`clu` is that place. A small, fast, single-binary CLI backed by a local SQLite database. **No daemon, no server, no account, no network.**
## β¨ Highlights
| | |
|---|---|
| π¦ **Single binary, pure Go** | SQLite via `modernc.org/sqlite` β no CGo, no system libs. |
| πΎ **Local-first** | One file: `.clu/data.sqlite`. Commit `config.yaml`, gitignore the DB. |
| β‘ **Atomic claim** | `UPDATE β¦ RETURNING` with subquery β racing agents get different issues. |
| π― **Capability routing** | Agents declare capabilities in `config.yaml`; `cap:foo` labels flow to matching agents. |
| πΈοΈ **Bulk graph instantiation** | `clu batch` turns one JSON doc into a whole validated graph (thousands of issues + deps) in one transaction β generate it with any script. |
| π **Cascading cancel** | `clu cancel ` walks the dep graph forward and cancels the whole tail. |
| π **Milestones & phases** | `milestone` issues auto-close when their dependencies do β self-completing umbrellas and automatic phase boundaries. |
| π§Ύ **Audit log** | Every write is recorded; `clu history ` and `clu log` show who did what, when. |
| π§ **Context inheritance** | `clu claim --context` prints the upstream chain (notes + comments) so an agent inherits what was done before. |
| π **Agent launcher** | `clu agent start ` spawns a configured agent (command + layered prompts) and heartbeats it. |
| π **Workflow templates** | YAML graphs of issues + deps with optional human-approval checkpoints. |
| π **Named locks + mailbox** | TTL'd `clu lock` for shared resources; `clu ping`/`clu inbox` for fire-and-forget inter-agent messages. |
| π₯οΈ **Web UI** | `clu web` β a local dashboard: list, kanban, dependency graph, approvals. |
| π§Ύ **JSON everywhere** | Every command takes `--json` and emits exactly one JSON value to stdout. |
| πΏ **Branchless sync** *(experimental)* | `clu sync` stores issues on a dedicated git ref (`refs/clu/store`) β branch-independent, no conflicts with code, syncs across clones. [Details](docs/content/docs/sync.mdx). |
| π **No network** | No telemetry, no cloud, no account. Sharing is opt-in over *your own* git remote. |
## π₯οΈ Web UI
`clu web` serves a local dashboard (default `:5757`) over the same SQLite file β no extra config, no separate API to run.

Board β kanban by status, with avatars and how long each task has been in progress.

List β every issue with priority, status, and started_at ("started 3h ago").

Approvals β pending checkpoints with suggested approvers and what they block.

Detail β status/priority/type controls, the checkpoint gate, and dependency edges.
## π¦ Install
```bash
# From a clone (installs the CLI + the web UI bundle):
make install
# Or, just the CLI:
go install github.com/arjia-labs/clu/cmd/clu@latest
```
`make install` runs `go install` and then `clu web --install`, which
builds the web UI (`pnpm install` + `pnpm build`) and copies the
output to `~/.local/share/clu/web` so `clu web` works from any
directory. Skipped silently if pnpm isn't on PATH β the CLI works
without the UI.
Add `$HOME/go/bin` to your `PATH`. Verify with `clu --help`.
## π Quickstart
```bash
mkdir my-project && cd my-project
clu init # π creates .clu/ with DB + config
clu create -p 1 "fix the login redirect" # β clu-a3f81b
clu create -d clu-a3f81b "add tests for the redirect" # π wires the dep atomically
clu ready # π’ what's unblocked?
clu claim --context # π― take the next one + see its upstream context
clu close clu-a3f81b # β
done β unblocks the tests
clu ready # π’ tests are now ready
```
That's the whole core loop. See [`demo.sh`](demo.sh) for an end-to-end exercise, or [`AGENTS.md`](AGENTS.md) for the agent-facing operational guide. From inside an agent session:
```bash
clu brief
```
prints the agent guide plus the project's declared agents and who's currently live β pipe it into your agent at session start. π§
## π¦ Status semantics
| status | meaning | downstream effect |
|---|---|---|
| π’ `open` | not yet started | normal |
| π‘ `in_progress` | claimed; an agent is working | normal |
| β
`closed` | done successfully | **unblocks** dependents |
| β `cancelled` | abandoned | dependents stay blocked (or cascade-cancel) |
`clu cancel ` marks the target **and all transitive descendants** as cancelled β the cascade is the whole point of having a status distinct from `closed`. `clu reopen ` reverses either terminal state.
```mermaid
stateDiagram-v2
[*] --> open: create
open --> in_progress: claim
in_progress --> closed: close
in_progress --> cancelled: cancel
open --> cancelled: cancel
closed --> open: reopen
cancelled --> open: reopen
closed --> [*]
note right of closed: unblocks dependents
note right of cancelled: cascade-cancels the tail
```
Two type-driven behaviours sit on top of the status loop: a **`checkpoint`** issue is a manual gate (stays `checkpoint:pending` until `clu approve`), and a **`milestone`** issue *auto-closes* when all its dependencies close β the self-completing umbrella behind `clu batch --group` and phase boundaries. Issues also carry a `started_at` (set on claim, distinct from `updated`) so `clu show`, the web list, and `doctor`'s stuck-check know how long something's actually been in progress.
## π€ Multi-agent setup
Declare your agents in `.clu/config.yaml`:
```yaml
id_prefix: clu-
agents:
code-reviewer:
description: "Reviews Go code for correctness and security"
capabilities: [go-review, security-review]
doc-writer:
description: "Writes README + docs/ updates"
capabilities: [docs]
```
Then each agent claims from its own lane:
```bash
clu claim --agent code-reviewer --wait --heartbeat
```
`--heartbeat` is opt-in; without it the claim loop doesn't advertise liveness. With it, `clu agent ls` shows who's online and when they were last seen.
Coordinators route work by either **assigning directly** (`clu create -a doc-writer ...`) or **tagging capability** (`clu create --capability docs ...`). Capability-tagged issues in the default lane flow to whichever agent advertises that capability. Use `clu create --label urgent ...` when a normal label should be attached atomically with the new issue.
### π Launching agents
Give an agent a launch spec in `config.yaml` and start it with one command:
```yaml
agents:
code-reviewer:
capabilities: [go-review]
command: claude # the executable to run
prompts: [SOUL.md] # files under .clu/agents/code-reviewer/
startup_prompt: "Check clu inbox -a code-reviewer, then claim ready work."
```
```bash
clu agent start code-reviewer # exec the agent, heartbeating while it runs
clu agent start code-reviewer --print # just show the assembled command
```
Any `*.md` in `.clu/agents/_shared/` is prepended to **every** agent (a common `AGENTS.md` / `AUTONOMY.md` lives in one place, not copied per agent); the agent's own prompts layer on top. clu stays runtime-agnostic β `command` can be `claude`, `codex`, or anything.
### π§ Inheriting context
When an agent picks up a dependent task, `--context` walks the upstream chain and prints each prerequisite's description, notes, and comments β the story of what was done before:
```bash
clu claim --context # on claim
clu show --context # any time
```
### ποΈ Watching for work (the killer combo)
In Claude Code, point the Monitor tool at `clu ready --watch -a ` and you've got a push-style task feed: clu suppresses unchanged ticks, Monitor turns each new state into one notification. **No polling loops, no `while true`, no `diff` against `seen`.**
```
Monitor: clu ready --watch -a code-reviewer
```
See [AGENTS.md](AGENTS.md) for the full pattern.
## πΈοΈ Bulk graphs (`clu batch`)
`clu run` is for hand-authored YAML. When you want to **generate** work β
import a backlog, fan out a migration across modules, or build a thousand
interdependent tasks β produce a JSON document with any tool and pipe it to
`clu batch`. clu validates the whole graph (acyclic, every reference
resolves, fields valid) and writes it in **one transaction**: a single bad
entry aborts everything, so you never get a half-built graph.
```bash
generate-graph | clu batch --dry-run # validate + stats, write nothing
generate-graph | clu batch --group "Auth rollout" # commit under a self-completing umbrella
```
The contract is just JSON β an array of issues that reference each other by
local **alias**:
```json
[
{"alias": "design", "title": "Design auth", "priority": 1},
{"alias": "impl", "title": "Implement auth", "needs": ["design"], "capabilities": ["go"]},
{"alias": "gate", "title": "Approve release", "needs": ["impl"], "checkpoint": {"approvers": ["alice"]}},
{"alias": "ship", "title": "Ship", "needs": ["gate"]}
]
```
Run **`clu batch --docs`** for the full field reference. Highlights:
- **`needs`** takes aliases *or* existing real issue IDs β so a generated subgraph can hang off the committed graph.
- **`checkpoint`** makes an issue a manual approval gate (same as a `clu run` checkpoint).
- **`key`** (e.g. `"linear:ENG-123"`) makes re-running **idempotent** β `--on-existing skip` (default) won't duplicate it; `--on-existing update` re-syncs its fields. Perfect for a recurring import:
```bash
linear issue query --json | node examples/generators/linear-todo.js | clu batch --on-existing update
```
This is the **generation / instantiation split**: any language emits the graph (loops, conditionals, computed fan-out β things a static template can't do); clu owns validation and atomic instantiation. See [`examples/generators/`](examples/generators/) for a zero-dependency JS helper (`clu.js`) with a `phase()` builder, plus runnable examples (feature rollout, release train, phased migration, Linear import).
## π Workflows
Drop a YAML template into `.clu/templates/`:
```yaml
name: release
vars:
version: { required: true, pattern: '^\d+\.\d+\.\d+$' }
steps:
- id: build
title: "Build {{version}}"
- id: test
title: "Test {{version}}"
needs: [build]
- id: approve
type: checkpoint # π¦ human gate
title: "Approve {{version}} for prod"
wait: { approval: [alice, bob] }
needs: [test]
- id: deploy
title: "Deploy {{version}}"
needs: [approve]
```
```bash
clu run release -v version=1.2.3 # β parent + 4 children + deps in one shot
```
Agents drive it by claiming `ready` issues as each step closes; humans clear checkpoint gates via `clu approve `. Failing a checkpoint cascade-cancels the rest of the run. See [`demo-workflow.sh`](demo-workflow.sh) for the full demo.
> `clu batch` is the programmable superset of `clu run` β same checkpoints and grouping, but the graph comes from code instead of a YAML template.
## π§Ύ Audit & history
Every write is recorded in an append-only event log:
```bash
clu history # full timeline of one issue (who/what/when)
clu log --kind claimed --since 24h # global stream, filterable by actor/kind/issue/since
```
The actor is the resolved `--agent` (or `$USER`); payloads record just the changed fields. The log is local β it's not part of `clu export` (which carries portable state, not history).
## π₯οΈ Web UI
```bash
clu web # serves a local dashboard (default :5757)
```
A read/write dashboard: filterable issue list, kanban board, dependency graph for a run, and an approvals queue for pending checkpoints. Backed by the same store via an in-process REST API (`clu http` exposes that API standalone).
## π€ Coordination primitives
Beyond the issue graph, for things that don't fit a ticket:
```bash
clu lock deploy --ttl 1h -- ./deploy.sh prod # TTL'd named lock; auto-released, leak-proof
clu ping code-reviewer "PR #412 ready" # fire-and-forget message (TTL'd, off the work log)
clu inbox -a code-reviewer # read your messages
clu worktree add feature-x --bootstrap # git worktree + project-defined setup
clu sync push --remote origin # publish issues to a branch-independent git ref (experimental)
```
`clu sync` (experimental) keeps the tracker on a dedicated `refs/clu/store` ref β
so any checkout sees the same issues, writes never collide with code commits, and
a teammate's clone can `clu sync pull --remote origin` to get the backlog without
the DB ever being committed. See [the sync docs](docs/content/docs/sync.mdx).
## π Layout
```
cmd/clu/ β¨οΈ entrypoint
internal/cli/ π§© one file per kong subcommand
internal/store/ πΎ SQLite layer, split by domain
βββ models.go bun model types
βββ migrations.go manual migrations (PRAGMA user_version)
βββ issues.go create/get/close/reopen/cancel/update
βββ claim.go ready/claim atomic queries
βββ deps.go dependency edges + cycle detection
βββ batch.go validated bulk graph instantiation
βββ milestone.go auto-close cascade
βββ events.go append-only audit log
βββ context.go ancestor-context walk
βββ β¦ labels, comments, kv, cron, agents, locks, mailbox, doctor
internal/workflow/ π YAML template loader + planner
internal/http/ π REST API (backs the web UI / `clu http`)
internal/config/ βοΈ config.yaml parsing
web/clu-web/ π₯οΈ TanStack Start web dashboard
examples/generators/ πΈοΈ codemode graph generators for `clu batch`
.clu/ π per-project storage (DB, config, templates, agents/)
```
## π§ Design notes
```mermaid
flowchart TB
subgraph clients["Clients"]
cli["clu CLI
(Kong)"]
agents["AI agents
(claim Β· comment Β· close)"]
batch["generators
(node script | clu batch)"]
end
subgraph core["clu binary"]
cmds["internal/cli
one file per command"]
http["internal/http
REST API"]
store["internal/store
Bun + sqlitedialect"]
wf["internal/workflow
YAML planner"]
end
web["web/clu-web
TanStack dashboard"]
db[(".clu/data.sqlite
single file, pure-Go driver")]
agents --> cli
cli --> cmds
batch --> cmds
cmds --> store
wf --> cmds
http --> store
web --> http
store --> db
```
- πͺͺ **One identity flag.** `-a` / `--agent` is both the lane filter and the actor identity. No `--as` β single-user local tool, the user/agent distinction was deliberately collapsed.
- ποΈ **Hand-rolled migrations** via `PRAGMA user_version`. Append-only, never edit an applied migration.
- π οΈ **Bun + sqlitedialect** for queries. Raw SQL escape hatches in exactly two places: the atomic claim, and the cancel-cascade CTE.
- π **Kong** for the CLI struct, with struct-tag commands and intermixed flags.
The rationale for each sticky decision lives in [`CLAUDE.md`](CLAUDE.md).
## π
Not in scope
`clu` is deliberately small. It does **not** try to be:
- π a live, server-backed sync layer with cell-level merge β for sharing across machines there's the experimental [`clu sync`](docs/content/docs/sync.mdx) git ref (manual push/pull over your own remote), not a always-on sync server
- π a generic project-management tool β no sprints, milestones, OKRs
- π a *live* bridge to GitHub / Linear / Jira. (You can still **import** from anything by piping a generated graph to `clu batch`; an idempotent `key` keeps re-runs clean β see [`examples/generators/linear-todo.js`](examples/generators/linear-todo.js).)
- π€ an agent runtime β *you* are the agent; `clu` just gives you somewhere to put the work
## π€ Contributing
PRs welcome. Before sending:
```bash
go build ./... && go test ./...
./demo.sh && ./demo-workflow.sh
```
See [`CLAUDE.md`](CLAUDE.md) for code conventions (one file per kong command, sentinel errors per entity, JSON-clean output, etc.).
## π License
MIT β see [LICENSE](LICENSE).
Built for the era of many small agents working together. β‘