# Plan

> Use after DISCOVER, or standalone with an approved design, to produce the cold-executor trio (plan.md + spec.md + prompt.md). Keep short, verifiable leaves and group connected work into bounded packages for implementation and review, with operator approval before BUILD.

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

---


You are the PLAN skill — Phase 4 of the Lintel cycle.

## What this skill does

Takes APPROVED design doc (from DEFINE) + discover-report.md (from DISCOVER) and produces:
1. **plan.md** — task list with file paths + complete code (where prescriptive) + verification steps + dependencies + ordering
2. **spec.md + prompt.md** — the master spec and cold-executor handoff, reviewed with the plan
3. **Plan signals** — tasks, phases and a labelled whole-cycle token estimate. Present before BUILD; no invented price.
4. **Founder approval gate** — explicit pause before commit

Adopted from speckit (cross-section Analyze), Architect image (cost-estimate gate, founder approval gate), and superpowers (two-stage subagent review).

## When to use

- After DEFINE has produced APPROVED design doc
- After DISCOVER has produced discover-report.md
- Standalone if operator already has design doc but needs plan
- Re-PLAN if BUILD reveals plan was wrong (loop-back path)

## When NOT to use

- intent=hotfix (light plan only, or skip to BUILD with minimal task list)
- intent=trivial-edit (skip entirely, just BUILD with verification)
- No APPROVED design doc → return to DEFINE
- intent=research-dive → no PLAN needed (research mode ends at DISCOVER)

## Workflow

### Existing Spec Kit plan branch

When the operator selects existing Spec Kit artifacts, use the
[shared work-map contract](../spec-kit/references/work-map.md) before the ordinary template
pipeline below. Read the original spec.md, implementation plan.md and tasks.md, check their
coverage/dependencies and record missing decisions. Preserve their structure and task IDs.
Write the exact-path handoff and work.json, then validate it with `bin/li-work-artifacts.py`; Lintel plan.md/spec.md companions, if needed, are
reference-only. Existing authorization can approve this mapped scope; do not require a new
Lintel approval heading inside Spec Kit plan.md or recreate its tasks through DEFINE/PLAN.
The remainder of the ordinary trio-generation steps applies only to Lintel-native plans.
For native plans, also write work.json with `tasks` pointing to plan.md and link it from todo.md.

For either workflow, select the initiative explicitly from operator intent or unambiguous
committed work links. Set `LINTEL_WORK_MAP` to that work.json; for a newly created native
plan, set `LINTEL_PLAN_DIR` to the exact directory being written. Never select by modification
time. The completeness gate below validates this selection for both workflows. Record package
membership in the existing design or linked handoff using the original task IDs; mapped work
without grouping uses singleton packages, without a duplicate task list. Code/helpers live in
`LINTEL_SOURCE_ROOT`; maps and their artifacts resolve relative to `LINTEL_REPO_ROOT`.


**Existing authorization:** record the operator's authorized scope before the gates below.
Present plan signals and a reviewable plan, but do not ask again for execution already explicitly
authorized in this session. Ask once when a material scope/authority decision remains unanswered.
Approval does not extend to production actions, secrets or unrelated work.

### Step 1 — Load context

**Surface relevant lessons (mirrors SENSE Step 0a — non-blocking):**

Invoke `/li:lessons-surface` keyword-scoped to planning so prior-session lessons warm the plan before any tasks are written. Same mechanism SENSE uses (max 3 lessons, prepended to context, silent on no match, never a blocker):

Invocation: `/li:lessons-surface --keyword "planning architecture scope dependencies"` (a portable skill call; silent if no relevant matches).

Then read:
- APPROVED design doc from DEFINE
- discover-report.md from DISCOVER (if present)
- `scope.md` from SCOPE (the `depth_schema` source — `flat` / `phased` / `tree`; selects the plan.template.md variant). If absent (e.g. SCOPE skipped in a light mode), default `depth_schema: flat`.
- the canonical templates (`scaffolding/01-foundation/templates/plan/{plan,spec,prompt}.template.md`)
- CORE-PRINCIPLES.md (always)
- the active pack's compliance gates (`resolve_pack_field compliance.hooks`; none by default)
- Recent ADRs identified by DISCOVER as relevant

If design doc not APPROVED → BLOCKED, return to DEFINE.

