1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
#+TITLE: Task Review Workflow
#+AUTHOR: Craig Jennings & Claude
#+DATE: 2026-05-20
* Overview
A short, daily list-hygiene habit. Each run surfaces the handful of top-level tasks that have gone longest without a review, walks them with Craig one at a time, and records the outcome — re-grade, kill, mark in-progress, or just confirm it's still right — stamping =:LAST_REVIEWED:= as it goes.
The point is /trust/: when Craig opens =todo.org=, the priorities and wording should feel accurate. Tasks drift — an =[#A]= from six months ago may not be urgent now, a commitment keeps getting deferred without ever being killed, a body loses the context that made it actionable. Walking a small rotating batch every day keeps the list honest without a big periodic purge.
This is *not* =open-tasks.org=, which just displays the list or picks the next task. This workflow *changes* tasks. Full design and rationale: [[file:../../docs/design/task-review.org][docs/design/task-review.org]].
* When to Use This Workflow
User says one of: "task review", "review tasks", "let's do a task review", "groom my tasks", "task-review".
Cadence is daily and rotational — the batch is the oldest-unreviewed tasks, so consecutive days cover different tasks. At the default batch size of 7 over ~80 open tasks, the full list rotates about every 12 days.
* Phase A: Precondition
Confirm =todo.org= exists at the project root. If it doesn't, say "this project has no =todo.org= to review" and stop — there's nothing to do.
* Phase B: Select the batch
Run the staleness script in list mode to get the oldest-unreviewed top-level tasks. Default batch size is 7; let Craig override if he asks for more or fewer.
#+begin_src bash
.ai/scripts/task-review-staleness.sh --list todo.org 7
#+end_src
Each output line is tab-separated: =<line> <LAST_REVIEWED-or-NONE> <heading>=. The list is already ordered oldest-first (never-reviewed tasks sort before dated ones), so walk it top to bottom. Selection only includes depth-2 =**= headings that are =TODO=/=DOING=/=VERIFY= with an =[#A]=/=[#B]=/=[#C]= cookie — DONE/CANCELLED and deeper headings are out by construction.
If the list is empty, report "nothing to review — every task has been looked at recently" and stop.
Read =todo.org= once now so the body of each selected task is in context for the walk. Don't re-read per task.
* Phase C: Walk the batch
Get today's date once for the stamp:
#+begin_src bash
date "+%Y-%m-%d"
#+end_src
Then take the tasks one at a time, in list order. For each, show Craig the heading, its priority, when it was last reviewed (or "never"), and a one-line reminder of the body. Then ask what to do. The actions:
| Action | What it does | Stamp =:LAST_REVIEWED:=? |
|--------+--------------+--------------------------|
| *Keep* | Still correct as-is — no change beyond recording the review | Yes |
| *Re-grade A/B/C* | Change the priority cookie to =[#A]= / =[#B]= / =[#C]= | Yes |
| *Kill* | Abandon it: =TODO=/=DOING= → =CANCELLED= plus a =CLOSED: [YYYY-MM-DD Day]= line | No (it leaves the pool as CANCELLED) |
| *Doing* | =TODO= → =DOING= (no-op if already DOING/VERIFY) | Yes |
| *Edit* | Reword the heading or body — do it with Craig, then record the review | Yes |
| *Skip* | Not now — leave it untouched so it resurfaces next run | No |
Keep is the common case — most tasks are still right and just need re-stamping. Be decisive and quick; this is a 5-minute habit, not a planning session.
*** Tagging =:quick:= — small tasks
While reviewing each task, estimate its effort. If you judge it *30 minutes or less* and it doesn't already carry =:quick:=, add the tag to the heading line. If the heading and body don't tell you how long it'll take, *ask Craig* — don't guess. A wrong =:quick:= is worse than none: the tag exists so Craig can grab a genuinely small task in a spare moment, and a mislabeled one wastes that moment.
This is orthogonal to the action chosen — a task can be kept (or re-graded, or marked DOING) *and* tagged =:quick:= in the same pass. Skip the assessment on a Kill, since it's leaving the pool. Tags go on the heading line per [[file:../../claude-rules/todo-format.md][todo-format.md]], sharing one =:tag1:tag2:= cluster.
*** Tagging =:solo:= — tasks Claude can finish end-to-end
While reviewing each task, judge whether Claude could build *and* verify it without Craig's help, and if so add =:solo:= to the heading line. Three gates, all of which must hold:
1. *Buildable* — Claude has the capability and access to do the work.
2. *Verifiable by Claude* — an objective or local check exists that Claude can run itself. Craig's routine spot-checking does not count against this, and neither does handing off a residual human-in-the-loop confirmation as a structured manual-testing reminder (the =verification.md= "Handing Off Manual Verification" pattern). The disqualifier is having no verification path of Claude's own at all — when the success criterion is only judgeable by Craig's eyes or subjective taste.
3. *No upfront decision* — no design or preference call Craig must make before Claude can begin.
If any gate is shaky, leave the tag off. Like =:quick:=, a wrong =:solo:= is worse than none — it tells Craig he can hand the task off and walk away, so a mislabeled one wastes that trust. When the heading and body don't make all three gates clear, ask Craig instead of guessing.
The shape of a solo task: Claude builds it, verifies everything it can verify itself, and leaves a manual-testing reminder for the residual confirmation Craig does anyway. Craig running that reminder is assumed and does not flip the task to non-solo — solo is about whether Claude *can* verify, not whether Craig *also will*.
=:solo:= is independent of both the action and =:quick:=. A task can be =:solo:= but slow (a bounded refactor that takes hours yet needs no input) or =:quick:= but not =:solo:= (a five-minute change that hinges on a preference call). Tag each axis on its own merits; both share the one =:tag1:tag2:= cluster. Skip the assessment on a Kill.
*** Stamping =:LAST_REVIEWED:=
Set =:LAST_REVIEWED:= to today's date (from above) in the task's =:PROPERTIES:= drawer:
- If the task already has a =:PROPERTIES:= drawer, update or add the =:LAST_REVIEWED:= line inside it.
- If it has no drawer, insert one immediately after the heading — or, when the heading carries a =DEADLINE:=/=SCHEDULED:=/=CLOSED:= planning line, immediately after that line (org requires the planning line to sit directly under the heading, with the drawer below it):
#+begin_example
** TODO [#A] Some topic :tag:
:PROPERTIES:
:LAST_REVIEWED: 2026-05-20
:END:
Body...
#+end_example
The exact date string matters: =task-review-staleness.sh= and the wrap-up health check both parse =:LAST_REVIEWED: YYYY-MM-DD=.
*** Killing a task
Follow the completion rules in [[file:../../claude-rules/todo-format.md][todo-format.md]]. A killed top-level =**= task stays task-shaped: change the keyword to =CANCELLED=, add a =CLOSED: [YYYY-MM-DD Day]= line under the heading (generate with =date "+%Y-%m-%d %a"=), and leave the priority and tags intact. It's then a candidate for =--archive-done= at the next cleanup. Don't stamp =:LAST_REVIEWED:= on a kill — it's leaving the review pool anyway.
* Phase D: Close out
When the batch is done (or Craig calls it early):
1. Summarize what changed — re-grades, kills, anything marked DOING, anything newly tagged =:quick:= or =:solo:= — in a couple of lines. Don't list the keeps individually; "the rest were confirmed as-is" is enough.
2. The edits are already written to =todo.org=. If Craig keeps =todo.org= open in Emacs, remind him to revert the buffer so his editor picks up the changes (and flag that any unsaved edits he had open could collide — re-running picks up whatever's on disk).
* Common Mistakes
1. *Re-reading =todo.org= per task* — read it once in Phase B; the in-memory view is canonical for the walk.
2. *Stamping a killed task* — a kill leaves the pool; no =:LAST_REVIEWED:= needed.
3. *Walking more than the batch* — staleness ordering means the batch is the right set; don't expand it into a full-list review.
4. *Turning it into planning* — this is hygiene (is each task still right?), not "what should I do today". For that, use =open-tasks.org=.
5. *Drifting the date format* — =:LAST_REVIEWED:= must be =YYYY-MM-DD=, or the staleness script won't read it.
6. *Marking a kill DONE instead of CANCELLED* — DONE means finished, CANCELLED means abandoned. A task review kills tasks that shouldn't be done at all.
7. *Guessing a =:quick:= estimate* — if the heading and body don't make the effort clear, ask Craig instead of tagging on a hunch. A mislabeled =:quick:= defeats the tag's purpose.
8. *Over-tagging =:solo:=* — if you can't confirm all three gates (buildable, verifiable by Claude, no upfront decision), leave it off. A =:solo:= whose only verification is Craig's eyes, or that needs his input or hardware, defeats the tag's purpose. But a task Claude builds and verifies itself, leaving Craig a manual-testing reminder for his routine spot-check, *is* solo — the reminder doesn't disqualify it.
* Living Document
Adjust the batch size if 7/day feels wrong — smaller for a tighter daily touch, larger to rotate faster. If the action set grows (e.g. a "defer with a date" action), add it to the Phase C table and note the stamping behavior.
|