---
name: journal-todos
primary: true
description: File distinct future work as a to-do, declare work before writes, tell parked from blocked, and close both explicitly. Load it when you wait on a subagent, a helper or a background run; or when a helper is given a worktree of its own, or its work is taken back; or when a bounded job goes to a helper on another provider, such as Codex, or a helper reports; or when to-dos are moved between lanes or the board is read; or when you start, log, park, await or end work, or before the first write.
keywords: awaited, awaiteds, helper, helpers, worktrees, worktree, kanban, kanbans, work, works, tracking, trackings
commands: todos, awaited, helpers, kanban
---

# To-dos and work

## When the user asks for work

1. **It is the current work**, a step of it, or a correction: carry on; `journal work log <n> "<what moved, and why>"` when the direction changes.
2. **It is different.** A to-do — the default: `journal todo create "<title>" --brief "<why, where to start>"`, say "filed as to-do n", and carry on. Its words: `journal todo ask <n> "<question>"` files a question on the row and the row waits; `todo answer <n> "<text>"` answers it; `todo block <n> "<why>"` / `todo unblock <n>`; `todo after <n> <m>` says it waits on row m (`--off` undoes); `todo strike <n> "<why>"` abandons it on the record; `todo start <n>` opens work for it; `todo prune --days 30` drops long-closed rows. The list is ordered by priority, then number: `journal todo priority <n> low|default|high|critical` (or a number; 100 is default). You assign priority yourself when urgency, impact, dependencies or risk make a difference, and revise it when the evidence changes; an explicit user priority always overrides that judgment.
   File it immediately, before looking at files, investigating, implementing, or deferring it. If one message mixes current-work steering with a distinct future request, apply the steering to the open work and file the distinct request first.
3. **It is different and the user said NOW** — their word, not your judgement: update the open work with where it got to, then start the new one.

With nothing open, the request is the work: read until you can name it, `journal work start "<the work>"`, go. **Declare before the first write**: a write with no work open is refused by the gate. `journal todo start <n>` opens work for a row; `journal work end <n> --how "<what landed>"` ends it, and the row is closed only by `journal todo done <n> --how "<how>"` — ending work is not finishing a row. `journal work log <n> "<message>"` writes a dated entry in the work's log — every decision, turn and finding as it happens; twenty edits without an entry hold your writes until you log. `work update` only renames or rewords the work itself. A commit closes a row when its message carries `Journal: todos done <n>` at column 0.

**"I'll do it after this" is a to-do, every time.** The deferral feature names the sentence back to you if nothing was filed.

A distinct future task becomes `journal todo create` immediately when the user names it, before further investigation, implementation, or deferral. Put the user's evidence, scope and a starting point in its brief. Use `todo after` for another row, `todo block` for an external condition, and `todo ask` for a user decision. Auto mode takes the next ready row by priority.

Start with `journal todo start`; keep the work's log as you go — `journal work log <n> "<message>"` for every decision, turn and finding, with its reason. Twenty edits without a log entry hold your writes until you log. End the work with `journal work end`, then close the row with `journal todo done`. Never leave completion implicit.

## Parked and blocked

**Parked.** The row is in hand (its work was started) and nothing stops it, but something else goes first by choice: the user asked for something now, or another row matters more. `journal work park <n> "<what goes first>"` sets it aside; `journal work resume <n>` picks it up where it stopped. Only started work can be parked. A to-do that was never started is not parked: it waits on the list until it is taken.

**Blocked.** The row cannot go ahead until something else happens first:
- another to-do: `journal todo after <n> <m>` (it waits on row m, `--off` undoes);
- a decision or a conversation with the user: `journal todo ask <n> "<question>"`;
- anything outside: `journal todo block <n> "<why>"`, then `journal todo unblock <n>` once it has happened.

Auto mode skips a blocked row until what it waits on is done; a parked row stays yours to resume.

The test: could you pick it up right now if you chose to? Yes, it is parked. No, it is blocked. Never park what is stuck, and never block what you only put aside.

## Wait for agents and background commands

The agent can wait for named subagents, helpers or background commands. When all of them finish, their results come back and the work goes on.

journal work await "<what>" --on <id>,<id> names what the wait is on: a subagent's or a background run's id as you were given it, or helper:<n>. It stands, with no reminders, until every one of them has finished, even while you work on; then their results are written into the work's log and you are told once to carry on. A wait without --on clears when you work again, as before.

Its lines and guards are for the main agent only; none reach a subagent.

## Helper worktrees

Each helper works in its own git worktree, made from the latest commit of the working branch. Its commits are copied back once it has rebased.

A helper that changes code gets its worktree through journal worktree cut "<name>" [--helper <name>]: it is cut from the current tip of the branch the main checkout is on, and prints the path and branch to put in the dispatch prompt. journal worktree drift <n> says what the working branch gained since; the helper is told once for each new tip to rebase. Once it has rebased onto the working branch, journal worktree take <n> cherry-picks its commits onto it, and journal worktree drop <n> removes the worktree and its branch.

The main agent stays in its own checkout: while its working folder sits in another one, every tool call is refused until it goes back with cd, since a compaction there would move it into that checkout's environment. git -C <folder> or a subshell works in another checkout without moving.

These reach your subagents too: the line drifted, the guard Tell drift.

## Helpers

A helper agent on any provider takes one bounded job in an environment of its own, kept out of the lists, and its report comes back to the chat.

