# Unikit Plan

> Create an implementation plan for a feature — a dependency-ordered, actionable task list for the project. Has four modes: fast (a quick single-pass plan), full (a richer plan that can also create a git branch), ultra (a multi-file bundle — a manifest plus one deeply specified file per phase — for execution by a smaller model), and add (extend an existing plan with more tasks). Pick the mode from the user's wording: "full plan" runs full; "quick plan" or "fast plan" runs fast; "ultra plan", "ultraplan" or "ultra-plan" runs ultra; a plain "create a plan" with no qualifier defaults to fast; "add to the plan" or "extend the plan" runs add. Use whenever the user wants to plan a feature or task, e.g. "create a plan", "create a full plan", "create a quick plan", "run an ultra plan for the inventory system", "plan this feature", "add this to the plan", "extend the plan", "add a phase to the plan". Ultra runs only when the user names it — never because the feature looks large.

- Skill: `nintendadev/unikit-plan` (Agent Skill, multi-file: 9 files)
- Install (CLI): `npx skillmds@latest add nintendadev/unikit-plan`
- Raw SKILL.md: https://api.skillmd.com/api/skills/nintendadev/unikit-plan/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: NintendaDev (https://skillmd.com/u/nintendadev)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/nintendadev/unikit-plan

---


# {{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 (when `git.enabled` and `git.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
- **Add** — modify/extend an existing plan without creating a branch

**Output artifacts by mode:**

**Fast mode** → single flat file `.unikit/code/PLAN.md`:
- **`.unikit/code/PLAN.md`** — the single manifest: overview, settings, checklist with WHY context per task, effort estimates, file paths, commit plan, dependency graph, and the `## Technical Context` section (constraints, interfaces, key patterns, files, editor targets, DI bindings) based on the codebase state at planning time.
- Temporary plan for quick work — `/unikit-implement` may offer deletion after completion.

**Full mode** → folder `.unikit/code/plans/<feature-name>/`:
- **`.unikit/code/plans/<folder>/PLAN.md`** — the single manifest: overview, settings, checklist with WHY context per task, effort estimates, file paths, commit plan, dependency graph, and the `## Technical Context` section (constraints, interfaces, key patterns, files, editor targets, DI bindings) based on the codebase state at planning time.

**Ultra mode** → the same folder, additively:
- **`.unikit/code/plans/<folder>/PLAN.md`** — the same manifest, carrying the mode marker plus `## Phase Index` and `## Cross-Phase Dependencies`, with `## Technical Context` reduced to its cross-phase part.
- **`phase-NN-<slug>.md`** — one file per phase, holding the task-scoped detail. The canonical shape of both is `{{skills_dir}}/{{self_name}}/references/ULTRA-PLAN-FORMAT.md`.

When a research is linked (from `/unikit-explore`), the plan references it via `## Based on` using the Research Reference Format below. The research's `## Active Summary` is used as **input** for generating the plan's own `## Technical Context`, not as a replacement — the plan's section reflects the actual codebase state at planning time and supersedes the research summary.

### Research Reference Format

Standard block for `## Based on` when linking to a research. Each entry records the SHA256 of the region between the `## Active Summary` markers of the research's `RESEARCH.md`, as it was at linking time. `/unikit-improve`, `/unikit-implement` and `/unikit-verify` recompute it to detect that the research actually changed — a content signal, not a clock comparison. The plan does **not** copy the summary: the plan's own `## Technical Context` is already a snapshot, and it is a better one because it was checked against the current code.

