Coordinate work with confidence.

Climier is a durable task DAG for coordinating work, decisions, and knowledge across agents, sessions, and humans. Every change is validated, committed, and logged atomically.

Start the quickstartSource
bun add --global climier
A four-node Climier graph in the initiative “auth”. The task T-auth-0 is taken, submitted, and accepted. Acceptance is what satisfies its blocker edge and derives T-auth-1 as ready; submission does not.
climierstatus --initiative auth
  • 1in progress
  • 2blocked
  • 1open gates
rev 5
T-auth-0 · BLOCKS → T-auth-1

Session contract

in progress
T-auth-1 · BLOCKS → T-auth-2

Session store

blocked
T-auth-2

Production cutover

blocked
G-auth-prod · BLOCKS → T-auth-2

Cutover approval

open

alice holds the claim on the blocker. Nothing downstream moves yet.

climier take T-auth-0 --as alice
{
"node": {
"id": "T-auth-0",
"status": "in_progress"
},
"freshly_claimed": true
}
log · append-only
  • rev 5action takeactor alicenode T-auth-0

How the graph stays honest.

Climier keeps one snapshot, one write path, and one derivation. Nothing else is allowed to become a second source of truth.

Ready and blocked are derived, never stored.

The snapshot keeps one lifecycle value per node. ready and blocked are recomputed from the graph on every read, so a reported status cannot drift away from the work behind it.

incoming BLOCKS edgesatisfied when
blocker kindsatisfied when
taskdone or archived
gateresolved, or superseded by a resolved gate
knowledgenever
missing node or cyclenever

submitted waits for validation. It never satisfies a blocker, no matter how long the review takes.

Every mutation is one locked, atomic commit.

State, revision ledger, and audit log land together under a single project lock. Two writers serialize instead of interleaving, and the log can never describe a state that was not written.

~/.climier/projects/<id>/
.lock
held for one write
tasks.json
rev 7
revision-ledger.json
rev 7
log
entry 7 appended

One lock per project, so writers serialize instead of racing. Add --if-revision N and the write fails when the node moved since you read it.

Every claim names its actor, and stale ones surface.

Mutating commands record who acted. A claim is visible to the whole project, and a claim held too long raises an alert instead of silently squatting on ready work.

climier status --stale-ms 1800000exit 0severity: warning
{
"alerts": [
{ "kind": "stale-claim",
"severity": "warning",
"task_id": "T-auth-3",
"claimed_by": "bob", … }
]
}

Narrow the read with --claimed-by alice. Counts stay global: a claim is visible to everyone, not only to the agent that took it.

The lifecycle, once.

Four persisted states, each written by one command. Everything the graph reports is derived from where a node sits on this line.

  1. open

    climier add-task T-1 …

    Registered. Ready when no blocker is unsatisfied.

  2. in_progress

    climier take T-1 --as alice

    One claimant. The claim is stamped and visible.

  3. submitted

    climier submit T-1 --note "…"

    Under review. Downstream stays blocked.

  4. done

    climier accept T-1 --as reviewer

    Accepted. Downstream BLOCKS edges are satisfied.

rejectsubmitted → open
climier reject T-1 --reason "…"
releasein_progress → open
climier release T-1
cancelany → canceled
climier cancel T-1 --reason "…"

From an empty directory to a ready task.

Eleven lines, no server, no account. The same commands work in a terminal, a script, or an agent — they all read the same JSON.

Start the quickstart
terminal
# requires Bun 1.4+
$ bun add --global climier
$ mkdir climier-demo && cd climier-demo
$ climier init
$ climier add-initiative demo --as alice
$ climier add-task T-example-1 --initiative demo \
--title "Write the first task" \
--body "Complete the first piece of work in the demo project." \
--acceptance "The work is complete and its checks pass." \
--blocked-by "" --as alice
$ climier status