**Profile impact:** resolve the active pack through `resolve_pack_field` and read only the
referenced policies or knowledge relevant to this design. In the template's Profile impact
section, trace each applicable requirement to its exact pack field or source file/section,
existing requirement ID, affected leaf IDs and verification evidence. State what changes in
the deliverable because of that requirement. Keep advice distinct from mandatory policy;
profile presence does not prove that a hook is installed or a control passed. For `_default`
or no applicable requirement, record that outcome without inventing enterprise controls.

### Step 2 — Plan-eng-review (engineering plan)

Invoke `/li:plan-eng-review` skill (or inline equivalent).

Output: task list with for each task:
- Task ID
- Title (verb + object)
- Target file path(s), one accountable implementer/owner and the permitted edit boundary
- Requirement IDs from the approved design/spec (including applicable profile requirements)
- Dependency on prior tasks
- Observable acceptance outcome, verification command/procedure and expected evidence
- Estimated tokens; keep the granularity time check internal unless time was requested
- Complexity (mechanical / multi-file / architecture)
- Recommended implementer role (per discover-report's mapping; shared by its work package)

Rule (from superpowers): each task should be 2-5 minutes of implementer time. Bigger = decompose.

Group leaves into **work packages** (`P1`, `P2`, …) using the
[planner module contract](../../docs/concepts/planner-as-module.md#work-packages).
Each package has one outcome, the same write owner and edit boundary, connected dependencies
and acceptance evidence mapped back to its unchanged leaf IDs. The template carries the
package table; keep leaf detail separate. Split at owner, security, irreversible-decision or
independent rollback boundaries. Choose boundaries from the work, not a fixed leaf count or
duration. An existing ungrouped plan uses one package per leaf without renumbering its tasks.

BUILD executes packages sequentially, their leaves in dependency order, and applies spec then
quality review to the combined package once, with findings and evidence mapped to leaves.
A package cannot be DONE until every leaf is verified. Determine review depth from the whole
package: several small edits can still form a substantive integration. Packaging changes the
execution/review unit; the ≤5-minute leaf check and approval gates remain.

Instantiate the trio from the canonical templates as **DRAFT** before the following reviews;
keep those drafts current as tasks change. A verification command alone is not an acceptance
criterion: name the behavior it must demonstrate and its expected result. Link existing
authoritative requirements instead of copying them into a competing specification.

### Step 3 — Plan-design-review (if frontend in scope)

If design doc indicates UI/frontend work, invoke `/li:plan-design-review`:
- Design system implications
- Accessibility considerations
- Visual sketch (if needed) via `/li:design-html` or `/li:design-review`

Add design tasks to plan.

### Step 4 — Plan-devex-review (always)

Invoke `/li:plan-devex-review`:
- Operator-DX implications (will this be painful to use later?)
- Documentation needed
- Telemetry hooks needed
- Test coverage gaps

Add DX-improving tasks to plan.

### Step 5 — Plan-tune (iterative refinement)

If plan-eng-review / plan-design-review / plan-devex-review surface conflicts or gaps, invoke `/li:plan-tune` to reconcile.

Iterate until plan is internally consistent.

### Step 6 — Dependency graph

For each leaf, identify upstream blocking leaves, then derive package dependencies from those
edges. A package must not hide a dependency on a leaf in a later package. Visualize:

```
T1 (setup) → T2 (schema) → T3 (api) → T5 (test-e2e)
                       ↘ T4 (ui) ↗
```

Detect cycles and impossible orderings in both views. Keep leaf IDs authoritative; the package
table is a grouping in plan.md, not a new job-state schema or an automatic dispatch service.
Surface blockers explicitly.

### Step 7 — Cost estimate (MANDATORY GATE)

**Time-on-request (design §3.7):** wall-clock time fields are emitted **only** when the operator asked for them (`--with-time`, or they explicitly request it). Tokens + task count + size are always shown; time is opt-in so the default estimate never anchors on a guessed duration.

**Honest signals only (no invented dollar figure).** Lintel has no pricing table and the token
estimator is **uncalibrated until CAPTURE records actuals** (`scale_calibrated_prior` falls back to
`size_default_prior` — a hardcoded guess — when no history exists; see `lib/scale-estimator.sh`).
So the gate presents what the system can honestly compute — **task count, the phase list, and a
labelled token estimate** — and does **not** present a dollar number the system cannot derive.

```yaml
# Plan signals (honest — task count + phases + labelled token estimate)
total_tasks: N   # unchanged leaf count
work_packages: N
phases: [<phase list from the plan — what BUILD will actually run>]
size: <XS|S|M|L|XL from scope.md>
execution_roles: [<roles selected for package complexity and review independence>]
# model_configuration: <actual available host configuration, only when known>

token_estimate:
  value: <tokens from scale_token_estimate <size>, once for the whole cycle>
  basis: <calibrated|uncalibrated from the same helper result>
  samples: <matching measured cycles from the same helper result>
  scope: cycle
# estimated_time: <sum minutes>     # only when --with-time
```

`scale_token_estimate <size>` returns `tokens basis samples` in one read; the numeric
`scale_calibrated_prior` API remains available. CAPTURE records whole-cycle actuals, so never
multiply this prior by the number of tasks or sum it once per leaf. Calibration writes remain
opt-in under ADR-0008; no usable actuals means `uncalibrated`, even if a log file exists.

AskUserQuestion (MANDATORY):
"Plan ready: <N> tasks across <phase list>, est. ~<tokens> tokens (<CALIBRATED | UNCALIBRATED — no actuals recorded yet>). Proceed?"  (append ", ~<duration>" only when `--with-time`; **never** a `$` figure)
- A) Approve and proceed
- B) Scope-trim (which tasks to defer)
- C) Decompose (tasks too big, break further)
- D) Abort (scope too large)