```
### <slug>
- **Summary SHA256**: <64 hex chars>
- `RESEARCH.md` — the manifest; its `## Active Summary` is the declared input
- `CONTRACTS.md` — interfaces, patterns, files, DI bindings (include only if the file exists)
- `SOURCE.md` — original exploration dialogue (include only if the file exists)
```

Full paths are resolved from `.unikit/code/researches/<slug>/`. Example:

```
### customer-items-on-scene
- **Summary SHA256**: 9f2c1d4e7a05b83c6e1f0a94d27b5c38ea6417d9b0c25f83a1e46d7c92b0f5a1
- `RESEARCH.md` — the manifest; its `## Active Summary` is the declared input
- `CONTRACTS.md` — interfaces, patterns, files, DI bindings
- `SOURCE.md` — original exploration dialogue
```

The heading is the folder name, whatever that name is. Folders created before dateless naming keep the form `YYYY-MM-DD_name` — the on-disk migration merges a folder's contents but never renames it — so an entry reading `### 2026-03-15_customer-items-on-scene` is exactly as valid as the example above.

An entry carrying `- **Brief SHA256**: …` predates the manifest: it hashed `RESEARCH_BRIEF.md`, the retired brief field, and it is never recomputed against the summary — the three readers report `drift unknown` and `/unikit-improve` Step 5.5 replaces it on an accepted re-link.

**What is hashed: the bytes between the `## Active Summary` markers of `RESEARCH.md`, and nothing else.**

The rule is unchanged — hash the requirements, never the log. What changed is where the requirements live. A manifest mixes declared requirements with an append-only session log, so it is hashed section by section, behind start/end markers. The earlier revision of this section rejected markers on the grounds that the file split already was one; the file split has been retired, because the split is what created the obligation to keep two documents in sync, and that cost was paid on every save.

| Region / file | Role | Hashed |
|---------------|------|--------|
| `RESEARCH.md` → between the `## Active Summary` markers | the planner's declared input — constraints, requirements, decisions | **yes** |
| `RESEARCH.md` → `## Findings`, `## Sessions`, the header | evidence and log; `Updated:` moves on every session | no — appending a session must **not** report drift |
| `SOURCE.md`, `CONTRACTS.md`, ADR, C4, the dependency graph | log and rationale | no — this skill reads them for context, and that is **not** a reason to hash them: any appended clarification would fire drift with the requirements unchanged |

**Computing the hash.** Normalize, then hash — never hash the raw bytes:

0. **Extract the text between `<!-- unikit:active-summary:start -->` and `<!-- unikit:active-summary:end -->`, excluding the marker lines themselves.** Both markers are matched as whole lines. If either is missing, or either occurs more than once, the region is undefined: omit the `Summary SHA256` line and print `WARN [research] <folder>: Active Summary markers missing or duplicated — drift detection disabled for this link`.
1. Strip a leading **UTF-8 BOM** if present.
2. LF line endings — strip every carriage return (`CR`, byte `0x0D`).
3. Trim trailing spaces from every line.
4. Exactly **one final newline**.
5. **Preserve line order and leading whitespace.** This is a prohibition, not a transformation: the summary carries fenced code blocks and indented list structure, and any well-meaning re-indentation breaks every hash that was ever recorded.

Feed the normalized text through **stdin, never a temp file**: `… | shasum -a 256 | awk '{print $1}'`, falling back to `sha256sum` when `shasum` is unavailable.

Rule 0 is carried out on text this skill has **already read**, not by a separate shell command. It adds no grant: `allowed-tools` is unchanged by the move from a file to a region.

HTML comments **inside** the region are kept in the hashed text; only the two marker lines are excluded, by rule 0. There is no pasted copy of the summary anywhere in the plan, so there is nothing to align the digest with. The manifest's template comments are stable text: the template ships via `unikit-ai update`, existing manifests are project files and are never re-delivered, so a template edit cannot retroactively flip an already-recorded hash.

Rejected alternative: `git hash-object` would reuse the existing `Bash(git *)` grant instead of adding two, and `.unikit/` is not gitignored so the manifest is normally tracked. It is SHA-1 with a blob header — the field says SHA256 — and it would make the check depend on git while this skill explicitly supports `git.enabled: false`.

**When no hash tool is available.** If neither `shasum` nor `sha256sum` runs, **omit the `Summary SHA256` line entirely** and print one line to the user:

