wf — a shared workflow for many coding agents on one machine
wf is the task workflow I use to run several long-lived Claude Code sessions in parallel, each
working in its own project under one folder (/projects). How to set it up and use it:
docs/manual.md. It has three parts:
- One rules file for every agent.
shared/CLAUDE.mdsets out the loop each agent follows: cold start, test-first implementation, one commit per finished task, when to ask and when to decide, and how to report problems with the workflow itself. Claude Code loadsCLAUDE.mdfrom the working directory and every parent, so the file is symlinked once as/projects/CLAUDE.mdand every project gets it. A project's ownCLAUDE.mdholds only project specifics and wins on conflict. - A task tool,
wf. Each project keeps its open work in aTASKS.mdwith stable ids. Agents never read or rewrite that file whole; they use one short command per operation (wf next,wf add,wf done,wf ctx, …), andwf checkmakes sure no reference rots. - A memory/CPU ledger,
wf res. Agents reserve memory and CPUs before a big or long job and get a clear "busy, retry after HH:MM" instead of out-of-memory kills. The owner keeps a guaranteed reserve, and a larger one in gaming mode. Built on systemd user units and cgroups.
Status: a personal setup, published as a reference. It is shaped around one person's machine and habits: Linux, systemd, Claude Code, one
/projectsfolder. It is provided as is. Setup and daily use: docs/manual.md. There is no support and no plan for Windows or macOS. Take whatever ideas or code are useful to you.
Why
With one agent, a task list in a markdown file works fine. With five or more agents running for days, things go wrong:
- Each project grows its own task scripts and workflow prose, and they drift apart.
- Agents spend context reading and rewriting long task files, renumber items, and break references ("see task 14").
- A workflow fix has to be copied into every project.
- Two agents start a 10 GB build at the same time and one of them is killed, or the desktop freezes.
wf answers these with one rules file, a task format with stable ids, a CLI that makes every
routine edit one command, and a ledger that rations memory and CPU.
The loop (shared/CLAUDE.md)
Short version. The file itself is the authority.
- Cold start ("continue"):
wf nextshows the questions waiting for the owner, items that need a human, plans in flight, and the next pickable task with its context. The agent works on it without asking. - Task kinds: an implementation slice (at most about 1 h) is test red → implement → verify
green. Design work goes through brainstorming → spec → owner approval →
wf addslices. Bugs: evidence → failing test → fix. - Autonomy: decide, record the decision in the spec or task, report it. Ask only at real
forks. Blocked on the owner →
wf add -s awaiting "<question>"and move on to another task. - Done:
wf done <id> -m "<entry>"archives the task and prints the project's checklist,wf checkmust report 0 errors, then one commit. Never merge or push unasked. - Resources: a job over 2 GB RAM, over 4 cores or over 10 minutes goes through
wf res run. Exit 3 means busy: the agent notes it and works on something else. - Workflow problems:
wf report "<what>"appends to a shared inbox. The agent works around the problem and keeps going. The owner's workflow session triages the inbox later.
TASKS.md
# Tasks — myproject
## Awaiting your decision
- **a-save-format**: JSON or binary saves? Blocks [[t-save-load]].
## Pending
- **t-cave-seams** [P1] (<1h): Terrain: cave entrance seams. Close the slit beside the lintel.
- Tests (red first): seam test on the cave fixture.
- After: [[t-terrain-cave-render]]
Ref: DESIGN.md#terrain
- **t-save-load** [P2] (1h) (blocked: [[a-save-format]]): Save and load. Round-trip the world.
## Needs human
- **t-playtest-feel** [P1] (<1h): Play-test feel and tuning.
- [ ] jump height
## Deferred
- **t-android-port** [P3] (10h): Android port.
- Four sections. Items in Needs human are never picked by an agent.
- Ids (
t-…for tasks,a-…for questions) are stable and never reused. Links are written as[[id]]. - Priority P0–P3, effort from a fixed list (
<1h,1h,5h,10h,100h). Anything over 1 h is split into slices with--parent. After:lists dependencies.Ref:points into the project's docs, down to a heading anchor.wf ctxandwf nextprint the referenced sections, so an agent loads only what it needs.- Finished tasks become one dated line in
tasks/archive.md. The full history stays in git.
Commands
Run inside a project (a folder with workflow.toml). Every write command accepts --dry-run
and refuses a change that would add a wf check error.
| Read | |
|---|---|
next [--brief] |
what to work on now, with context |
list · show · ctx |
items, filtered · raw items · an item or doc anchor with everything it links to |
search <words> · log |
ranked search over tasks, archive and docs · newest archive lines |
projects |
every project under the root: counts, next task, check errors |
check |
validate format, ids, links, refs and anchors; exit 1 on any error |
| Write | |
|---|---|
add · done |
new item (id from the title or --id; --parent for slices) · archive finished tasks |
prio · move · status · set |
reprioritise · move or reorder · in progress / blocked · header fields |
rename · note · body · tick |
change an id and its links · append a line · replace the body · check a box |
report · init · migrate |
file a workflow problem · start a project · convert a numbered task list |
wf res |
|
|---|---|
run --mem 10G [--cpus N] --for 40m --title T [--queue\|--force] -- CMD |
reserve and start a job as a systemd user unit; exit 3 = busy (--force: fit against really free memory, ignoring ledger claims; the busy line names it when it would fit) |
status · wait · release · note |
reservations and budget · wait for a job · drop an entry · reserve for foreground work |
game on [--for 4h] / off |
raise the owner's reserve; agents slow down, never get killed; with hook installed, agent commands get no display |
hook |
Claude Code PreToolUse hook for ~/.claude/settings.json (see docs/resource-ledger.md §4.6) |
clean · adopt · timer on/off · tick |
stale tmpfs scratch · move running sessions into the agents slice · 1-minute housekeeping |
wf -h and wf <command> -h give the details.
Design notes
- Pure core.
wflib/is text in, text out, with no file access.wf.pyandwf_res.pydo the I/O. Python ≥ 3.11 standard library only. - Live tool, safe releases. Every agent runs the main tree of this repo the moment it
changes. Changes are made in a git worktree and fast-forwarded only when the tests pass and
wf checkgives the same result in every project as before. Commands are only ever added; a task-format change comes withwf migrate. - Concurrent writers. Task files are written whole via temp file + rename, and a write is
refused if the file changed since it was read.
wf reportappends with oneO_APPENDwrite. The resource ledger is a JSON file under a lock. - Ledger, not scheduler.
wf reskeeps no daemon. Every call reads/proc/meminfoand the ledger, admits or refuses, and starts the job as a transient systemd unit withMemoryMaxinsideagents.slice. A one-minute timer starts queued jobs, ends gaming mode and cleans up.
Full reference: docs/design.md (format, config, every command, release rules) and docs/resource-ledger.md.
Tests
python3 -m unittest discover -s tests
Licence and credits
MIT, see LICENSE. Credits: CREDITS.md.
From the author
These projects are things that have been tumbling about in my head for a long time, and I now feel like trying to do something with. The bulk of my focus here is on some of the games that I love, but every time I boot them up, I just fiddle about in the menu and set up mods and fixes for a couple hours, with my drive to play them fizzling out. This is my hope to solve that, and while I am a professional software engineer this would not have happened were it not for the rise of (relatively) cheap AI that could do the bulk of the work with me. If you don't approve, that's fine. I did these things for me, sharing them is something I do in the hopes to help others in similar situations, that just want to play the games they love. Thank you to all that made these playable in the first place, with some luck this finds you, and can bring some joy.
Written with AI assistance (Claude, by Anthropic), used as an engineering tool.