If A: continue to Step 8. If B/C: loop back. If D: status BLOCKED, no advance.

### Step 8 — Cross-section-analyze (delegates to /li:analyze, ADR-0004)

Invoke `/li:analyze` with trigger `plan-step8` — it runs the DEFINE↔PLAN and authority legs
(coverage, traceability, LOCKED-decision contradictions, discover-report ADR constraints) and
persists `.claude/runtime/state/analyze-report.md`. One implementation, shared with BUILD's final pass
and standalone runs; do not re-implement the checks inline.

If the report has findings: surface the gap-list, ask operator: defer to backlog / add to plan /
accept gap (record the acceptance in the report).

### Step 9 — Adversarial two-stage review (adopted from superpowers)

Dispatch CodeReviewer subagent (or general-purpose) with plan.md path:

**Stage 1 — Spec compliance review:**
"Does plan.md match design doc requirements exactly? Coverage gaps? Tasks not traceable to design?"

If Stage 1 finds issues: fix (Edit tool), re-dispatch. Max 3 iterations.

**Stage 2 — Quality review (only after Stage 1 PASS):**
"Are leaves well-decomposed, package boundaries coherent and aggregate review depth appropriate?
Are dependencies correct, estimates grounded, acceptance and evidence complete for every leaf?"

If Stage 2 finds issues: fix, re-dispatch. Max 3 iterations.

Convergence guard: if same issues persist across 3 iterations, surface as "Reviewer Concerns" in plan.md and proceed.

If subagent unavailable: skip review, note in plan.md "Adversarial review unavailable — plan unreviewed."

### Step 10 — Founder approval gate (MANDATORY PAUSE)

AskUserQuestion (per Architect image):
"Plan reviewed. <N tasks> across <phase list>, est. ~<tokens> tokens (<CALIBRATED | UNCALIBRATED>). Final approval?"  (append ", ~<duration>" only when `--with-time`; never a `$` figure — the basis for this is Step 7)
- A) APPROVE — proceed to BUILD
- B) REDIRECT — specific feedback (loop back)
- C) PAUSE — save state for later, don't proceed
- D) ABORT — close plan, status BLOCKED

If A: mark the reviewed trio APPROVED, finalize it and write the checkpoint. Only declare
status DONE after the artifact checks below pass. Until approval, all three remain DRAFT.

### Step 11 — Write artifacts

**The trio comes from versioned template files (Slice 2 — design §3.3).** plan.md / spec.md / prompt.md are no longer rendered from inline prose; they are instantiated from the canonical template family, the **single source of truth** for their shape:

- `scaffolding/01-foundation/templates/plan/plan.template.md` — **depth_schema-parametric** (flat / phased / tree marked sections).
- `scaffolding/01-foundation/templates/plan/spec.template.md` — engineering master spec.
- `scaffolding/01-foundation/templates/plan/prompt.template.md` — cold-executor handoff.