```
WARN [research] no SHA256 tool available — drift detection disabled for this link
```

Do not write a placeholder and do not substitute a timestamp: an absent field is honester than a field that looks like a hash and is not one.

The same applies when the object itself is absent. A linked research with no `RESEARCH.md` — omit the line and print `WARN [research] <folder>: no RESEARCH.md`. A `RESEARCH.md` whose `## Active Summary` markers are missing or duplicated — omit the line and print the rule-0 warning above. None of these branches blocks plan creation: drift detection is a convenience, not a gate.

## 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.

<!-- unikit:agents codex -->
## Subagent Delegation — BLOCKING PRE-REQUISITE

When the workflow reaches a step that requires a subagent (`Agent`), the assistant MUST automatically spawn the
subagent if agent execution is supported by the current environment and not prohibited by higher-priority
instructions.

Only if agent execution is unavailable or blocked, the assistant MUST ask the user before proceeding with any
alternative.
<!-- unikit:end -->

## Delegation agents

This skill uses a named delegation alias for `Agent(...)` calls. The alias is the single
place where the delegate's model is declared — call sites name the alias and never carry a
model argument of their own.

<!-- unikit:agents claude -->
- **`recon-agent`** — read-only parallel reconnaissance. Expands to:

  ```
  Agent(subagent_type: Explore, model: sonnet, prompt: "<focused question>")
  ```

  `sonnet` is a tier alias, never a version — the one model value that may be written into
  UniKit. A versioned model id goes stale silently and must never replace it.

  Fallback: if the `Agent` tool is unavailable, investigate inline with `Glob`/`Grep`/`Read`.
<!-- unikit:end -->
<!-- unikit:agents !claude -->
- **`recon-agent`** — read-only parallel reconnaissance. Expands to:

  ```
  Agent(subagent_type: Explore, prompt: "<focused question>")
  ```

  No model is named: this runtime either has no dispatch-time model argument or offers only
  versioned model ids, and a versioned id goes stale silently. The runtime's own configured
  default applies.

  Fallback: if the `Agent` tool is unavailable, investigate inline with `Glob`/`Grep`/`Read`.
<!-- unikit:end -->

- **`develop-agent`** — **not used by this skill.** It belongs to the code-writing skills (`/unikit-implement`, `/unikit-fix`, `/unikit-verify`); planning reads and analyses code, it does not write it. Recorded here so the alias named in "Code Analysis & Delegation Rules" can be looked up in the one place aliases are documented.

## 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 — the user is talking, not typing a CLI.

**Parsing rules:**
1. Extract `--base <branch>` if present anywhere in arguments → store as `base_branch`, remove from text
2. If `--list` is present → list mode, show all plans and STOP
3. If the first word (after flag removal) is `full` → full mode, remaining text is the feature description
4. If the first word is `fast` → fast mode, remaining text is the feature description
5. 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
6. If the first word is `add` → add mode, remaining text is what to add/change in the existing plan
7. 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 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, because an unwanted bundle leaves the user a folder of phase files they never asked for, while a missed one costs them one word.

`--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

```
/unikit-plan full Item appraisal system                    → mode: full, base: HEAD, description: "Item appraisal system"
/unikit-plan full --base master Item appraisal system      → mode: full, base: master, description: "Item appraisal system"
/unikit-plan fast Item appraisal system                    → mode: fast, description: "Item appraisal system"
/unikit-plan ultra Item appraisal system                   → mode: ultra, base: HEAD, description: "Item appraisal system"
/unikit-plan add Add error handling phase                  → mode: add, description: "Add error handling phase"
/unikit-plan Item appraisal system                         → mode: ?, ask user
```

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`.

Resolve the current git mode from `.unikit/config.yaml`:

- `git.enabled: true` → git-aware workflow is allowed
- `git.enabled: false` → no-git workflow only
- `git.base_branch` → target branch for diffs/merge guidance (default: detected
  branch or `main`)
