Anti-busywork forcing function
May 25, 2026 · View on GitHub
If your retrospective / learning-log / tracking tool generates new items on every run regardless of whether old items were ever acted on, the tool is busywork. Here's a 4-step mechanism for fixing that.
Originally implemented in the growth-retrospective skill. Pattern is tool-agnostic.
The failure mode
Every retro tool I've used (Notion templates, weekly retros, Roam dailies, custom spreadsheets) has the same long-term failure: items added monotonically, never removed. After 3 months the log is an aspirations dump. After 6 months it's psychic baggage. After 9 months I quietly stop opening it.
The root cause is structural, not behavioral:
- The tool generates new entries every run
- Old entries have no exit condition tied to observable artifacts
- The user has to do all the "is this still relevant?" work manually
- Manual work doesn't happen consistently → cruft accumulates → trust dies
The mechanism — 4 steps
Add a pre-scan gate to your tool. Run it before generating any new items.
Step 1. Extract prior commitments
Read the tool's last output. Pull out every action item / level-up step / TODO
that was proposed last time. Most tools store these as bullets under a
"next steps" or "follow-ups" heading. Even better if you can extract a named
artifact per item — "write STATS-CHEATSHEET.md", not "get better at stats."
Step 2. Check the world for evidence
For each named artifact, check whether it exists:
- Markdown / docs →
git log --all -- <path>orfind . -name <basename> - CLI flags →
grep -r "<flag>" - Scripts →
find . -name "<script>" - External setup (alerts, account changes) → can only confirm via user
You're not asking the user "did you do it?" You're checking observable state.
Step 3. Triage by ratio
Compute three numbers:
- N_completed: artifacts that exist now but didn't last time
- N_pending: artifacts proposed but still absent
- T_since_proposed: days since the last retro
Apply a heuristic. Mine is:
if N_pending >= 3 and N_completed == 0 and T_since_proposed >= 14:
push_back()
else:
proceed_to_new_scan()
The numbers are tunable; the shape is what matters.
Step 4. Push back with options, not silence
When the gate triggers, do NOT just refuse the run. Give the user three options:
- A (Commit): pick one of the pending actions and "make it active" — the user is now on the hook for closing this one before the next retro.
- B (Deprioritize): explicitly kill 1+ pending actions. They get removed from the tool's log. New items can be added next run.
- C (Override): proceed with a new scan anyway, but the override reason gets logged into the new retro.
This is the critical design decision. Push-back without options creates frustration. Push-back with explicit choices turns the tool into an accountability loop: items don't pile up because the user is forced to either close them or kill them.
Why "observable artifacts" matters more than "self-reports"
The whole mechanism breaks if the exit condition is "the user feels confident about X." Confidence is the trailing indicator of having internalized something. By the time you feel confident, you're done; you don't need the tool to tell you. By the time you don't feel confident yet, you might still be done, but you'd give up too early.
Anchor exit conditions in observable artifacts:
| Bad exit condition | Good exit condition |
|---|---|
| Feel confident with statistics | 3 consecutive PRs land a stats decision without an external consult |
| Understand the entity taxonomy | 2 consecutive sprints with no new entity type added |
| Know when to deploy carefully | 3 months without a 429 / rate-limit incident |
| Better at decision-making | Median time-to-decision on a Tier 1 domain drops 50% over 2 months |
The good ones are:
- Observable (anyone with
git logorgh issue listcould verify) - Bounded (you can know when you've satisfied them)
- Reversible (if condition stops holding, item bumps back into focus)
When NOT to apply this pattern
Don't add a forcing function to a tool whose value is passive observation without intervention:
- A dashboard showing system uptime
- A weekly digest of stats
- A read-only audit report
The forcing function only makes sense when the tool is supposed to change behavior. If the tool is informational, gate-keeping next runs is just gatekeeping.
Variants to consider
- Streak-aware gating: only push back after 2 consecutive "0 completed" runs, not the first one. Avoids gating users who legitimately had a busy fortnight.
- Severity grading: a single pending action triggers a soft nudge; 5+ pending triggers a hard block.
- Class-specific timeouts: a one-page cheatsheet has a 7-day timeout; a CI integration has a 30-day timeout. Different cost-to-complete = different patience window.
Companion tool
The growth-retrospective skill implements this pattern for personal-growth retrospectives, using git history
- chat archive as signal sources. Cross-agent (Claude Code, OpenAI Codex CLI, Google Antigravity).
One-line install:
curl -fsSL https://raw.githubusercontent.com/YoungApple/growth-retrospective-skill/main/install.sh | bash
But the pattern itself is the point. It works in any tool whose value depreciates when items pile up.
Credit
The "anti-busywork" framing came from a persona-review pass where a simulated "returning user 2 weeks later" reported: "my growth log looked the same as last time. Why would I run this again?" That feedback is the entire reason the gate exists.
If you build something with this pattern, drop a link in the skill's roadmap issue — I want to read what other shapes the pattern takes.