Read the template, strip the comment header + the unused `depth_schema` sections (for plan.template.md), fill the placeholders, and write the result to the output path. Preserve the approval status established at Step 10 when finalizing the drafts. If the scaffolding tree is absent, locate these templates in the installed Lintel source; if unavailable there too, retain the essential task fields from Step 2 and depth structure below, and record that the canonical template was unavailable.

**plan.md** (canonical, `.claude/plans/<slug>/plan.md`) — from `plan.template.md`:
```markdown
# Plan: <wedge title>   (size: <XS|S|M|L|XL> · schema: <flat|phased|tree>)

**Generated by:** /li:plan on <date>
**Status:** DRAFT (APPROVED only after Step 10)
**Design doc:** <path>
**Discover report:** <path>
**Scope:** <path to scope.md>

## Summary
<2-3 sentences>

## Plan signals
- Tasks: <N>
- Phases: <phase list — what BUILD will run>
- Size: <XS|S|M|L|XL from scope.md>
- Token estimate: ~<total> (<CALIBRATED from CAPTURE history | UNCALIBRATED — no actuals yet, size_default_prior guess>)
<!-- no dollar figure: Lintel has no pricing table (Step 7) -->
<!-- - Duration: <time>   ← only emit when --with-time (design §3.7) -->
```

**Depth-parametric rendering (design §3.3).** Read `depth_schema` from `scope.md` (emitted by the SCOPE phase) and render the `plan.template.md` section that matches. The 2-5 min granularity rule applies to the **leaf** (task at flat/phased, subtask at tree) — hierarchy adds milestones, it does not weaken the leaf check. `plan-eng-review` Step 0's BLOCKING per-leaf check stays.

- **`flat`** (XS/S — today's shape): one task table, IDs `T1, T2, …`.
- **`phased`** (M): phases with tasks, numbered `1, 1.1 / 2, 2.1`.
- **`tree`** (L/XL): phases → tasks → subtasks + milestone checkpoints, `1 / 1.1 / 1.1.a` (Slice 2 — see below).

Use the matching tables and per-leaf detail from `plan.template.md`; it is the source of
truth for ownership, requirement tracing, acceptance, verification and evidence fields.
Only add a minutes column when the operator requested time estimates.

**`depth_schema: tree` — WBS rendering for L/XL (Slice 2 — design §3.3).** Renders phase → task → subtask with milestone checkpoints. This replaces Slice 1's fallback (where `tree` degraded to `phased`).

**Numbering scheme** (three tiers, strictly hierarchical):
- **Phase** — `Phase 1`, `Phase 2`, … (top tier; each carries a `[milestone-checkpoint: <pass criterion>]`).
- **Task** — `1.1`, `1.2` / `2.1`, `2.2` (the `<phase>.<task>` tier).
- **Subtask** — `1.1.a`, `1.1.b` / `1.2.a` (the `<phase>.<task>.<letter>` tier; lowercase letters).

The **subtask is the LEAF** at tree depth — the verification and progress unit. The 2-5 min granularity rule applies to the subtask (`1.1.a`), NOT the task or phase. Work packages group these leaves for execution and review while retaining leaf evidence and status. Milestone checkpoints stay at the **phase** level; packaging does not replace existing resume pointers.

**`--lazy` (optional, opt-in — design §5 Approach-C graft):** for very large XL trees, the subtask leaves (`1.1.a`) under a phase MAY be elaborated **just-in-time** when BUILD reaches that phase, rather than all up front. When `--lazy` is set, render the phases + tasks now and mark each phase's subtasks `(lazy: elaborated at BUILD)`; the per-leaf ≤5 min rule still applies once a leaf is elaborated. Opt-in only — the default renders the full tree up front (preserves the trio's born-together contract; `--lazy` is the escape hatch for genuinely huge greenfield work where up-front elaboration would be wasteful).

**spec.md** (canonical, `.claude/plans/<slug>/spec.md`) — from `spec.template.md`:
- Master engineering specification — born in PLAN (v3.8 Feature 2.2: trio born together)
- Architecture overview from design doc
- Data model, interfaces, contracts
- Requirements traced to design
- Status: APPROVED (CAPTURE re-affirms on cycle-end, no longer the birth-point)