- `git.create_branches: true` → full mode may create a branch
- `git.create_branches: false` → full mode still creates a rich plan, but stays
  on the current branch

If `git.enabled = false`:

- Skip all branch commands
- Save full-mode plans under `.unikit/code/plans/<slug>/` (slug-based fallback)
- Treat the "create feature branch" step as unavailable

If `git.enabled = true` but the repository is not actually inside a git work tree:

- Warn the user that git-aware actions are unavailable until the repository is
  initialized
- Fall back to the same no-git behavior as above

### 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):

1. **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.

2. **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 whose `Lifecycle` is `active` — a record carrying no `Lifecycle` line counts as `active`, because records written before the field existed do not carry it — 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 myself
   ```
   Based 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, and `Updated` is never substituted for it: `Created` exists for display and for breaking ties, `Updated` drives every filter and all sorting. A record with no `Created` is shown as `"<Title>" (date unknown)` — never with empty brackets, because an empty bracket is indistinguishable from normal and hides the gap in the dialogue the same way an unlogged filter hides it in Step 2.

3. **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:

If the description was already resolved above → ask only about the mode:
```
AskUserQuestion: Which planning mode?

Options:
1. Full (recommended) — creates git branch, codebase reconnaissance, full plan
2. Fast — quick plan without a branch
```

If the description is ALSO still missing (no session context, no researches chosen) → combine into a single question:
```
AskUserQuestion:
1. Describe the feature you want to plan.
2. Which planning mode?
   a. Full (recommended) — creates git branch, codebase reconnaissance, full plan
   b. Fast — quick plan without a branch
```

Based on choice:
- Full → full mode (the Full-mode additional steps load in Step 1.5)
- Fast → fast mode (the Fast-mode additional step loads in Step 1.5)

Ultra is deliberately absent from this question — see the parsing rules in Step 0.

### Step 0.5: Bootstrap Context (MANDATORY — all modes except List)

Before any exploration or planning — silently load the project knowledge base. Do NOT narrate the loading process to the user. Runs in every mode named by this step's heading.

#### Required reads (always, every time, in parallel)

1. **`.unikit/DESCRIPTION.md`** — project description, tech stack, constraints
2. **`.unikit/ARCHITECTURE.md`** — architecture decisions, folder structure, module rules, dependency directions
3. **Read `.unikit/memory/code/RULES_INDEX.md`**. Load rules:
   - **RULES.md**: ALWAYS read `.unikit/RULES.md` first (highest priority)
   - **Core**: read the Core table. For EACH row where Required By = `all` or 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
4. **`.unikit/skill-context/{{self_name}}/SKILL.md`** — project-specific skill overrides (if exists)
5. **Read `{{skills_dir}}/{{self_name}}/references/ENGINE_RULES.md`** — engine planning vocabulary: kind → concept (§1), language & layout (§2), when to write `Editor:` (§3), engine planning pitfalls (§4), out of scope (§5), direct-edit feasibility (§6). Set `engine_rules_loaded = true`.

   **If the file is absent** — this is a **normal path**, not an error (an engine whose planning vocabulary has not shipped yet). Set `engine_rules_loaded = false` and:
   - Do **not** generate the `Editor:` field in any task.
   - Do **not** write the `Editor tasks` line into `## Settings` and do **not** ask the editor-mode question (Step 5, `mode-full.md` / `mode-fast.md`).
   - Report it at the confirmation step — the line `Engine rules: ENGINE_RULES.md not found, Editor: fields skipped` goes into **all three** confirmation points: Step 6 **Fast mode**, Step 6 **Full mode**, and `Add Step 3: Confirm` in `mode-add.md` (the `add` mode never reaches Step 6).

   Step 0.5 runs in **every mode except List** — so `add` mode loads the vocabulary too and may append `Editor:` lines to an existing plan on the same terms as `full` / `fast`.

