Task planner

A project-scoped task lifecycle the agent walks through with you. Replaces ad-hoc planning docs (the kind that live in conversation context and vanish the moment a session ends) with persistent state in CommitMind. Decisions made along the way auto-link to the task; commits land tied to it; future sessions get the right context cheaply.

The phase model

Every task moves forward through five phases plus an escape hatch:

discovery → design → implementation → review → done
                                                 ↘ abandoned (any time)

What belongs in each phase:

Forward only. The handler rejects reverse moves (design → discovery) with 422 phase_regression and rejects any move out of done / abandoned with 422 terminal_state — once a task is closed it stays closed.

MCP tools

| Tool | Purpose | | --- | --- | | task_create(title, description?) | Start a new task. Defaults to discovery. | | task_advance(task_id, to_phase, note?) | Move forward through the lifecycle. Reverse moves rejected. | | task_set_active(task_id?) | Pin which task this session works on. Omit task_id to unpin. | | task_get_active() | Returns the active task plus recent observations and decisions. | | task_list(include_terminal?, limit?) | Browse all tasks. | | task_complete(task_id, note?) | Convenience wrapper for moving to done. |

Concrete example: starting work on a notification system.

task_create({ title: "Add notification system" })
  → { id: "t_01j...", phase: "discovery" }

task_set_active({ task_id: "t_01j..." })
  → { active_task_id: "t_01j..." }

task_advance({ task_id: "t_01j...", to_phase: "design", note: "Scoped to email + in-app, no push." })
  → { id: "t_01j...", phase: "design" }

Auto-attach behavior

When a session has an active task pinned, every log_observation, every promote_decision, and every commit ingested in that session automatically links to the task. The MCP resolves the active task once per session (cached) and forwards task_id on every write — no extra arguments needed at the tool surface.

Out-of-session writes do not auto-link. The CLI's commitmind capture and the server-side commit backfill both run without a session context, so commits ingested through those paths land with task_id = NULL. That's intentional: backfill processes a project's whole history and shouldn't pick a single task to attribute everything to.

Phase summaries

Each non-terminal phase transition triggers a background job that reads everything captured during the closing phase — observations, decisions, the manual transition note — and emits a 2–3 sentence retrospective via gpt-4o-mini. The summary lands in two places:

  1. task_phase_transitions.auto_summary on the transition row itself, so the dashboard can render the phase history with prose context.
  2. A phase_summary observation linked to the task, so the project's hybrid search picks it up alongside everything else.

The worker runs in the background (5s busy poll, 30s idle), drains one transition per tick, and is best-effort: a flaky LLM call writes an empty-string sentinel so the row stops appearing in the queue rather than being retried forever. A failed summary never blocks the transition itself — task_advance returns the moment the phase column flips.

Terminal transitions (done, abandoned) don't trigger a summary — the worker query filters them out. Closing a task is the user's explicit signal that no further retrospect is wanted.

prime_session integration

When a session has an active task pinned, the active task's context is delivered as the first block of prime_session output. Token budget: ~1500. Includes:

No active task → no block, and the rest of prime_session's output is unchanged. Failures fetching the task context degrade gracefully: prime still returns the project-level commits + decisions + observations bundle.

Typical workflow walkthrough

The agent script for a small feature, end-to-end:

User: "Let's add a notification system"

Claude: [calls task_create("Add notification system")]  → task_id A
        [calls task_set_active(A)]
        [discovery phase] "What kind of notifications? In-app, email, push?"

User: "Email + in-app for now."

Claude: [calls log_observation("decided email + in-app, push deferred to v2")]
        [calls task_advance(A, "design", "Scoped to email + in-app, no push.")]
        [design phase] "OK, let me sketch the architecture..."
        [calls log_observation with type='design_note',
          "Notifications use a single fan-out worker..."]
        [calls promote_decision("Use in-process fan-out for notifications", ...)]
        [calls task_advance(A, "implementation", "Design locked.")]
        [actual coding happens; commits land + auto-link to task A]
        [calls task_advance(A, "review", "Implementation passes manual smoke + tests.")]
        [calls task_complete(A, "Reviewed by team, shipped.")]

Three things to notice:

Comparison to claude-superpowers / similar planning plugins

Conversation-context planning tools (the claude-superpowers plugin's writing-plans / executing-plans skills are the canonical example) load instruction docs into your session every time and keep state in the conversation transcript. They're great inside a single session; they evaporate the moment you compact, switch repos, or hand the work to a teammate.

CommitMind tasks live in your project's database. One source of truth across all sessions and team members. Every team member's Claude session sees the same active tasks; humans can browse, edit, advance, and abandon tasks via the dashboard without any agent involvement. The agent and the human are always looking at the same state.

The two approaches compose: use claude-superpowers for the in-session planning ritual ("write the plan, review it, execute step by step"), and CommitMind tasks for the persistent shell — task_create at the start, task_advance at each phase boundary, decisions and design notes auto-attach as they happen.

Privacy and costs

Observation and decision content is sent to the LLM at phase transitions only — about $0.001 per transition with gpt-4o-mini. This cost is not counted against the per-org decision-extraction quota; the auto-summary path is operational tooling, billed at the platform level rather than to your org.

No content is sent for ordinary task ops. task_create, task_advance, task_set_active, task_get_active, task_list, and task_complete all hit Postgres only. The LLM call fires from the worker after the transition lands, asynchronously.

Self-hosting and disabling

The auto-summary worker requires AI_GATEWAY_API_KEY on the API server's environment. When the key is unset, the summarizer silently disables: task_phase_transitions.auto_summary stays NULL, no phase_summary observation is emitted, and the worker logs a single "summarizer disabled" line at startup. The rest of the task workflow — create, advance, set active, list, complete, the dashboard, the auto-attach behavior — works fine without it.

To turn it back on after self-hosting: set the key, restart the worker. Pending transitions are picked up on the next idle tick.

Next steps