**prompt.md** (canonical, `.claude/plans/<slug>/prompt.md`) — from `prompt.template.md` — **v3.8 Feature 2.2: born in PLAN, not CAPTURE.**

It is a SELF-CONTAINED prompt: a fresh AI session reading only this prompt + the linked spec.md + plan.md can re-execute or extend the work without prior context. See `prompt.template.md` for the full skeleton (Context / Constraints / Acceptance criteria / Deliverables / How to re-execute / What you DON'T need to know).

The trio (plan.md + spec.md + prompt.md) is the cold-executor handoff contract. Born together in PLAN — from the versioned templates above — so standalone planner-module invocations (`/li:plan <design.md>` without a surrounding cycle) produce a complete handoff. CAPTURE re-affirms the trio (verifies presence, updates with final-build evidence) but no longer generates prompt.md.

**.planner-checkpoint.md** (`.claude/runtime/state/`):
- State for `/li:resume`
- Includes plan.md path, current task pointer, build-log placeholder

### Step 11a — Trio completeness gate (mechanical — issue I4)

The selected work map is the handoff contract for native and Spec Kit work. Before declaring
PLAN done, validate its paths, approval status and nonempty artifacts through the shared
validator. This proves selection and structural completeness; the preceding reviews must
also verify that requirements, leaf acceptance and handoff context are substantive, with no
unfilled template placeholders. Structural validation alone does not prove those semantics.

```bash
working_repo="${LINTEL_REPO_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null)}"
lintel_source="${LINTEL_SOURCE_ROOT:-$working_repo}"
selected_work_map="${LINTEL_WORK_MAP:-}"
if [ -z "$selected_work_map" ] && [ -n "${LINTEL_PLAN_DIR:-}" ]; then
  selected_work_map="${LINTEL_PLAN_DIR%/}/work.json"
fi
[ -n "$selected_work_map" ] || {
  echo "PLAN BLOCKED: select the initiative's work.json or exact LINTEL_PLAN_DIR" >&2
  exit 1
}
case "$selected_work_map" in
  /*|[A-Za-z]:/*) : ;;
  *) selected_work_map="$working_repo/$selected_work_map" ;;
esac
"${PYTHON:-python3}" - "$lintel_source/bin/li-work-artifacts.py" "$working_repo" "$selected_work_map" <<'PY'
from pathlib import Path
import runpy
import sys

helper, repo, selected = sys.argv[1:]
try:
    contract = runpy.run_path(helper)
    root = Path(repo).resolve()
    work = contract["load_work_map"](root, Path(selected))
    if work["status"] != "APPROVED":
        raise ValueError("selected work must be APPROVED before BUILD")
    for field in contract["REQUIRED_ARTIFACTS"]:
        path = contract["artifact_path"](root, work[field])
        if not path.read_text(encoding="utf-8-sig").strip():
            raise ValueError(f"selected {field} artifact is empty: {work[field]}")
except (OSError, ValueError, TypeError) as error:
    print(f"PLAN BLOCKED: {error}", file=sys.stderr)
    sys.exit(1)
print("PASS: explicitly selected approved work map and nonempty artifacts")
PY
gate_status=$?
[ "$gate_status" -eq 0 ] || exit "$gate_status"
slug_dir="$(dirname "$selected_work_map")"
# Optional stronger check: if a cold_executor envelope was emitted, validate it against the schema
[ -f "$slug_dir/handoff.envelope.yaml" ] && "$lintel_source/bin/li-envelope-validate" "$slug_dir/handoff.envelope.yaml" --quiet || true
```

### Step 11b — Handoff-size check against the 500k cap (trio-emit gate, NON-BLOCKING)

The trio (plan.md + spec.md + prompt.md) now exists on disk — this is the cold-executor handoff payload. Before recommending BUILD, run the existing cap check so the trio + warming context can't silently exceed the 500k cap (the v4.9 audit's PARTIALLY-UPHELD Promise 6: cap logic existed but was invoked at no handoff).

Invoke the existing mechanism — do **not** rebuild it:

`/li:handoff-size-check` (a portable skill call; reads the trio it just wrote + `.claude/runtime/state/warming-manifest.md`, applies the mode-aware cap from `/li:context-budget` mode_envelopes, default `customer-engagement: 500k soft / 750k hard`).