6. **Read `.unikit/system/engine-mcp/INDEX.md` — the base section only.** The delivery stamp plus every section **except** the `## Check` table: access, the live failure classes, shape and cost, what is irreversible here, the lane, and what to do when the file is silent. Those are the exceptions that shape *planning* — an irreversible write decides where a commit boundary falls, the lane decides what may never run in parallel, shape and cost decide how the work splits into phases. Set `mcp_index_loaded = true`.

   **Do not read the `## Check` table.** It is keyed by area for the executors, which grep their own task's area plus the cross-cutting ones on every editor task. A plan that carries checks forward has started making the executor's decisions with month-old information.

   **If the file is absent** — a **normal path**, not an error (a server that ships no rules tree, or no engine MCP at all). 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 unchanged
   ```

   Absence never switches a task to `⏸️ MANUAL`, never suppresses an `Editor:` field, and never disables the engine MCP (`.unikit/system/dev-principles.md` → **A9 · no rules ≠ no rights**).

#### Patches (learning from past fixes)

If `.unikit/code/patches/` exists:
- Use `Glob` to find all `*.md` files
- 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)

Check whether `.unikit/gamedesign/GD-IDS.yaml` exists.

- **Exists** → this project carries a game-design workspace. **Schema guard (clean
  break — no automatic migration):** the registry MUST be `version: 2`. On a pre-v2
  `version: 1` registry, do NOT read it — emit a loud `ERROR [design] GD-IDS.yaml is
  version 1 (pre-v2 layout); design grounding unavailable until the workspace is
  upgraded via /unikit-gd-spec` and set `design_linked = false` (the plan continues
  purely code-side, never silently misreading the old layout). With a valid
  `version: 2`, set `design_linked = true` and note it for **Step 4.5**, which reads
  the relevant system design (and any flow that exercises it, and any content type that feeds
  it) and produces the plan's `## Design` + optional `## Flow Context` / `## Content Context`
  snapshots. Do NOT read the design docs here — Step 4.5 owns that, after the feature scope is
  clear.
- **Absent** → set `design_linked = false` and skip every design step. The plan is
  purely code-side, exactly as before — projects without a design module are unaffected.

**One-way boundary:** planning *reads* design (`GD-IDS.yaml`, `systems/*.md`,
`flows/*.md`, and the read-only `## System Map [gen]` / `## Flow Map [gen]` in
`GAME.md`); it never writes or edits any `.unikit/gamedesign/` artifact. Design
changes flow only 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

1. Read the description and understand the feature intent.
2. **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:

3. **Get today's date** in `YYYY-MM-DD` format — it no longer goes into the folder name; it is the value of the manifest's `Created:` and `Updated:` fields (see the Plan Manifest Template in `{{skills_dir}}/{{self_name}}/references/TASK-FORMAT.md`).
4. The folder name **is** the feature name from step 2 — `<feature-name>`, no date and no separator prefix (e.g. `item-appraisal-system`).

```
# Example
ls .unikit/code/plans/
# 2026-03-08_mini-games-editor/    ← earlier format, left exactly as it is
# customer-types/
# → next: <new-feature>/
```

5. **Collision check — a slug that already exists never resolves itself silently.** Scan `.unikit/code/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>` (the `YYYY-MM-DD_` era), and a folder ending in `-<name>` whose name starts with three digits (the older `DDD-` era).

   - No match → create `plans/<feature-name>/` and continue.
   - A match → 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 `add` body (`{{skills_dir}}/{{self_name}}/references/mode-add.md`) on the matched folder and print `INFO [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>`.

   **Appending an automatic suffix (`-2`, `-v2`, a date) is forbidden.** The date used to be a separator as well as a sort key: two runs at the same feature produced two distinct names on their own. Without it there is one name, and a silently suffixed second folder is how the branch resolver starts finding the wrong plan again — the resolver matches the branch name, and the branch name has no suffix.

### Step 1.5: Load the Mode Body

