Skip to content

local-first · sqlite · mit

Work queuesfor humans and agents.

wrkq is a task ledger that lives next to your code. Unix verbs, one SQLite file, JSON on every command, and a principal on every write. Humans and agents work the same queue.

$ brew tap lherron/wrkq && brew install wrkq

or read what wrkq info tells your agent

why

Three things it gets right.

Verbs you already know.

Tasks and projects are paths. ls lists them, cat shows one, touch makes one, mv moves it, rm retires it. An agent that can use a shell can use wrkq with zero instructions, and wrkq info gives it the rest.

One file, no server.

Everything durable is in .wrkq/wrkq.db. WAL mode, busy timeouts and etag checks make concurrent agents safe. No accounts, no sync, nothing to run. Export the state and it goes through your PR like any other change.

Every write has a name on it.

Each mutation records a principal: agent:cody, agent:mable, you. Comments, claims and state flips are attributed and appended to an event log you can tail. When two agents touch the same task, claim makes the winner explicit.

# verbs$ wrkq ls inboxT-00042   Retry on 429            open      P3T-00043   Cache ETag on list      open      P2 # one file$ wrkq set T-00042 --state in_progress --if-match 7Error: task etag precondition failed # names$ wrkq claim T-00042 --as agent:codyClaimed T-00042 as agent:cody on macbook (generation 1)

install

Install it, then tell your agent.

$ brew tap lherron/wrkq && brew install wrkq

Step 1. Initialize the ledger in your repo

$ wrkqadm init$ wrkq mkdir inbox

Step 2. Add the hook to your agent's startup

Claude Code, Codex, opencode, pi and most harnesses run a shell hook at session start. Put this in it:

wrkq info 2>/dev/null || echo "wrkq not installed; ask the user"

wrkq info prints the task lifecycle rules and the command reference an agent needs. Nothing else to configure.

First five commands
commandwhat it does
wrkq touch inbox/login-flow -t "Login flow"create a task
wrkq set T-00001 --state in_progressstart it
wrkq comment add T-00001 -m "Added the form"leave a note
wrkq cat T-00001read it back
wrkq set T-00001 --state completedfinish it

agents

Built to be read by something that isn't you.

Agents don’t browse. They run a command, parse the result and run the next one. wrkq was designed from that side of the screen.

Structured output on every command.
--json, --ndjson, --porcelain, and --output yaml or --output tsv on anything. The command below returns one object, not an array, because that is what the caller asserted.
$ wrkq cat T-00042 --json --one
Wait, don't poll.
Blocks until the condition is true and exits 0. Exit 1 means the timeout won. Built for the Monitor tool.
$ wrkq monitor wait T-00042 --until state=completed --timeout 30m
Context that survives the session.
Leaves a note scoped to the agent and project. The next session runs wrkq handoff list and picks up.
$ wrkq handoff create -t "Where I left off" --body-file -
wrkq info
<task_tracking_rules>
# wrkq Task Management CLI

## Task Lifecycle
1. **Before starting a task**: Set task to `in_progress`
   wrkq set T-00001 --state in_progress

2. **During work on a task**: Add progress comments for significant milestones
   wrkq comment add T-00001 -m "Implemented core logic in cmd/apply.go"
   wrkq comment add T-00001 -m "Added test coverage, 3 edge cases found"
   wrkq comment add T-00001 -m - <<'EOF'
   Multi-line progress note from stdin.
   EOF

3. **Before completing a task**: Add final summary comment
   wrkq comment add T-00001 -m "Completed. Added apply cmd with 3-way merge support. Updated docs. All tests passing."
   wrkq set T-00001 --state completed
This is what your agent sees at startup.

commands

The whole surface.

Forty-odd verbs, grouped by what you’re doing. Every one has --help and --json.

files

work

find

watch

agents

projects

model

Small model, stable IDs.

states

  • idea
  • draft
  • open
  • in_progress
  • completed
  • blocked
  • cancelled
  • archived
  • deleted

Any valid state is accepted; the common path is a convention, not a gate.

entities

ContainerP-00007
A project, directory, feature or area. Hierarchical.
TaskT-00123
Kinds task, subtask, spike, bug, chore. Priority 1–4.
CommentC-00091
Append-only.
Attachment
Bytes on disk under the task's UUID, metadata in SQLite.
Relation
blocks, relates_to, duplicates. Open blockers make wrkq check blocked fail.
HandoffH-00012
An agent's note to its next session.
Claim
Single holder, scope, generation, one-time token.

addressing

Path, friendly ID or UUID. All three work everywhere.

  • inbox/retry-on-429
  • T-00042
  • 7a6ffe78-d331-4cad-9bfc-ae093e3aa071

faq

Questions people ask first.

Does it need a server?
No. wrkq opens the SQLite file directly. wrkqd exists for the case where several machines share one ledger over HTTP, and wrkq server start wraps it. You will probably never run it.
How do agents know how to use it?
They run wrkq info. It prints the lifecycle rules and a command reference. Put it in your startup hook and every session begins oriented.
What about concurrency?
WAL mode, busy timeouts, and an etag on every row. Pass --if-match to refuse a write that would clobber someone else’s. claim is atomic and single-holder.
Can I version it?
The database is local. wrkqadm exports and imports state so a project’s tasks can be committed, reviewed and merged like code.
Is there an MCP server?
Yes, mcp-server/ in the repo exposes selected operations over stdio. The CLI is still the primary surface and does more.
License?
MIT.