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:

  1. The tool generates new entries every run
  2. Old entries have no exit condition tied to observable artifacts
  3. The user has to do all the "is this still relevant?" work manually
  4. 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> or find . -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 conditionGood exit condition
Feel confident with statistics3 consecutive PRs land a stats decision without an external consult
Understand the entity taxonomy2 consecutive sprints with no new entity type added
Know when to deploy carefully3 months without a 429 / rate-limit incident
Better at decision-makingMedian time-to-decision on a Tier 1 domain drops 50% over 2 months

The good ones are:

  • Observable (anyone with git log or gh issue list could 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.