The shared preamble (Steps 0–1) is done. Load the selected mode's reference body
on demand — do **not** keep all five mode bodies in context 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 A-C (git branch, recon, preferences), then continue to the Shared Steps
  below. Steps D-H of that body run later — they replace Step 5 and Step 6 of the shared
  workflow, so do **not** run them here.

(`--list` and `add` modes already dispatched in Step 0 to their own bodies — `mode-list.md` / `mode-add.md` — and STOP; they never reach here.)

---

## Shared Steps (all planning modes)

### Step 2: Check for Related Researches

**If `research_pre_linked = true`** (user already confirmed a research in Step 0.2) → read that research's `RESEARCH.md` — `## Active Summary` as the declared input, `## Findings` and the adaptive artifacts for the rationale — plus `CONTRACTS.md` and `SOURCE.md` when they exist, mark `research_linked = true`, store research path for `## Based on`, and skip to Step 3.

Before exploring code, check if `/unikit-explore` has produced relevant researches.

1. Read `.unikit/code/researches/INDEX.md`
   - If the file doesn't exist — skip this step entirely, proceed to Step 3.

2. Read `workflow.research_relevance_days` from `.unikit/config.yaml` (default: `7`).

3. **Filter** entries by three criteria:
   - `Updated` is within `research_relevance_days` from today. The age key is `Updated`, never `Created`: with a continuation cycle, freshness means "when this was last confirmed", not "when the folder was opened".
   - `Status` is `completed` (skip `in-progress` and `needs-follow-up`). The field name and its three values are **fixed** — renaming either makes this filter match nothing and report "no researches found" instead of an error, which is a failure nobody can see.
   - `Lifecycle` is not `superseded`. A record carrying no `Lifecycle` line counts as `active`.

   **Log the drop.** After filtering, print exactly one line — **always**, including when nothing was dropped, because a line that appears only on a drop is a line nobody learns to expect:

   ```
   INFO [research] index: <N> entries, <K> shown (<a> older than <days>d, <b> not completed, <c> superseded)
   ```

   A record with no `Updated` is **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 index
   ```

   The repair exists and is named in the line: any save re-renders the index whole.

4. **Match**: compare each surviving entry's `Summary` against the feature description. Select entries that are contextually relevant to the feature being planned.

5. If **0 relevant** researches found — proceed to Step 3 silently. Mark `research_linked = false`.

6. 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").

7. For each selected research:
   - Read its `RESEARCH.md` — `## Active Summary` as the declared input, `## Findings` and the adaptive artifacts for the rationale; read `CONTRACTS.md` when it exists, and `SOURCE.md` for 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 = true` and store research path for `## Based on` (uses Research Reference Format)
   - The plan's `## Technical Context` is still generated in Step 5 — the research's `## Active Summary` is used as input, not replacement (the section reflects the actual codebase state at planning time)

### 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.

#### 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.

**Doc references to include in every Explore task prompt:**
- `.unikit/ARCHITECTURE.md` — always (module boundaries, dependency rules)
- Core rule files loaded in Bootstrap — pass the **paths from RULES_INDEX.md** relevant to the task's focus (e.g., design principles for architecture analysis, folder structure for file path verification)
- Stack rule files loaded in Bootstrap — pass if the task's focus involves that framework

```
Task 1 — Architecture & affected modules:
recon-agent(prompt:
  "Before analysis, read these project docs:
   - .unikit/ARCHITECTURE.md
   - [core rule paths relevant to architecture — from RULES_INDEX.md Core table]

   Then: find files and modules related to [feature domain]. Map the directory structure,
   key entry points, and how modules interact. Thoroughness: medium.")

Task 2 — Existing patterns & conventions:
recon-agent(prompt:
  "Before analysis, read these project docs:
   - .unikit/ARCHITECTURE.md
   - [core rule paths relevant to patterns — from RULES_INDEX.md Core table]
   - [stack rule paths if task's focus involves a specific framework]

   Then: find examples of similar functionality already implemented in the project.
   Show patterns for [relevant patterns: services, controllers, models, DI bindings, etc.].
   Thoroughness: medium.")

Task 3 — Dependencies & integration points (if needed):
recon-agent(prompt:
  "Before analysis, read these project docs:
   - .unikit/ARCHITECTURE.md
   - [core rule paths relevant to dependencies — from RULES_INDEX.md Core table]

   Then: find all files that import/use [module/service]. Identify integration points
   and potential side effects of changes. Thoroughness: medium.")
```

