Skip to content
NeuroDock

mcp-task-fractionator

ToolWhat it takesWhat it returnsWhy your brain cares
decompose{ goal, time_budget? }3–12 atomic tasks with acceptance criteria and a one-paragraph rationaleconverts the wall of “plan the migration” into things small enough that starting one is cheaper than avoiding it
next_one{ project }exactly one task, plus reasoning and a confidence numberanswers “what do I do right now” without re-deciding priorities — the choice fatigue moves out of your head and into the server

The fractionator’s whole job is the column-shift below: vague intent on the left, atomic moves on the right.

Before — vague goalAfter — atomic tasks (with time budgets)
“Plan the migration.”1. Inventory current staging DB schemas (PT20M) — acceptance: list of every table + row-count in a markdown file.
2. Read the prod runbook end-to-end once (PT30M) — acceptance: bullet-list of every step that touches a write path.
3. Draft the migration playbook headers only (PT15M) — acceptance: section titles, no body text.
4. Identify the three riskiest steps (PT25M) — acceptance: each step has one rollback line.
5. Sketch the rollback plan for step 1 only (PT30M) — acceptance: a checklist Sarah could follow if I were offline.

The rationale paragraph that ships with the response surfaces every assumption (timezone, what “end of week” meant, what was deliberately dropped) so the user can correct any one of them without re-running the decomposition.

mcp-task-fractionator carves a vague goal into a small ordered list of atomic 5–90 minute tasks with explicit acceptance criteria and dependency edges. It is stateless — persistence is the caller’s job, via mcp-cognitive-graph.

  • Package: packages/mcp-task-fractionator/
  • Version: 0.0.3
  • Schemas: packages/mcp-task-fractionator/schemas/*.schema.json
  • ADR: 0003 — Task fractionator tool design
  • Schema $id prefix: https://schemas.neurodock.org/mcp-task-fractionator/v0.1.0/
ToolInputOutput
decompose{ goal: string, time_budget?: string, max_chunk_size?: integer, time_buffer_multiplier?: number, motor_fatigue_aware?: boolean }{ tasks: Task[], rationale: string, time_buffer_multiplier?, motor_fatigue_aware?, truncated? }
next_one{ project: string }{ task: Task, reasoning: string, confidence: number }

Input:

  • goal — plain-language goal, 5–500 characters. Treated as private user data; never logged.
  • time_budget — optional ISO 8601 duration (PT4H, P3D, PT30M). The total estimated_minutes across returned tasks fits within the budget; otherwise the server returns BUDGET_INFEASIBLE rather than silently truncating.

Optional neurotype knobs (ADR 0011 — additive, default to today’s behaviour when absent; the server never branches on a neurotype enum):

  • max_chunk_size — integer 1–20. Caps the number of tasks returned, below the normal 3–12 target. When the goal naturally needs more steps, the server keeps the lowest-sequence prefix (a valid sub-DAG with no dangling dependencies), sets truncated: true, and says so in the rationale. It never silently drops steps or returns an invalid order.
  • time_buffer_multiplier — number 1.0–3.0. When greater than 1.0, each task gains an additive padded_minutes equal to round(estimated_minutes × multiplier); estimated_minutes stays raw so a presentation layer never double-pads. A value of 1.0 (or omitting the field) produces no padding. Out-of-range values are rejected with INPUT_INVALID.
  • motor_fatigue_aware — boolean. When true, the server echoes the preference and names it in the rationale so the client/skill can pace breaks. The server has no view of keystroke/click activity and does not infer fatigue.

Output:

  • tasks — array of 1–20 tasks (target 3–12, per ADR 0003). Each task has:
    • id — UUIDv4, server-generated.
    • title, description — verb-led, concrete.
    • estimated_minutes — integer in [5, 90]. Floor prevents trivial-shred; ceiling enforces atomicity. Always raw — never buffer-adjusted.
    • padded_minutesoptional, additive. Present only when time_buffer_multiplier greater than 1.0 was supplied; equals round(estimated_minutes × multiplier). Omitted otherwise.
    • acceptance_criteria — non-empty array. Required. An empty array is rejected as ACCEPTANCE_CRITERIA_REQUIRED.
    • dependencies — UUIDv4 references to siblings in the same response. Cycles are rejected.
    • sequence — 1-indexed total order. Distinct for every task; next_one is “sequence = 1 of the unfinished subset”.
    • tags — free-form labels for filtering.
  • rationale — one paragraph the user can read in 5 seconds. Surfaces assumptions (“I assumed Friday meant end-of-business Friday in your local timezone”). Not a marketing summary. Names any active knob (the padding multiplier, truncation, motor-fatigue-aware preference).
  • time_buffer_multiplier, motor_fatigue_aware, truncatedoptional, additive echoes. Each is present only when the corresponding knob was active; omitted otherwise so a no-knob call is byte-identical to the pre-R2 wire shape.

Reads from mcp-cognitive-graph to find pending tasks under the named project. Returns exactly one task plus reasoning and a confidence number.

The fractionator owns the decomposition algorithm; the graph owns the state.

CodeMeaning
GOAL_REQUIREDGoal missing or shorter than 5 characters after trimming.
GOAL_TOO_LONGGoal exceeded 500 characters. Split the goal itself.
TIME_BUDGET_UNPARSEABLEBudget did not match the ISO 8601 duration regex. No silent fallback.
INPUT_INVALIDAn R2 neurotype knob was out of range: max_chunk_size not a positive integer 1–20, or time_buffer_multiplier outside [1.0, 3.0]. Rejected, never clamped.
BUDGET_INFEASIBLENo task list fits the budget while still covering the goal. May include minimum_feasible_minutes.
DEPENDENCY_CYCLECandidate decomposition produced a cycle. Server bug, surfaced explicitly.
ACCEPTANCE_CRITERIA_REQUIREDInternal invariant — a candidate task had zero acceptance criteria.
DECOMPOSITION_UNAVAILABLELocal heuristic engine could not produce a credible decomposition. Payload SHOULD include a clarifying_question string.

decompose returns a task list but does NOT persist it. Callers (typically skills) write the tasks to mcp-cognitive-graph:

  • Each task becomes an entity (record_fact with the task id as subject and estimated_minutes, acceptance_criteria as facts).
  • Each dependency becomes a fact with predicate: "depends_on".
  • The project becomes an entity that owns the tasks via predicate: "part_of" (note: part_of lands in v0.2; v0.1 uses belongs_to).

The skill SDK ships a one-liner — decompose_and_persist(goal, project, time_budget?) — for the common path.

  • No remote calls.
  • No LLM call from inside the server. The v0.2 decompose_with_assist path will accept an LLM-drafted decomposition as input; the server remains the schema and invariants authority.
  • Goal text is never logged — not at info, not at debug, not in error payloads. Validation errors reference field names, not content.
  • Additive-only within v0.1.x.
  • The 5–90 minute estimated_minutes range, the 1–20 task count range, and the required non-empty acceptance_criteria are part of the contract; changing them is a major bump.