- **SURFACE, don't block.** A yellow/red verdict warns ("this plan yields ~Nk handoff, near cap — split it?") and surfaces options (split the plan, cut a warming target, switch to a higher-cap mode). It does NOT halt PLAN — the operator decides.
- **Off-switch:** `--skip-handoff-size-check` (or `SKIP_HANDOFF_SIZE_CHECK=1`) skips the gate entirely for operators who don't want it. Silent when skipped.
- Silent green pass when trio + warming < soft cap — no friction in the common case.

### Step 12 — 00-state.md append

Mechanical since v5.0 (ADR-0008) — one command, not a YAML obligation:

```bash
_sl="${LINTEL_SOURCE_ROOT:-${LINTEL_REPO_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null)}}/lib/state.sh"
[ -f "$_sl" ] || _sl="$HOME/.lintel/lib/state.sh"; source "$_sl"   # installed by install.sh in consumer repos
state_append PLAN DONE next=BUILD plan_path=<path> spec_draft_path=<path> tasks_count=<N> tokens_est=<total> tokens_est_basis=<calibrated|uncalibrated>
```

## Status protocol

- **DONE** — plan APPROVED with cost estimate accepted + adversarial review pass
- **DONE_WITH_CONCERNS** — approved with caveats noted (reviewer concerns left in plan.md)
- **BLOCKED** — cost exceeds operator budget OR alternative undecided OR design missing
- **NEEDS_CONTEXT** — design doc incomplete, return to DEFINE

## Pause-points (MANDATORY)

1. After plan-eng-review/design-review/devex-review → confirm findings addressed before tune
2. After cost estimate → AskUserQuestion gate (D7)
3. After cross-section-analyze → if gaps, AskUserQuestion defer/add/accept
4. After two-stage review → fix gaps before next stage
5. After full plan + reviews → AskUserQuestion founder approval gate (D10)

## Hop-in support

YES — operator can /li:plan with existing APPROVED design doc.

Skip-conditions:
- intent=hotfix (light plan, skip cost-estimate gate if <5k tokens)
- intent=research-dive (no plan needed)

## Integration

**Reads:**
- APPROVED design doc (from DEFINE)
- discover-report.md (from DISCOVER)
- `scope.md` (from SCOPE — the `depth_schema` that selects the WBS template variant)
- `scaffolding/01-foundation/templates/plan/{plan,spec,prompt}.template.md` (the canonical trio templates)
- CORE-PRINCIPLES.md
- the active pack's compliance gates (`resolve_pack_field compliance.hooks`; none by default)
- Recent relevant ADRs
- `.claude/memory/lessons.md` (via `/li:lessons-surface`, keyword-scoped, non-blocking)

**Writes:**
- `plan.md` (canonical)
- `spec.md` (draft, finalized in CAPTURE)
- `.claude/runtime/state/.planner-checkpoint.md`
- `.claude/runtime/state/00-state.md` (PLAN entry)
- `.claude/runtime/audit/plan-metrics.jsonl`

**Triggers:**
- BUILD with plan.md as canonical source

## Recommended agents to dispatch (from discover-report)

- **Planner** (engineering/) — primary, task decomposition
- **Architect** (engineering/) — sanity-check tech choices
- **BackendArchitect / FrontendBuilder / DataPipelineDesigner** (engineering/) — per domain
- **APIDesigner** (engineering/) — if API surface
- **DatabaseDesigner** (engineering/) — if schema changes
- **TerraformReviewer / K8sManifestReviewer** (devops/) — if infra
- **ADRDrafter** (engineering/) — if non-trivial decisions surface during planning
- **SecurityAuditor / ThreatModelDrafter** (security/) — sensitive-data flow review
- **EUAIActReviewer** (compliance/) — if AI/ML in a regulated market

## Anti-patterns

- **Plan that's a vague to-do list** — must be file:line:verb with complete code or precise spec
- **No cost estimate** — operator commits to unknown burn → wasted hours
- **Skipping two-stage review because "it's a simple plan"** — simple plans hide assumption gaps
- **Ignoring ADRs identified in DISCOVER** — they're constraints, not advisory
- **Task decomposition too coarse** — 2-5 min per task (superpowers rule); bigger = decompose
- **Invented model availability** — select roles by package complexity and honor the current host's actual model configuration
- **Plan finalized without founder gate** — gate is MANDATORY per Architect image pattern

