The stupid coordination tool

Tasks and architecture decisions in your repo, behind one CLI any coding agent can call.

npm install -g @haksolot/ank
npx skills add haksolot/ank

Open source, Apache-2.0. Linux, macOS and Windows.

The loop, run once

~/auth-service
ank context src/auth/

CONSTRAINTS (1 active)
  ADR-06d2  Opaque sessions rather than stateless JWT

TASKS (1)
  TASK-820d  [open] Migrate auth to opaque sessions

> ank claim TASK-820d to start

ank claim 820d
claimed TASK-820d259af6a7 migrate-auth-to-opaque-sessions -> HEAD

ank context

TASK-820d  Migrate auth to opaque sessions

DONE_CRITERIA
  The auth tests pass and no reference to jwt.verify remains in src/auth/

CONSTRAINTS (1 active)
  ADR-06d2  Do not introduce self-contained JWTs for user auth. Every session goes through the Redis store.

ank log "jwt.verify removed from session.ts"
logged LOG-6b0f39d7a4c1 on TASK-820d259af6a7

ank done
running: auth-tests ... ok (0.0s)
running: no-jwt ... ok (0.0s)
proof recorded: auth-tests@94a1f671c577 -> local/e3b0c44298fc@9c45c50  (scope/18d14da584ab)
proof recorded: no-jwt@791cc818d0ad -> local/e3b0c44298fc@9c45c50  (scope/18d14da584ab)
TASK-820d259af6a7 -> done

Real output, taken from the quickstart. Its test suite replays these commands against the binary on every change.

Works with the agent you already run

ank is a command-line tool. Any agent that can run a shell command can run the loop, and a client with no shell reaches the same verbs over MCP.

  • Claude Code
  • Codex
  • Cursor
  • OpenCode
  • Gemini CLI
  • GitHub Copilot
  • Cline
  • Amp
  • pi
  • Antigravity
  • Goose
  • Kiro
  • Roo Code
  • Kilo Code
  • Windsurf
  • Qwen Code
  • Mistral Vibe
  • OpenHands
  • Junie
  • Devin

One command installs the skills into whichever of these it finds, and some thirty more.

Your agent reads the code, not the thread

An agent can read every line of your code, but not your tracker, your wiki, or the thread where you decided that sessions must never be self-contained JWTs. Nothing stops the next session from writing one.

ank keeps those decisions and the work in .ank/, attached to the code they constrain by a glob. Before it starts, the agent runs ank context src/auth/, and the rule comes back with the task.

Plain markdown files in your repository, reviewed like any other change. No server to run: claims are git refs.

Six verbs

The whole loop an agent needs. ank help lists every other one.

  1. ank context <path>

    What binds this perimeter, and what is takeable. The first call, always.

  2. ank claim <id>

    Take a task and freeze its criterion.

  3. ank show <id>

    The entity whole: frontmatter, body and log.

  4. ank log "<message>"

    What you learned, while you work. Writing it renews the claim.

  5. ank done

    Run the declared verifiers and record the proof.

  6. ank release --reason "<why>"

    Hand the task back, and say why.

Three ideas underneath

Each one is a property of the tool, not a convention you are asked to keep.

Scope, not hierarchy

Constraints and work are two planes joined only by globs. A rule written last year binds work created today, and a glob is checked against the filesystem, where a label is not. No epic, no parent, no rollup to keep in step.

ank new adr --title "Opaque sessions rather than stateless JWT" \
    --scope "src/auth/**" \
    --constraint "Do not introduce self-contained JWTs for user auth. Every session goes through the Redis store."
created ADR-06d29e727d24 Opaque sessions rather than stateless JWT

The criterion is frozen at claim

Claiming a task freezes its done_criteria by hash, where the editor of the file cannot reach it. Rewriting the criterion to unblock yourself unblocks nothing: ank check shows the divergence. One claim at a time per identity, and a claim is a git ref: two agents reaching for one task get one winner.

ank claim 820d
claimed TASK-820d259af6a7 migrate-auth-to-opaque-sessions -> HEAD
ank claim 51c2
error[7]: human:marie holds a live claim on TASK-820d259af6a7 (expires in 30m)
  -> ank release --reason "<why>"   (a second session on this machine sets its own ANK_AGENT)

Nobody declares themselves done

An agent that reports its own result can simply be wrong. ank done runs the verifiers itself and records what actually ran, hashed. A task with nothing to run asks for a proof you hand it, and every refusal names the command that resolves it.

ank claim 51c2
claimed TASK-51c2a0f6d418 say-in-the-readme-what-a-session-is-now -> HEAD
ank done
error[5]: proof required to move TASK-51c2a0f6d418 to done
  -> ank done --proof commit:<sha>

What it is not

  • Not a tracker. No cycles, estimates, velocity or roadmap.

  • Not a wiki. Only what is actionable or binding for an agent goes in.

  • Not a security boundary. It protects against drift, not against an attacker.

ank is built with ank

Its own repository runs on this loop. The .ank/ at its root holds the ADRs its code is held to and the tasks that built it, and the documentation cites those decisions by id.

The version is 0.x on purpose: the loop and the exit codes are specified, the storage format is not yet.

Read its .ank/ on GitHub

Install ank

Two commands. Linux, macOS and Windows, with git 2.34 or newer.

npm install -g @haksolot/ank
npx skills add haksolot/ank