**Fallback:** If Agent tool is unavailable, investigate directly using Glob/Grep/Read — search for relevant files, read key source code, and synthesize findings inline.

**Rules:**
- Fast mode: launch all 2-4 tasks from scratch.
- Full mode: Step B already identified key files, directories, and patterns. Use those findings to make Phase A prompts **specific** — include concrete file paths, class names, and module names discovered in Step B. This avoids re-discovery and focuses Phase A on deeper analysis of known areas rather than broad scanning.
  Example: instead of "find files related to [feature]" → "Read `<content-root>/.../IFeatureService.<ext>` and `<content-root>/.../FeatureController.<ext>` found in recon. Analyze their interfaces, DI bindings, and integration points." (`<content-root>` and `<ext>` resolve from `references/ENGINE_RULES.md` §2)
- After tasks return, synthesize: files to create/modify, patterns to follow, dependencies, risks.

#### 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:
1. Read source code of existing similar features found in Phase A
2. Extract interface signatures, constructor dependencies, DI bindings from installers
3. Identify patterns the new feature must follow (naming, structure, registration)
4. 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

This is the material the phase file's `## Current-Code Evidence` table and its
`### Implementation Steps` are written from. Thin reconnaissance does not survive the
detail floor — it 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. A file pasted whole goes stale on the first edit made
against it, and it reads as more authoritative than a path-and-symbol citation while being
less true.

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

Project docs (DESCRIPTION.md, ARCHITECTURE.md, RULES.md, core/stack rules, patches, skill-context) were already loaded in Step 0.5 (Bootstrap). This phase handles only remaining optional reads.

**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-implement` milestone completion and `/unikit-verify` roadmap gates

### Step 4.5: Resolve Design Context (game-design module)

**Runs only when `design_linked = true`** (the gate is resolved inline in Step 0.5). When it is
true, load `{{skills_dir}}/{{self_name}}/references/design-context.md` and follow it on demand —
do **not** keep the design-context body in context for pure-code plans. That body reads the shared
`design-read` contract (`.unikit/system/gamedesign/design-read.md`), applies **Flow-First
Resolution** (*intent decides the door* — resolve a system, a flow, or a content type first,
ambiguous → ask), and produces the plan's `## Design` (+ optional `## Flow Context` /
`## Content Context`) snapshot, then returns here for Step 5. When `design_linked = false`, skip this step entirely (the design-context body is never
loaded).

This step embodies the **one-way boundary**: it only *reads* design artifacts — 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:

1. **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 `kind` vocabulary is in `.unikit/system/dev-principles.md` → A8.
2. **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. A question of this shape keeps its answer for months ("is there a test run at all"); a question about a name loses it in days — which is why 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 `⏸️ MANUAL` into the task.** That is a runtime verdict, reached by trying and producing the evidence of absence (A9); a planner that writes it in advance has lifted the executor's obligation to try;
- an evidence class that is not reachable → rewrite the acceptance criterion against a class that is, or say plainly in `## Overview` that 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. The reference is the executors' resource — `/unikit-implement` and `/unikit-fix` reach for it on two triggers, and neither of them is "planning".

**No engine MCP configured, or discovery yields nothing → skip.** Plan against the base principles, unchanged. The absence of an answer is not a restriction (A9).

### Step 5: Create the Plan

- **Fast and full** — use the canonical templates fro

…(truncated)