## Failure recovery

- **Cost estimate exceeds budget**: AskUserQuestion scope-trim / decompose / abort. Don't proceed silently.
- **Subagent reviewer unavailable**: skip review, note in plan.md, proceed with caveat in status.
- **Cross-section analyze finds critical gap**: PAUSE, fix gap (back to DEFINE if design-level), re-plan.
- **Operator rejects 3x at founder gate**: status BLOCKED, save state for next session, don't loop indefinitely.

## Voice tier behavior

`voice: internal`. Plan.md is engineering-internal. spec.md inherits the active pack's voice tier (`resolve_pack_field voice.default_tier`; default: internal).

## Module-callable (v3.8 Feature 2.4)

PLAN is no longer just Phase 4 of `cycle` — it's a callable planner-module that any workflow can invoke.

### Three invocation modes

**1. Inside cycle (Phase 4):**
```
/li:cycle → SENSE → DEFINE → DISCOVER → PLAN → BUILD → REVIEW → SHIP → CAPTURE
                                          ▲
                                  reads DEFINE + DISCOVER outputs from job dir
```

**2. Standalone:**
```
/li:plan <design.md>
   ↓
   workflow_root: true → spawns own job at .claude/runtime/jobs/plan-<stamp>-<hash>/
       (job auto-spawn is dormant by decision, ADR-0008 — the job-begin hook is
        not auto-registered; the trio + approval gate below run regardless)
   produces: plan.md + spec.md + prompt.md (the trio)
   handoff-size-check against 500k cap (trio + warming)
   founder approval gate
   → DONE, ready for cold-executor handoff
```

**3. Sub-module called by another workflow_root skill:**
```
/li:cycle                    OR    /li:safe-install
  ↓ discovery                       ↓ pre-flight
  CALL /li:plan --from <design>     CALL /li:plan --from <change-spec>
  ↓ receives trio                   ↓ receives trio
  proceed to BUILD with trio        proceed to execute with trio
```

The calling workflow passes:
- `--from <path>` (design doc or change-spec)
- `--called-by <skill-name>` (sets `CALLED_BY` env so job.yaml records caller)
- `--no-job` (if the caller is itself a workflow_root job; nested jobs are pointless)

### Output contract (deterministic for callers)

Regardless of invocation mode, PLAN always emits:

- `<run-dir>/plan.md` — task breakdown
- `<run-dir>/spec.md` — engineering master spec
- `<run-dir>/prompt.md` — cold-executor handoff (born here, v3.8 Feature 2.2)

Callers can rely on these paths existing post-DONE. CAPTURE re-affirms but doesn't (re)generate.

### Job integration

When `workflow_root: true` fires `job-begin` hook:
- Job spawned at `.claude/runtime/jobs/plan-<stamp>-<hash>/`
- Trio written to `outputs/plan.md`, `outputs/spec.md`, `outputs/prompt.md`
- `job-end` promotes trio to `.claude/plans/<slug>/` on DONE

### Anti-pattern: nested job spawning

If `/li:cycle` calls `/li:plan` as Phase 4, the operator already has a cycle-job. PLAN should NOT spawn its own nested job — that creates two open jobs for one workflow. The caller passes `--no-job` (or `NO_JOB=1` env) so the `job-begin` hook short-circuits.

### See also

- `docs/concepts/planner-as-module.md` (architecture doc)
- `/li:jobs` controller

## Cycle-position footer

Close your report with the shared position footer so the operator always knows where they are in the
cycle and the one logical next action — whether this phase ran standalone or inside `/li:cycle`:

```bash
source "${LINTEL_SOURCE_ROOT:-$LINTEL_REPO_ROOT}/lib/cycle-footer.sh"   # fallback: "${LINTEL_SOURCE_ROOT:-$(git rev-parse --show-toplevel)}/lib/cycle-footer.sh"
render_cycle_footer                               # reads .claude/runtime/state/00-state.md; --compact for short replies
```

Skipped phases render `⊘`; ASCII via `LINTEL_ASCII=1`. See [ADR-0003](../../.claude/decisions/0003-cycle-position-footer.md).