A helper is for work that writes. Work that only reads, such as a review, research or a design, goes to your own subagent instead, also when it reviews a branch in a nested checkout, dispatched with your agent tool: Claude's Agent tool, Codex's spawn_agent with an agent_type from .codex/agents. The subagent shows in the viewer's agent list and its answer comes back to you.

A helper or subagent that has worked in the project already knows it. New work that is related to its job, or touches the same code, goes to it with a message, journal helper say <n> "<the new work>" for a helper and SendMessage (send_input on Codex) for a subagent, instead of a fresh dispatch; keep one around while related work may follow. When you dispatch a new helper while an idle one already touched the files its job names, the answer names that one.

At most helpers.kept (8) agents of each type, such as helpers or designers, are kept for reuse, and at most helpers.working (6) agents work at the same time; 0 turns a limit off. When the kept ones of a type are full and some of them wait for work, a new dispatch of that type is refused with the idle ones listed, those that touched the same files first, each with the line that sends it the work. An idle agent of another type never has to go. journal helper finish <n> or journal agent retire <id> frees a place. Reviewers and critics start fresh, so they are never held back.

journal helper dispatch <name> "<job>" --provider codex --model <model> --brief "<the bounded job>" starts a helper in an environment of its own, named after you and the helper, which stays out of the environment lists; --worktree gives it a worktree cut from the working branch for any job that changes code, and --checkout <path> launches it instead in a git checkout inside the project, such as a nested repository on its own branch. The name follows the naming law and the model is always named, one the provider offers: a model it does not offer is refused with the list of those it does. You are told when it reports: its report shows in the chat as a message from it. journal helper say <n> "<text>" [--todos <n>,<n>] sends it a follow-up and hands it those to-dos; journal helper stop <n> ends its agent; once its work is taken (journal worktree take) or dropped, journal helper finish <n> packs its environment away. Helpers write to one another the same way: from a helper, journal helper say <n> "<text>" reaches the helper of that number at once, or at its next turn while it is busy, on Codex and Claude alike, and journal helper peers lists them.

--todos <n>,<n> hands the helper rows of your own list: they are its alone, so nobody else starts or closes them. The helper marks one with journal helper done <n> "<what landed>": it shows as done, waiting for its merge, and closes once its worktree is taken. Stopping the helper, or its turn ending in an error, gives back the rows it has not finished; finishing it gives back the rest.

A question a helper asks in its own environment, or a subagent asks in the environment lent to it, reaches you at once as a line naming it, the question and its options, and again while the question stays open. Answer it with journal question answer <n> in that environment; the helpers list and the plan page show a helper that waits on one.

A helper whose agent stops running before it reports, as after a restart of the machine, is named to you at once; one that has done nothing for a while is named so you can check on it.

These reach your subagents too: the guard Keep subagent files, the guard Refuse test runs to helpers.

## Kanban board

The to-dos of an environment as lanes of cards, moved by drag or by journal todo shift.

To see the to-dos as lanes, run journal todo board [--plan n] [--agent id]. To move a card, run journal todo shift <n> <lane> [--why "<why>"] [--how "<how>"]: it goes through the same actions the rest of the journal uses (blocking, unblocking, closing, reopening, and starting a to-do dropped on Doing, through the same gate as journal todo start).

Every open to-do is a card in one of five lanes, worked out from its state and never stored: To do, Held (blocked, waiting on another row, or held by its plan), Doing (work is open on it), Needs you (a question waits on it) and Done (closed in the last kanban.done_days days). The Board page in the viewer shows the lanes side by side; the user drags cards between them or moves them from a card's menu.

Its lines and guards are for the main agent only; none reach a subagent.

## Work tracking

The agent must open work before it changes files. Work is linked to its to-do and keeps a log. After twenty edits without a log entry, file changes are blocked until it writes one.

One piece of work is in hand at a time: starting another is refused until this one is ended or parked. Take a row with journal todo start <n>, or start work of its own with journal work start "<title>"; log each decision and turn with journal work log "<message>" (work.log_after, 20 edits without an entry holds the writes); end it with journal work end <n> --how "<what landed>", and --set todo=<n> closes the row with it.

journal work park "<why>" sets it aside with no clock — it stays open, stops being nudged and stops holding writes, and journal work resume <n> picks it up again. Park when nothing stops the work but something else goes first by choice. What cannot go ahead until something happens is blocked, not parked: journal todo after, todo ask or todo block on its row. Never park to wait for an answer you could carry on without.

journal work await "<what>" says you are waiting for something outside your hands, such as a long build or a run in Docker, in your own words, and the chat shows it. Say it once instead of writing another line each time nothing has changed. Working again clears it, and you are told that it was cleared; parking clears it too. While it stands you are told every five minutes (work.ask_awaiting_every) to check the thing you wait on and carry on or wait again. A shell command that only waits, such as sleep 30 or an until or while loop around sleep, is refused: say journal work await and stop, and a message or a report wakes you.

Auto mode is on by default: it is the user's word to work the list and decide without blocking questions, and switching it off stops the offers. The next ready row by priority is offered on idle while nothing is open. Stopping with work open while another row is ready earns the same offer: a row that waits on the user gets its question with todo ask and the next row is taken, so the agent stops only when nothing ready is left. When the work in hand waits on a helper or a subagent that is still working, the next ready row is offered at once, so the agent works on instead of sitting out the helper's turn. Five minutes quiet with unparked work open earns a direct question, are you still working? A row is ready when it is not blocked, waits on no open row or question, and its plan's phase is current.

These reach your subagents too: the guard Refuse held calls.
