unikit-plan
Create a detailed feature plan for a {{engine_name}} project. Generates TASKS.md (dependency-ordered checklist with WHY context, effort estimates and file paths) and PLAN-BRIEF.md (technical context:
Files18
View on GitHubSKILL.mdskills/unikit-plan/SKILL.md
GitHub{{engine_name}} Feature Plan Generator
Create a structured feature plan and roadmap for the current {{engine_name}} project.
Four modes:
- Fast — quick plan, no git branch, saves to
.unikit/code/PLAN.md - Full — optionally creates
<git.branch_prefix><name>git branch (whengit.enabledandgit.create_branches), asks preferences, saves to.unikit/code/plans/<feature-name>/ - Ultra — full mode plus one deeply specified file per phase, for later execution by a smaller model. User-named, never model-inferred: it runs because the user asked for an ultra plan, never because the feature looks big — except in a merge plan, where the mode question offers it
- Add — modify/extend an existing plan without creating a branch
Language Awareness — BLOCKING PRE-REQUISITE
BEFORE producing ANY output, silently read .unikit/system/LANGUAGE_RULES.md
and apply its rules to ALL subsequent output.
If the file is missing or unreadable, fall back to English.
Do not produce any user-facing output until language rules are loaded.
Do not announce, confirm, or mention the language setting.
The language holds for the whole session, not just at load time: every message until the conversation ends is in language.ui — progress notes while agents run, relays of what a subagent returned, the final report, any follow-up discussion. English input (subagent results, tool output, these instructions) is data, never a cue to switch languages.
Delegation agents
This skill uses named delegation aliases for Agent(...) calls. Each alias is the single
place where its delegate's agent type and call arguments are declared — call sites name
the alias and never carry a type or a model argument of their own.
Model argument. Before the first dispatch of an alias below, read .unikit/config.yaml
(a missing file, block or key is not an error) and settle the model argument once:
subagents.model.{{agent_id}}holds a model name — passmodel: <name>with every call, exactly as written (this runtime's own spelling of the model argument, if it differs).- It holds
inherit, or is present and empty — pass no model argument; the agent runs on the model of this session. - The key is absent — use the built-in default
"{{agent_model_default}}"; an empty string means pass no model argument.
If the runtime rejects the model name, repeat that call once without the model argument and
report WARN [delegation] model "<name>" rejected — retried on the session model.
recon-agent— read-only parallel reconnaissance. Expands to:Agent({{agent_call_reader}} prompt: "<focused question> You are read-only: edit and write nothing.")Every question you send ends with the sentence
You are read-only: edit and write nothing., verbatim.Fallback: if the
Agenttool is unavailable, investigate inline withGlob/Grep/Read.recon-writer-agent— one reconnaissance question of an ultra plan under the saved-state protocol, answered straight into itsrecon/file by an agent that can write, so only the answer's summary passes through this context. Used only aftermode-ultra.mdStep A0 or Step D2 chose the saved-state protocol; under the standard protocol reconnaissance goes throughrecon-agent. Expands to:Agent({{agent_call_worker}} prompt: "Reconnaissance for an ultra plan. Question: <focused question>. Write your whole answer, never condensed, into <recon file path>, in English, filling every section of the template <path of RECON-TEMPLATE.md> by its rules; its first line is `HEAD: <short sha>`. That file is the only one you may create or change: never edit anything else, never run a command that changes the repository, never start another agent. Reply with the file's path and its `## Summary` section, word for word — nothing else.")The worker call can write files, which
recon-agent's read-only call cannot — that is why this alias exists. This agent can edit files and only its prompt bounds it — hence the change guard inultra-stateful.md→## Recon files.Fallback: if the call fails, the runtime has no agent tool, or the agent returns without its file, ask that question through
recon-agent— it only reads and cannot save a file — then, the moment the answer returns and before anything else, createrecon/if it is missing and write the answer into the file yourself, whole, in the form ofRECON-TEMPLATE.md; takependingoff only once the file is on disk (ultra-stateful.md→## Recon files→ Without a writing agent).
Input
$ARGUMENTS — optional keyword full, fast, ultra, or add, optional --base <branch> flag, followed by free-form description in any language. The mode may also be named inside that free-form text rather than as a leading token.
Parsing rules:
- Extract
--base <branch>if present anywhere in arguments → store asbase_branch, remove from text - If
--listis present → list mode, show all plans and STOP - If the first word (after flag removal) is
full→ full mode, remaining text is the feature description - If the first word is
fast→ fast mode, remaining text is the feature description - If the first word is
ultra, or the text asks for an ultra plan in any phrasing or language — "ultra plan", "ultraplan", "ultra-plan", "ультраплан", "make an ultra plan for the inventory" → ultra mode; strip the ultra wording and the verb that carried it, the remainder is the feature description 5a. If the text left after an optional leadingultrais exactly the name of a folder under.unikit/code/plans/that holds.planning/STATE.mdand no manifest.unikit/code/plans/<name>/PLAN.md, this is a continuation: load{{skills_dir}}/{{self_name}}/references/mode-ultra.mdand{{skills_dir}}/{{self_name}}/references/ultra-stateful.md, and follow## Resumethere; Steps 0.1-4 do not run again. - If the first word is
add→ add mode, remaining text is what to add/change in the existing plan - Otherwise → ask interactively, entire text is the description
Ultra is user-named, never model-inferred. Rule 5 recognises the request wherever it sits in the sentence, but it must be a request: ultra is never offered in Step 0.2 (except in a merge plan, where the mode question offers it) and never chosen because the feature looks large, spans many files, or seems hard — size is not a request. Wording that only asks for care — "a deep plan", "plan this thoroughly", "a detailed plan" — is not ultra; fall through to rule 7 and ask.
A merge request — the user asks to merge a named branch into the current one (not a rebase, a cherry-pick or a merge by pull request number): load {{skills_dir}}/{{self_name}}/references/merge-plan.md and follow it. It owns the trigger, the analysis, the mode question — fast, full or ultra (add does not apply to a merge) — and the shape of the plan; a branch that is not named is asked for there. An ordinary plan does not read that file.
--base <branch> — the branch to create the feature branch from (full mode only). --base flag overrides git.base_branch from config. Priority: --base flag > git.base_branch from .unikit/config.yaml > fallback main.
Workflow
Step 0: Parse Mode & Select Mode
Initialize flags: research_pre_linked = false, research_linked = false, design_linked = false.
If mode is --list → load {{skills_dir}}/{{self_name}}/references/mode-list.md and follow it (it STOPs; Steps 0.1–7 do not run).
If mode is add → run Step 0.5 (Bootstrap Context), then load {{skills_dir}}/{{self_name}}/references/mode-add.md and follow it (it STOPs; never creates a branch).
Step 0.1: Resolve Git State
Do not auto-run git init. Read the git keys from .unikit/config.yaml:
git.enabled: false→ no branch commands; a full-mode plan goes to.unikit/code/plans/<slug>/git.base_branch→ the target branch for diffs and merge guidance (default: the detected branch ormain)git.create_branches: false→ full mode still writes the rich plan, on the current branchgit.pull_requests.checkpoints— read once by the mode file's#### PR checkpoints;git.pull_requests.max_levelis never read by the planner.
git.enabled: true outside a git work tree → warn that git-aware actions are unavailable until the repository is initialized, and continue as with git.enabled: false.
Step 0.2: Resolve Feature Description
If the user provided a feature description → use it and skip this step.
If the description is empty (user only typed a mode keyword like full or fast, or no arguments at all):
Check session context — look in the current conversation history for results of
/unikit-explore. If found, use the exploration topic and findings as the feature description and context.Check recent researches — if no session context, read
.unikit/code/researches/INDEX.md(if it exists). The index is sorted newest-first. Take the first entry whoseLifecycleisactive— a record carrying noLifecycleline counts asactive— and ask:AskUserQuestion: Found recent research: "<Title>" (<Created>) Use as basis for planning? Options: 1. Yes — use this research 2. No — I'll describe the feature myselfBased on choice:
- Yes → use research title/summary as description, mark
research_pre_linked = true(skip research matching in Step 2) - No → proceed to ask user for description (step 3 below)
<Created>is the displayed field — never substituteUpdatedfor it. A record with noCreatedis shown as"<Title>" (date unknown), never with empty brackets.- Yes → use research title/summary as description, mark
No context available — if neither session context nor researches exist, ask the user for a description:
AskUserQuestion: Describe the feature you want to plan.
If no mode keyword was found by the Step 0 parsing rules, ask one question, adding the description question when the description is still missing:
AskUserQuestion:
1. Describe the feature you want to plan. ← only when the description is still missing
2. Which planning mode?
a. Full (recommended) — creates git branch, codebase reconnaissance, full plan
b. Fast — quick plan without a branch
Ultra is deliberately absent from this question — see the parsing rules in Step 0 — except in a merge plan, where the mode question offers it.
For a merge request the mode question is the one in merge-plan.md; ultra appears there as the third option.
Step 0.5: Bootstrap Context (MANDATORY — all modes except List)
Silently load the project knowledge base before any exploration — do not narrate the loading.
Required reads (always, every time, in parallel)
.unikit/DESCRIPTION.md— project description, tech stack, constraints.unikit/ARCHITECTURE.md— architecture decisions, folder structure, module rules, dependency directionsRead
.unikit/memory/code/RULES_INDEX.md. Load rules:- RULES.md: ALWAYS read
.unikit/RULES.mdfirst (highest priority). Rule topics: only the root here — its topic files load per phase in Step 5 (Rule refresh per phase), or earlier when the Step 4 exploration needs one. - Core: read the Core table. For EACH row where Required By =
allor contains{{self_name}}— read that file from.unikit/memory/code/core/using the Read tool. Do NOT skip any matching row. Always re-read at skill start, never rely on prior conversation cache - Stack: load dynamically when the current task or context matches "Load When" column, or when a need arises during work
- RULES.md: ALWAYS read
.unikit/skill-context/{{self_name}}/SKILL.md— project-specific skill overrides (if exists)Read
{{skills_dir}}/{{self_name}}/references/ENGINE_RULES.md— engine planning vocabulary: kind → concept (§1), language & layout (§2), when to writeEditor:(§3), engine planning pitfalls (§4), out of scope (§5), direct-edit feasibility (§6). Setengine_rules_loaded = true.If the file is absent — a normal path, not an error (an engine whose planning vocabulary has not shipped yet): set
engine_rules_loaded = false. Every step that writes anEditor:field, theEditor taskssetting or a confirmation line reads that flag (Step 5, Step 6,mode-full.md,mode-fast.md,mode-add.md).addmode runs this step too.Read
.unikit/system/engine-mcp/INDEX.md— the base section only: the delivery stamp plus every section except the## Checktable — the exceptions that shape planning: where a commit boundary falls, what may never run in parallel, how the work splits into phases. Setmcp_index_loaded = true.Do not read the
## Checktable — it is the executors', grepped per task by area.If the file is absent — a normal path: set
mcp_index_loaded = false, print exactly one line, and continue with the same rights:MCP rules: no INDEX.md — no known exceptions for this server, rights unchangedAbsence never switches a task to
⏸️ MANUAL, never suppresses anEditor:field, and never disables the engine MCP (.unikit/system/dev-principles.md→ A9 · no rules ≠ no rights)..unikit/config.yaml→testing.plan.checkpoints— the test-run placement policy, resolved per mode bymode-full.md/mode-fast.md/mode-ultra.md; here it is only read. File or key absent → the mode file's default, silently.
Patches (learning from past fixes)
If .unikit/code/patches/ exists:
- Use
Globto find all*.mdfiles - Read each patch to learn from past fixes
- Account for known pitfalls when designing the plan — tasks should avoid patterns that caused bugs
Design context (game-design module — optional)
.unikit/gamedesign/GD-IDS.yaml exists → it MUST be version: 2. On version: 1 do NOT read it: emit ERROR [design] GD-IDS.yaml is version 1 (pre-v2 layout); design grounding unavailable until the workspace is upgraded via /unikit-gd-spec, set design_linked = false, and plan code-side only. On version: 2 set design_linked = true — Step 4.5 reads the design once the feature scope is clear; nothing is read here. Absent → design_linked = false, and every design step is skipped.
Planning only reads design; it never writes to .unikit/gamedesign/ — design changes go through the /unikit-gd-* skills.
Remember loaded rule file paths — pass them to Explore tasks in Step 4.
Step 1: Determine Feature Name and Folder
- Read the description and understand the feature intent.
- Invent a short English name for the feature — maximum 3-4 words, lowercase, hyphenated.
Examples:
mini-games-editor,customer-dialogue,item-appraisal-system,wallet-ui.
Fast mode → skip steps 3-5 below. The plan goes to .unikit/code/PLAN.md (flat file, no folder).
Full and ultra modes → continue:
Get today's date (
YYYY-MM-DD) — the value of the manifest'sCreated:andUpdated:fields (Plan Manifest Template in{{skills_dir}}/{{self_name}}/references/TASK-FORMAT.md).The folder name is the feature name from step 2 —
<feature-name>, no date and no separator prefix (e.g.item-appraisal-system).Collision check — a slug that already exists never resolves itself silently. Scan
.unikit/code/plans/and.unikit/code/archive/plans/for a folder matching the new name in any of the three formats that coexist on disk: exact<name>, a folder ending in_<name>(theYYYY-MM-DD_era), and a folder ending in-<name>whose name starts with three digits (the olderDDD-era).- No match → create
plans/<feature-name>/and continue. - A match in
.unikit/code/plans/that has no manifest.unikit/code/plans/<name>/PLAN.md→ a plan that was not finished:
AskUserQuestion: A plan named "<name>" was not finished (.unikit/code/plans/<name>/ has no manifest). Options: 1. Continue it 2. Start over 3. Choose another name- "Continue it" is offered only when the folder holds
.planning/STATE.md; without it (an interrupted standard protocol) the option is absent. - "Continue it" → load
{{skills_dir}}/{{self_name}}/references/mode-ultra.mdand{{skills_dir}}/{{self_name}}/references/ultra-stateful.md, and follow## Resumethere. - "Start over" →
node {{skills_dir}}/{{self_name}}/scripts/plan-bundle.mjs discard .unikit/code/plans/<name>, printINFO [plan] <name>: unfinished plan removed — starting over, create the folder again and continue. A non-zero exit → stop with itsERRORline (code 3: the folder holds a finished plan).nodecannot run → print the folder's path, ask the user to remove it, and stop. - "Choose another name" → the folder stays; repeat this check on the new slug.
- A match in
.unikit/code/plans/→ ask, and do not decide it yourself:
AskUserQuestion: A plan named "<name>" already exists (<matched folder>). Options: 1. Refine the existing plan — hand over to add mode 2. Choose another name — I'll enter a different slug- "Refine the existing plan" → hand control to the
addbody ({{skills_dir}}/{{self_name}}/references/mode-add.md) on the matched folder and printINFO [plan] <name> exists — switching to add mode. - "Choose another name" → take the user's slug and repeat this check on it. On success print
INFO [plan] creating <new-name>. - A match only in
.unikit/code/archive/plans/→ the name belongs to an archived plan. An archived plan is not refined in place, and a second folder of that name would collide when this one is archived:
AskUserQuestion: A plan named "<name>" is archived (<matched folder>). Options: 1. Choose another name — I'll enter a different slug 2. Cancel planning- "Choose another name" → as above. "Cancel planning" → STOP.
Appending an automatic suffix (
-2,-v2, a date) is forbidden.- No match → create
Step 1.5: Load the Mode Body
Load only the selected mode's body — never all of them at once:
- Full mode → load
{{skills_dir}}/{{self_name}}/references/mode-full.md, run its additional steps (git branch, recon, preferences), then continue to the Shared Steps below. - Fast mode → load
{{skills_dir}}/{{self_name}}/references/mode-fast.md, run its preferences step, then continue to the Shared Steps below. - Ultra mode → load
{{skills_dir}}/{{self_name}}/references/mode-ultra.md, run its additional steps A0-C (writing protocol, git branch, recon, preferences) — Step A0 first and on its own, before any agent — then continue to the Shared Steps below. Steps D-H of that body run later — they refine Step 5 and Step 6 of the shared workflow, so do not run them here.
Shared Steps (all planning modes)
Step 2: Check for Related Researches
The research-link contract — read at the first link, and only then. The moment this step links its first research — through the research_pre_linked shortcut below or through point 7 — read .unikit/system/research-link.md. For each research linked here, compute its Summary SHA256 over the ## Active Summary just read, by ## Computing the hash, and keep the digest for Step 5 (## Writing an entry).
If .unikit/system/research-link.md is missing or unreadable, do not block: record no Summary SHA256 and check none — print WARN [research-drift]: research-link contract missing — drift detection off for this run; run unikit-ai update once, and continue.
If research_pre_linked = true (the user already confirmed a research in Step 0.2) → read it as point 7 below does, mark research_linked = true, store its path for ## Based on, and skip to Step 3.
Before exploring code, check if /unikit-explore has produced relevant researches.
Read
.unikit/code/researches/INDEX.md- If the file doesn't exist — skip this step entirely, proceed to Step 3.
Read
workflow.research_relevance_daysfrom.unikit/config.yaml(default:7).Filter entries by three criteria:
Updatedis withinresearch_relevance_daysfrom today. The age key isUpdated, neverCreated.Statusiscompleted(skipin-progressandneeds-follow-up). The field name and its three values are fixed.Lifecycleis notsuperseded. A record carrying noLifecycleline counts asactive.
Log the drop — one line, always, including when nothing was dropped:
INFO [research] index: <N> entries, <K> shown (<a> older than <days>d, <b> not completed, <c> superseded)A record with no
Updatedis not guessed at from another field. It is excluded, and it is named:WARN [research] <folder>: index row has no Updated — excluded; run /unikit-explore to redraw the indexMatch: compare each surviving entry's
Summaryagainst the feature description. Select entries that are contextually relevant to the feature being planned.If 0 relevant researches found — proceed to Step 3 silently. Mark
research_linked = false.If 1 or more relevant researches found — ask the user:
AskUserQuestion: Found related researches:
1. <Title> (<Date>) — <Summary>
2. <Title> (<Date>) — <Summary>
Options:
1. Use all listed researches
2. Let me pick which ones (specify numbers)
3. Skip all — plan from scratch
Based on choice:
- Use all → load all listed researches as planning context
- Let me pick → wait for user to specify numbers, load only selected
- Skip all → proceed without research context, mark
research_linked = false
Highlight the most relevant entries in the question text (e.g., "Recommended: #1, #3").
- For each selected research:
- Read its
RESEARCH.md—## Active Summaryas the declared input,## Findingsand the adaptive artifacts for the rationale; readCONTRACTS.mdwhen it exists, andSOURCE.mdfor the dialogue - Use as planning context and as starting point for Phase B deep-dive — reduces scope of Explore tasks in Step 4
- Mark
research_linked = trueand store the research path for## Based on
- Read its
Step 3: Analyze Requirements
Before exploring code, analyze the feature description for completeness.
If requirements are clear — proceed to Step 4.
If requirements are ambiguous or incomplete — ask clarifying questions:
Before planning, a few things need clarification:
1. [Specific question about feature scope]
2. [Question about implementation approach]
3. [Question about edge cases]
Wait for answers before proceeding. Do not plan based on assumptions when the description is ambiguous — ask.
Step 4: Explore the Codebase & Technical Design
This is the most critical step. The goal is to produce a deep technical understanding sufficient
for writing actionable tasks with meaningful WHY context and for generating a ## Technical Context that reflects the actual codebase state at planning time.
You loaded the project rules in Step 0.5 (Bootstrap). Now use that knowledge to write precise prompts for Explore tasks and to synthesize their results against project conventions.
Ultra mode, saved-state protocol: reconnaissance goes through recon-writer-agent — each answer lands in its own recon/<topic>.md, whole and never condensed (written by the agent itself, or by this session before anything else when the runtime has no writing agent), and later steps work from the file's ## Summary (ultra-stateful.md → ## Recon files).
Phase A: Exploration (Explore tasks)
Launch 2-4 Explore tasks in parallel, each with a specific focus. Each task MUST receive references to project documentation files so it operates with project knowledge.
Every task gets the same prompt shape; only the focus and the rule paths change:
recon-agent(prompt:
"Before analysis, read these project docs:
- .unikit/ARCHITECTURE.md
- [core rule paths relevant to <focus> — from the RULES_INDEX.md Core table]
- [stack rule paths, when <focus> involves a specific framework]
Then: <focus>. Thoroughness: medium.")
Foci: (1) architecture & affected modules — the files and modules related to [feature domain], the directory structure, the entry points and how the modules interact; (2) existing patterns — similar functionality already implemented, and its patterns (services, controllers, models, DI bindings); (3) dependencies & integration points, when needed — everything that imports or uses [module/service], its integration points and side effects. In full mode, name the files and classes Step B found (mode-full.md).
After the tasks return, synthesize: files to create/modify, patterns to follow, dependencies, risks.
Code analysis in this skill is read-only: never /unikit-devcontext, never a code-writing delegate.
Phase B: Technical Deep-Dive (Explore agent)
Always runs — produces the plan's ## Technical Context content based on the current codebase state.
When research_linked = true: use the research's ## Active Summary — and CONTRACTS.md when it exists — as a starting point for the deep-dive. They provide initial constraints, interfaces, and patterns; Phase B verifies them against the actual code and updates/extends as needed. This ensures the plan's own context is fresh and accurate even if the codebase changed since the research was conducted.
When research_linked = false: perform full technical analysis from scratch.
Launch an Explore task for detailed technical analysis using findings from Phase A. Include doc references (ARCHITECTURE.md + all core/stack rules from Bootstrap). The task should:
- Read source code of existing similar features found in Phase A
- Extract interface signatures, constructor dependencies, DI bindings from installers
- Identify patterns the new feature must follow (naming, structure, registration)
- Find constraints — what is MUST vs FORBIDDEN based on existing code
Return format: structured report matching the ## Technical Context section of the Plan Manifest Template in {{skills_dir}}/{{self_name}}/references/TASK-FORMAT.md. Do not guess — base on actual code read. Thoroughness: very thorough.
Fallback: If Agent tool is unavailable, perform analysis inline using Read.
Synthesize the task's findings with Bootstrap rules to produce the plan's ## Technical Context content.
Ultra depth gate (ultra mode only)
In ultra, reconnaissance is not finished until the plan has code-level evidence for every phase:
- relevant existing paths and symbols
- callers/consumers and side effects
- exact integration and configuration points
- existing tests, fixtures, commands, logging, migration, and documentation patterns
It feeds each phase file's ## Current-Code Evidence table and its ### Implementation Steps; thin reconnaissance is rejected by {{skills_dir}}/{{self_name}}/references/ULTRA-PLAN-FORMAT.md → ## Required Detail Gate.
Do not paste entire source files into phase plans. Cite only the evidence that makes the implementation steps deterministic.
When evidence for a phase cannot be gathered, the decision goes into the manifest's
## Open Questions as a blocking question — it is never hidden behind a vague step.
Phase C: Additional context
OPTIONAL (recommended): Read .unikit/ROADMAP.md if it exists:
- Use it to link this plan to a specific milestone (when applicable)
- This reduces ambiguity in
/unikit-implementmilestone completion and/unikit-verifyroadmap gates
Step 4.5: Resolve Design Context (game-design module)
Only when design_linked = true: load {{skills_dir}}/{{self_name}}/references/design-context.md and follow it. It reads the shared design-read contract, resolves the door (a system, a flow or a content type), produces the ## Design snapshot plus the optional ## Flow Context / ## Content Context, and returns here for Step 5. When design_linked = false the body is never loaded. Read only — never write to .unikit/gamedesign/.
Step 4.6: Read the Catalog Negatively (only when the plan carries editor work)
Gate. Runs only when Step 4 established that the feature touches the editor's serialized state and an engine MCP is configured (MCP server {{engine_mcp_tool}} present in {{settings_file}}). A pure-code plan skips this step and makes no call at all.
Whatever engine-MCP grants this skill's frontmatter carries are read-only discovery and nothing else — that is the whole of the planner's contact with the engine MCP. Use them once, to answer exactly two questions:
- Which kinds of editor work have no route here at all — so the plan does not schedule an intent this project cannot carry out. The six-word
kindvocabulary is in.unikit/system/dev-principles.md→ A8. - Which evidence classes are reachable — so no acceptance criterion is written against evidence nobody can produce. The claim-class → evidence-class lattice is A2 of the same file.
That is the entire question — not which tool does it, not how it is called, not a strategy — and neither the question nor its answer is written into the plan.
What the outcome may change, and what it may not:
- a kind of work with no route → do not schedule it as engine-MCP work: express the change in a form that has a route, or keep the task and name the missing capability in its
WHY:. Do not pre-write⏸️ MANUALinto the task — it is a runtime verdict (A9); - an evidence class that is not reachable → rewrite the acceptance criterion against a class that is, or say plainly in
## Overviewthat it cannot be closed here. Never silently downgrade it to the cheapest observation available.
The planner never: calls anything that changes state, reads the ## Check table, reads .unikit/MCP-RECHECK-NOTES.md, or opens Context7.
No engine MCP configured, or discovery yields nothing → skip. Plan against the base principles, unchanged.
Step 5: Create the Plan
- Fast and full — use the canonical templates from
{{skills_dir}}/{{self_name}}/references/TASK-FORMAT.md. - Ultra — the canonical source of templates and integrity checks is
{{skills_dir}}/{{self_name}}/references/ULTRA-PLAN-FORMAT.mdand nothing else.TASK-FORMAT.mddescribes the single-file format and applies only where the bundle specification explicitly points back at it.
Plan file path:
- Fast mode →
.unikit/code/PLAN.md(single flat file) - Full mode →
.unikit/code/plans/<feature-name>/PLAN.md(single manifest in a folder) - Ultra mode →
.unikit/code/plans/<feature-name>/PLAN.md(manifest) +phase-NN-<slug>.md— written straight into that folder by either writing protocol (mode-ultra.mdStep F)
In ultra, Step 5 is carried out by mode-ultra.md Steps D-G — the section list below still
applies to the manifest, minus the task-level subsections of ## Technical Context.
Plan Sections (all planning modes)
Header timestamps —
Created:andUpdated:directly under the H1, both today's date from Step 1 (Bash(date *)). Their shape and the rule for movingUpdated::{{skills_dir}}/{{self_name}}/references/TASK-FORMAT.md→ Plan Manifest Template; ultra writes the same two lines under its own H1. Full and ultra also writePlanned at: <short sha>(git rev-parse --short HEAD) underUpdated:— only in a git work tree with at least one commit; it never moves (TASK-FORMAT.md→ Plan Manifest Template).## Overview— 3-5 sentences: WHAT is being built, WHY it's needed, WHAT GOAL it serves.## Based on— ifresearch_linked = true, one entry per linked research in the form.unikit/system/research-link.md→## The entry, carrying theSummary SHA256computed back in Step 2 (a research whose digest could not be computed there is written without that line —## Writing an entry). The contract was already read in Step 2; it is not re-read here. After all research entries, add "see the## Technical Contextsection below". If no research: "see the## Technical Contextsection below".## Design,## Flow Context,## Content Context(game-design module) — the snapshots Step 4.5 prepared, placed in this order directly after## Based on, each omitted when it was not produced (always, for a pure-code plan). What each one carries — theSYS-id, its version and the cited Acceptance Criteria; theFLOW-id, its wiring mode andGOALsteps; theCT-id, itsscaleandCT.fieldsschema — isdesign-context.md's.## Designfeeds/unikit-verify'simplemented_versionwriteback;## Flow Contextand## Content Contexthave none.## Settings— User preferences (/unikit-implementreads this):Testing: yes/no— whether tests are written at all: tests for logic and system values (dev-principles.mditem 5)Test checkpoints: task | phase | plan— where the test-checkpoint tasks stand; resolved in the mode file, omitted whenTesting: no,taskonly in ultra.Docs: yes/no— whether to show documentation checkpoint (invokes/unikit-docs)Editor tasks: mcp | manual | direct— read by/unikit-implement: how tasks carrying anEditor:line are carried out. Resolved inmode-full.md/mode-fast.md. Omit this line entirely whenengine_rules_loaded = false.PR checkpoints: yes— only when this plan carries at least one PR checkpoint task (pr_checkpoints = truein the mode file and two or more modules); otherwise the line is absent.
## Roadmap Linkage(optional, only if.unikit/ROADMAP.mdexists):- If linked:
Milestone: "<name>"andRationale: "<why>" - If skipped:
Milestone: "none"andRationale: "Skipped by user"
- If linked:
## Checklist— phases with tasks. Every task MUST include description,WHY:line,Files:line. The WHY line answers: "what breaks or is missing if we skip this task?"When to write
Editor:— the criterion is neutral: the change touches the serialized state of the editor, not source text. Editing a plain text or config file stays inFiles:. The concrete signals for the active engine are listed in{{skills_dir}}/{{self_name}}/references/ENGINE_RULES.md§3 — read them from there, do not restate them here: they are engine facts (a scene, a prefab, a blueprint are not the same concept across engines), and a second inline copy diverges from §3 on its first edit. Form:Editor: [kind] <container> → <target> : <action>, one line per target, placed afterFiles:(grammar and the 6 kinds:references/TASK-FORMAT.md→### Editor task grammar). Pure code tasks omit the field. Whenengine_rules_loaded = falsethe field is not generated at all.Test-checkpoint task. A run point is a separate checklist task carrying the line
Test checkpoint: <coverage>in the positionFiles:occupies. The rest — noFiles:, where a checkpoint is worth placing, a phase left without one, the closingTest checkpoint: planunderTesting: yes, no list of suites, no run commands elsewhere — is{{skills_dir}}/{{self_name}}/references/TASK-FORMAT.md→### Test checkpoint task grammar; do not restate it here.Modules (full and ultra). Group the phases into modules by the criteria of
{{skills_dir}}/{{self_name}}/references/TASK-FORMAT.md→### Modules section— always, whether or not PR checkpoints are on. Write## Modulesdirectly after## Roadmap Linkage— above## Checklistin full, before## Architecture and Decisionsin ultra (the ultra manifest template) — when there are two or more modules, or one longer than four phases; a module longer than four phases carrieswhy long:. Do not restate the criteria here.PR checkpoint task. When
pr_checkpoints = trueand there are two or more modules, the last task of every module but the last is a PR checkpoint task carryingPR checkpoint: <module name> → <base>in the positionFiles:occupies; underTesting: yesandTest checkpoints: phase | taskthe module's test-checkpoint task stands right before it. Grammar, labels and placement:TASK-FORMAT.md→### PR checkpoint task grammar.Rule refresh per phase. Before you draft the tasks of each phase — in ultra, before you write each phase file (
mode-ultra.mdStep F) — match the phase's name and the tasks you are about to write against theLoad whencolumn of the## Topicstable in.unikit/RULES.mdand the Stack table of.unikit/memory/code/RULES_INDEX.md. Read only the topic files and stack rules not loaded yet — keep their paths inloaded_rules, the same delta/unikit-implementStep 3.0 computes; when unsure, load. A listed topic file that is missing →WARN [rules] topic file missing: .unikit/rules/<slug>.md, continue. Nothing is re-read between the tasks of one phase.## Commit Plan— when 5+ tasks, checkpoints every 3-5 tasks, each mirrored by a decorative<!-- Commit checkpoint: tasks X-Y -->marker in## Checklist;/unikit-implementdoes not parse it (TASK-FORMAT.md). A range never crosses a module boundary.## MCP Findings— emitted empty (heading and header row) whenever the plan carries at least oneEditor:task, omitted otherwise; filled by the executor. Contract:TASK-FORMAT.md→### MCP findings section.## Rule Candidates— emitted always, and empty (heading and header row). Contract:TASK-FORMAT.md→### Rule candidates section.## Test Runs— emitted empty underTesting: yes(the heading alone), omitted underTesting: no. Contract:TASK-FORMAT.md→### Test runs section.## Dependency Graph— phase dependencies in ASCII.
Guard B — a phase carrying an Editor: task is serialized alone in its execution layer.
The unit of parallelism downstream is the phase. /unikit-implement and unikit-implement-coordinator build the phase graph from the **Dependencies:** lines, compute execution layers (Layer 0 = phases with no dependencies; Layer N = phases whose dependencies all sit in layers 0..N-1) and run every phase of one layer concurrently, while the tasks inside a phase always run in order.
So this is a rule about layers, never about tasks: two Editor: tasks in one phase are already sequential, and splitting them into two phases to "separate" them creates exactly the collision it was meant to prevent.
How to write it. When a phase carries at least one Editor: line, write the dependency lines so that the phase is the only member of its layer:
- the editor phase depends on every phase that must precede it, so nothing from the earlier layers lands beside it;
- every remaining phase depends on the editor phase, directly or transitively, so nothing from the later ones does either.
Then check the graph you actually wrote, not the intent: walk the layers the way the coordinator does and confirm that every layer holding an editor phase has exactly one member. If serialization makes the plan awkward, move the editor work into a phase of its own rather than relaxing the rule.
Module barrier. A module boundary is a layer barrier — the closing phase of a module depends on every other phase of it, and every phase of the next module depends on that closing phase (TASK-FORMAT.md → ### Modules section). Write it into the **Dependencies:** lines together with Guard B and check the layers once for both.
## Total Estimated Effort— sum of all phases.## Technical Context— always included. Nine subsections (CONTEXT,CONSTRAINTS,INTERFACES,KEY PATTERNS,DEPENDENCY GRAPH,FILES,EDITOR TARGETS,DI BINDINGS,OUT OF SCOPE);EDITOR TARGETSis omitted entirely when the plan carries noEditor:task. In ultra the manifest keeps only the cross-phase part and the rest goes into the phase files — the distribution rule is{{skills_dir}}/{{self_name}}/references/ULTRA-PLAN-FORMAT.md. Content comes from Step 4 Phase B, synthesized with the Bootstrap rules: base it on the actual code, do not invent. Template:{{skills_dir}}/{{self_name}}/references/TASK-FORMAT.md.
Self-check: every interface the tasks name is in ### INTERFACES with its full {{engine_code_language}} signature, every Editor: target has its ### EDITOR TARGETS row (Kind / Container / Target / Change), and the DI bindings follow references/ENGINE_RULES.md §2. In fast and full the check runs inside the one plan file; in ultra both subsections live in the phase file of the task that owns them, and the check runs between the manifest checklist and that file — never pull them back into the manifest.
## Open Questions(optional) — uncertainties the planning pass could not close, one line each; the last section of the manifest (TASK-FORMAT.md).unikit-plan-polisherwrites its leftovers here; omit the section when there are none.
Step 6: Confirm with User
Show the user:
- The plan path —
.unikit/code/PLAN.md(fast), or.unikit/code/plans/<feature-name>/PLAN.md(full, ultra), plus the research reference if linked - Full and ultra: the git branch name when
branch_created = true, otherwise the current branch name - A brief summary of the phases and the total estimated effort
- The modules —
N modules, M PR checkpoints(orone module) — one line - When
engine_rules_loaded = false— the lineEngine rules: ENGINE_RULES.md not found, Editor: fields skipped - The reminder: "To start implementation, run:
/unikit-implement" - Ask whether to adjust anything
Merge plan: the closing message is the one {{skills_dir}}/{{self_name}}/references/merge-plan.md describes — it names the command that runs the plan.
Ultra mode: the items above plus mode-ultra.md Step H (phase-file count, task count, integrity result, and the not-implementation-ready line when blocking open questions exist). Under the saved-state protocol its .planning/ folder is already gone (plan-bundle.mjs finalize).
Step 7: Context Cleanup
Suggest the user to free up context space if needed: /clear (full reset) or /compact (compress history).
Task Description Requirements
Beyond Step 5 item 5 and references/TASK-FORMAT.md: name a dependency on another task's output when the phase order does not make it obvious; a simple task (rename, delete, move) may carry its paths in the description instead of a Files: line. A task needs a concrete deliverable, and its WHY: must not restate it.
Important Rules
- NO report tasks — don't create summary/report tasks at the end of a plan
- Right granularity — not too big (overwhelming), not too small (noise). A task should be completable in one focused session
- Dependencies matter — order tasks so they can be done sequentially without blockers
- Respect module boundaries — follow the dependency rules of
.unikit/ARCHITECTURE.md; never invent a direction it does not state - A plan is intent, not inventory — no tool name ever reaches it. Names live in the live catalog and in the
evidencecolumn of a findings row, and nowhere else. The planner never lifts an obligation on the executor's behalf — no pre-declared gate, no "this server cannot do X", no⏸️ MANUALwritten in advance