Use ONLY when the user explicitly asks to plan a task, create a task file, produce a task breakdown in the accepted format, or prepare a critiqued strategy before coding. Writes under the `tasks` role. Not for design chat or ad-hoc code suggestions.
62
75%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
Fix and improve this skill with Tessl
tessl review fix ./plugins/flowai/skills/plan/SKILL.mdCreate a clear, critiqued plan in the tasks location resolved from AGENTS.md, written in the project's accepted task format. The template default uses date hierarchy directories and a slug without a date prefix, but the project instructions are authoritative. Tasks are committed records with extended frontmatter, so they serve as the canonical record of what was decided, planned, and shipped.
Canonical empty-valued example for an operational task with no FR / tags / related tasks:
---
date: "2026-05-17"
status: to do
implements: []
tags: []
related_tasks: []
---Binds on EVERY question you ask — the clarifying questions in Step 2 and the variant selection in Step 4 alike:
1., 2., …), not a heading, a bold-only line, or a paragraph.agent's choice — on a multi-select where the user delegates with agent's choice (or its language equivalent), pick the subset yourself, justify the pick in one line, and proceed without re-asking for confirmation.<step_by_step>
Initialize
todo_write, todowrite) to create a plan based on these steps.YYYY-MM-DD format (e.g. via date +%Y-%m-%d or your environment's date primitive). Hold it as <DATE>. Derive <YYYY> and <MM> (zero-padded). Resolve the tasks role from AGENTS.md and then derive the eventual task file path from that role's layout.Deep Context & Uncertainty Resolution
SRS and SDS from AGENTS.md. If you don't know their current content, read the resolved files now.tasks role. For each found file, parse its YAML frontmatter implements: field. Keep only tasks whose implements: set has a non-empty intersection with the FR-IDs you are about to put in the new task's implements:. Cap at 10 by recency (newest first by frontmatter date); if more match, list IDs in chat without bodies and ask the user which to expand. Read the full body of each kept task before drafting the new task's body. List the loaded tasks in chat (one bullet per task: file path + matched FR-IDs + one-line summary). That list is the KEPT set and nothing else. Opening a candidate's frontmatter to test the intersection is not loading it: a task whose implements: shares no FR with yours must not appear in the list, must not be summarised, and must not reach related_tasks: — a rejected candidate presented as loaded context is the failure this filter exists to prevent. If no related tasks exist, say "No prior tasks share FRs with this one — drafting from scratch."Proactive Resolution from AGENTS.md: analyze prompt, codebase, search for gaps.glob, grep, ripgrep, search, webfetch) for unknowns.surface-scout): when the enumeration above ran AND your environment provides the pre-declared surface-scout agent, dispatch it now via your subagent tool (e.g. Task, Agent, task; on Codex the tool is spawn_agent — pass agent_type="surface-scout" and fork_turns="none" (a full-history fork cannot carry an agent type), then collect with wait_agent), naming surface-scout as the agent type. A generic exploration or search agent your host offers (Explore, general-purpose, and the like) is NOT a substitute: the cross-check's value comes from that agent's own instructions, and swapping it for a generic one silently turns the independent pass into an ordinary search. Input: the user's request text VERBATIM (plus quoted user clarification turns, if any) — NOTHING else. Do NOT include your own enumeration, your restatement of the request, a suspected fix location, or a preferred approach: the scout's value is independence, and seeding it with your framing destroys the cross-check. Ask for the report, not a launch — many subagent tools dispatch in the background by default and answer with a handle (an agent id plus token/duration counters) instead of the scout's findings. When your tool offers a foreground or blocking mode (a run_in_background: false parameter or equivalent), set it, so the call returns the report itself. If you nevertheless get back only a handle, CONTINUE THAT AGENT by its id — send it a message or resume it and ask it to state its findings — and use what it answers. Do NOT feed an agent id to a background-task polling tool: an agent id and a background-task id are different things, and the poll answers No task found with ID: <id> however long you give it. Redeeming that handle is a step you owe, not an option: a dispatch you launched and never collected has cost turns and bought nothing, and the pull to shrug and enumerate the tree yourself is strongest exactly there. Hold the collected report for step 3. You may quote the scout only from a message you can point to. If no message ever carried its text, write no quotation — say in one line that the report did not arrive, and let your own enumeration stand under your own name. Your enumeration is welcome in the surface list; it is a forgery under the scout's byline. Establish availability by LOOKING, never by assuming — list the agent directories (ls .claude/agents/ .cursor/agents/ .opencode/agent/ "${CODEX_HOME:-$HOME/.codex}/agents/" 2>/dev/null); a surface-scout file there — .md for most hosts, surface-scout.toml under the Codex home — means the agent is installed, so dispatch it. Running inside a sandbox or an automated harness is NOT evidence of missing subagents; decide from the listing, not from where you think you are. Doing the pass inline instead is the one outcome this step exists to prevent. Only an empty listing, or a dispatch that actually failed, skips it; step 3 then records the degradation visibly.Draft Framework (G-O-D)
mkdir -p or your environment's equivalent).date: YYYY-MM-DD, status: to do, implements: [FR-..., ...] (or []), tags: [...] (or []), related_tasks: [...] (or []). Write the empty list, never omit the key. Eliding one is a defect, and the two that get elided in practice are tags and related_tasks — the task-file example the accepted format carries shows only implements:, so a file copied from it looks finished while missing two keys.## Goal, ## Overview (with ### Context, ### Current State, ### Constraints), ## Definition of Done — seed one bullet per outcome the request states (behaviors, examples, acceptance conditions, deliverables), in the request's own terms; preserve stated expected results exactly (no paraphrase). Related outcomes may collapse into one bullet when a single acceptance check proves them all. No discrete outcomes stated → leave placeholder bullets. Acceptance tuples are added in step 5a.try-catch, and which tests prove error propagation is preserved.### Affected Surface under ## Overview (only when the affected-surface enumeration ran): FIRST the scout's collected report as a clearly delimited VERBATIM block (fenced, unedited — this is the raw record plan-critic, review, and the human recompute the divergence from). Only text the scout actually returned may go in that block: labelling your own enumeration as the scout's output is a fabricated quotation and a worse defect than having none — when you did not collect a report, omit the block and name the reason in one line instead. Copy it, do not retype it. Tidying is what breaks this in practice, and it does not read as tidying at the time: shortening absolute paths to repo-relative ones, dropping the scout's evidence lines because the bullet above already says it, merging two of its bullets, reflowing its headings. Each of those makes the block disagree with what the scout sent, and the whole point of the block is that a later reader can hold it against the scout's own words. Too long is not a reason to trim — a long block is the record working. If you find yourself improving the text, you are writing your own enumeration under someone else's byline. THEN one PLAIN bullet per surface item/class from the UNION of your list and the scout's — every row of the scout block gets its own bullet here, INCLUDING the rows the scout itself already marked not affected (copy its evidence into your bullet; the fenced block is the scout's record, the disposition list is yours, and a row present only inside the block has no disposition — observed 2026-09-06, plan-affected-surface-scout: the two scout rows for documents/ and .codex/ had no bullet and the critical item failed) — - <item> — <disposition>, where the disposition is one of: covered-by <DoD item / planned step>; not affected — <inspected evidence> (evidence forms by domain: code = path/lines; infrastructure = environment/service + config key; process = document/step/owner); deferred — human choice. Checkbox bullets (- [ ]/- [x]) are FORBIDDEN in this subsection — they would corrupt automatic task-status derivation. Items you are unsure about default to deferred — human choice and are surfaced at variant selection. Write the real content the moment you create the heading: a promise such as (surface enumeration will be added after variant analysis) is a FORBIDDEN placeholder — an empty heading reads as "nothing affected" to every downstream reader. Nothing to enumerate → omit the heading entirely rather than stub it.surface-scout file; the dispatch errored outright; or the dispatch ran but you could not obtain the scout's findings by any route. In every one of them the task file MUST carry, under ## Follow-ups, the line Surface cross-check (surface-scout) did not run — no subagent support in this environment. This is not optional bookkeeping: it is the only trace that the cross-check is missing, and its absence claims a verification that never happened. Create ## Follow-ups if the file has no such section yet.## Solution section yet.Strategic Analysis & Variant Selection
Variant Analysis from AGENTS.md.— partial: drops <constraint> and say the constraint is deferred rather than met. Name the debt in this variant's Cons in so many words — what it defers, and what it will cost to undo when the deferral runs out. "Simplest" and "fewest dependencies" are not that: they describe the build, not the bill, and a reader cannot weigh a cost nobody stated. Widening it until it needs no such marker deletes the archetype: the set then holds three correct designs and no fast one, and the trade-off the user was meant to weigh never reaches them.A., B., C., …); the option's own Pros, Cons, Risks and Best For are nested under it. There is no separate variant write-up anywhere before the question — no ### Variant N sections, no bolded option headers followed later by a bare "which do you prefer?". Describing a variant twice is the defect this rule exists to prevent: the copies drift, and the reader reads the same thing twice to answer once.undefined for an input class), one variant MUST fix THAT helper — return the correct value for the input it mishandles — even when a team note discourages touching shared code. The note is an input to the ranking below, not a filter on the list: a plan that offers only consumer-side patches has already decided the question the user is asked to decide. (2026-09-06: plan-recommends-root-over-symptom offered three DB-side variants and none touched getTimezoneName().)— full scope when the variant covers all stated outcomes, or — partial: drops <dropped outcome(s)> when it does not. If the dropped list is too long for a title, use a count in the title (— partial: covers 2 of 4 stated outcomes) and name every dropped outcome in the variant's Cons. A bare partial marker without named outcomes or a count is a defect. Dropped outcomes MUST also be named in the variant's Cons. A stated outcome must appear in ≥1 variant or be explicitly named as deferred at selection time — a silent drop is a planning defect. The scope choice is made at variant selection on this visible information; after selection, record the chosen variant's dropped outcomes under ## Follow-ups in the task file. A partial marker is this rule working, not a defect it reports. Two things are defects: dropping an outcome silently, and enlarging a variant until it covers everything so that no marker is needed. The second one does not feel like a defect while you write it — it feels like refusing to offer a broken option — which is why it has to be named here. It deletes the choice the user was supposed to make, and it deletes it invisibly, because a set of uniformly full-scope variants still looks complete.Detail Solution (S) — execute immediately after user selects a variant
## Solution section placeholder with concrete implementation steps for the selected variant (follow the project's accepted task format).### Affected Surface exists: update its dispositions to the SELECTED variant — every covered-by must point at a step or DoD item of the chosen variant's Solution; items the chosen variant drops become deferred — human choice with a matching ## Follow-ups entry.
5a. Acceptance Tuple Check — execute immediately, no permission needed## Definition of Done. For each, confirm the tuple (FR-ID, Test path or Benchmark id, Evidence command) is present and concrete (no placeholders like <TBD> or TODO). manual — <reviewer> is acceptable only with an explicit reviewer name.implements: that are absent from the resolved SRS, the task MUST contain an explicit DoD entry "add FR-XXX section to SRS with **Acceptance:** field filled".**Tasks:** Back-Pointer (FR-DOC-TASK-LINK) — execute immediately, no permission needed. This is a write step.implements: frontmatter, locate the heading ### <FR-ID>: in the resolved SRS.**Description:** bullet (- **Description:** ...). Look at the line(s) immediately following it within the same section.
- **Tasks:** [...] bullet already exists: append , [REF:task:<YYYY>-<MM>-<slug> | <slug>] to the comma-separated list. Idempotency: if the exact SALP REF is already in the list, do nothing for that FR.**Tasks:** bullet exists yet: insert a new line - **Tasks:** [REF:task:<YYYY>-<MM>-<slug> | <slug>] immediately AFTER the **Description:** bullet (before any other bullets in the section). The task: namespace id is <YYYY>-<MM>-<slug> (e.g. 2026-06-adopt-salp-anchors), derived from the task file's path.5b. Update Documentation Index (FR-DOC-INDEX) — execute immediately, no permission needed. This is a write step, not a planning step.
index from AGENTS.md. For every FR-ID in the task's implements: frontmatter, register a row there.index file does not exist, create it with a ## FR heading (additional sections like ## SDS, ## NFR may be added by other skills; do not pre-scaffold them here).## FR, ensure exactly one row per FR-ID. Row format (SALP):
- [REF:fr:<id> | <FR-ID>] — <one-line summary> — <status>
<id> — lower-kebab of the FR mnemonic (strip FR- prefix, lowercase, preserve . for hierarchical IDs like FR-DIST.MARKETPLACE → dist.marketplace). The reference resolves against the [ANC:fr:<id>] token next to the SRS heading. If the SRS section does not yet exist, write the REF anyway — develop/commit will add the matching ANC when the SRS section is added, at which point scripts/check-salp.ts will resolve it.<one-line summary> — pull from the SRS **Description:** first sentence if the section exists, otherwise reuse the task title (or a short paraphrase ≤80 chars).<status> — mirror the SRS **Status:** value if present, else [ ].## FR before writing.plan-critic): when the task file contains a ### Affected Surface scout block OR step 4 presented 2+ variants, AND your environment provides the pre-declared plan-critic agent — dispatch it via your subagent tool with the task file path as input (on Codex the tool is spawn_agent — pass agent_type="plan-critic" and fork_turns="none" (a full-history fork cannot carry an agent type), then collect with wait_agent), then COLLECT its report the same way as the scout in step 2 — ask for a foreground/blocking dispatch where the tool offers one, and if you get back only an agent id, continue that agent by its id rather than polling it as a background task. Present its returned objection list in chat VERBATIM as the critique for step 7. A fresh context is the point: do not summarize, soften, or pre-filter its objections. If the dispatch fails or the agent is not installed, fall back to self-critique below AND write one line under ## Follow-ups: Independent critique (plan-critic) did not run — no subagent support in this environment.## Follow-ups entry naming the deferral reason; additionally, every covered-by pointer in ### Affected Surface resolves to an existing Solution step or DoD item (no dangling pointers). Complements Rule 8 (items↔tuples); this check ensures nothing stated in the request is missing. The task file, not the chat, is the record.</step_by_step>
Follow the project's accepted task format; AGENTS.md says where that format is defined. Frontmatter MUST extend that template with date, status, tags, related_tasks (rule 9 above).
ad81ae6
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.