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 wrkqwhy
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 wrkqStep 1. Initialize the ledger in your repo
$ wrkqadm init$ wrkq mkdir inboxStep 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.
| command | what it does |
|---|---|
| wrkq touch inbox/login-flow -t "Login flow" | create a task |
| wrkq set T-00001 --state in_progress | start it |
| wrkq comment add T-00001 -m "Added the form" | leave a note |
| wrkq cat T-00001 | read it back |
| wrkq set T-00001 --state completed | finish 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 yamlor--output tsvon 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 listand picks up. $ wrkq handoff create -t "Where I left off" --body-file -
<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 completedcommands
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 makewrkq check blockedfail.- 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?
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?
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?
--if-match to refuse a write that would clobber someone else’s. claim is atomic and single-holder.Can I version it?
wrkqadm exports and imports state so a project’s tasks can be committed, reviewed and merged like code.Is there an MCP server?
mcp-server/ in the repo exposes selected operations over stdio. The CLI is still the primary surface and does more.