che-plan
Transforms an Approved SPEC into one or more structured tickets (Jira, Linear, ClickUp). Supports single tickets or Epic/Feature structures with sub-tasks, BDD acceptance criteria, and dependency mapp
SKILL.mdskills/che-plan/SKILL.md
GitHubChe Plan (Epic & Ticket Generator)
SHARED REFERENCES:
- Approved SPEC format:
che-specskill- Engineering contracts (BDD, KISS, DbC):
engineering-contractsskill- Path resolution:
cheCLI (che compute_paths,che ensure_dirs)
This skill acts as a bridge between technical specification and project management. It ensures that implementation tasks are properly documented, categorized, and linked in external tools.
§0 PRECONDITIONS
- Approved SPEC required: This skill MUST fail if no Approved SPEC is found for the current feature/slug.
- MCP Access: Requires access to
mcp_flockr-linear,mcp_laion-clickup, or a browser-based agent for Jira. - User Input: Requires Project/Board name and Target Language (default: English).
- CANONICAL PRECONDITION TRIO (Vertical + Reversibility + Assertive DbC): Parse Approved SPEC YAML frontmatter AND scan §2 SCOPE for literal overrides before any ticket generation.
4.1 CANONICAL #0 — Vertical Slice Precondition (unchanged):
- Case A (VERTICAL, default):
frontmatter.tracer_f0_defined === trueAND §4.5 VERTICAL SLICES table has ≥1 F0 row with Layers Touched ≥ 2 → proceed normally. - Case B (HORIZONTAL OVERRIDE, explicit only):
frontmatter.vertical_slice_required === falseOR the literalEXPLICIT_OVERRIDE_HORIZONTAL_PLAN:+ 1-line justification appears verbatim in SPEC §2 SCOPE → proceed, but FIRST append a[HORIZONTAL_TICKET_PLAN]entry to decisions.log.jsonl containing the spec_slug, justification verbatim, and count of sub-tasks to be generated. - Case C (INVALID — FAIL HARD): Neither case above is true. → REJECT with canonical V16/V17 text. 4.2 CANONICAL #1 — Reversibility Precondition (TRIGGER per S08 CHE_RULES §X: estimated_files_max >= 5 OR external_deps_count >= 1):
- Parse SPEC for literal
EXPLICIT_OVERRIDE_REVERSIBILITY: <justif>in §2 SCOPE OR check that header### §4.6 REVERSIBILITY DECLARATIONSexists with 3 non-empty sub-tables (V19a Wrapper Boundary, V19b Rollback Flags if applicable, V19c Forking Road). - If NEITHER override NOR 3 tables present → REJECT before ticket generation: "CANONICAL #1 Reversibility precondition failed (che-plan §0.4.2). Approved SPEC scope ≥ 5 files or uses ≥ 1 external dep per S08 CHE_RULES, but §4.6 Reversibility Declarations tables (V19a/b/c) are missing AND no EXPLICIT_OVERRIDE_REVERSIBILITY literal in §2. Either (A) re-run che-spec so V19 passes, or (B) get user to add literal
EXPLICIT_OVERRIDE_REVERSIBILITY: <1-line reason ≤120 chars>to §2 SCOPE, re-approve, then retry." 4.3 CANONICAL #3 — Assertive Programming Precondition (TRIGGER per S09 CHE_RULES §X: B_COUNT >= 3): - If scope
B_COUNT >= 3(S09): Either SPEC contains valid §4.7 Assertive Programming table (A-1..N rows ≥ ceil(B/3) per S02 CHE_RULES §X), all rows have "CRASH" in last col), OR §2 literalEXPLICIT_OVERRIDE_DBC_ASSERTIONS: <justif>exists. - Else → REJECT: "CANONICAL #3 DbC Assertive precondition failed per S09 CHE_RULES. B_COUNT=$B >= 3 requires §4.7 Assertive Programming invariants table (V20, density floor per S02) OR explicit override literal. Re-run che-spec to pass V20, or add EXPLICIT_OVERRIDE_DBC_ASSERTIONS to §2."
- Case A (VERTICAL, default):
§1 WORKFLOW
Step 1: Spec Analysis
- Read the SPEC from
$CHE_WORKSPACE_SHARED/specs/<slug>/<timestamp>-spec.mdOR from$CHE_WORKSPACE_SHARED/spec_<slug>.md(try both, first existing wins). - Extract
B_COUNT,AB_COUNT,change_class, ANDtracer_f0_definedfrom YAML frontmatter. Parse §4.5 VERTICAL SLICES table into a list of slice dictionaries[{id:F0, bid:[...], layers:[...], done:...}, {id:F1,...}]. - Pre-decomposition vertical slice validation (G-VS-2 gate here):
- If
EXPLICIT_OVERRIDE_HORIZONTAL_PLAN:NOT found in §2 SCOPE ANDtracer_f0_defined !== true: HARD REJECT before structure decision. Msg = identical to §0 Precondition #4 Case C. - Parse every sub-slice: compute
distinct_layers = len(set(slice.layers)). Collect listsingle_layer_slices = [s.id for s in slices if distinct_layers < 2 AND s.id[-12:] != 'H-OVERRIDE-1']. Iflen(single_layer_slices) >= 3AND no override → REJECT: "Vertical slice decomposition has $N slices touching only 1 architectural layer each — this is horizontal planning disguised as vertical. Either add 2nd layer to each slice OR declare EXPLICIT_OVERRIDE_HORIZONTAL_PLAN in §2 SCOPE bullet with ≤120 char justification."
- If
- Structure Decision (thresholds per S10 CHE_RULES §X):
- Single Ticket: If
B_COUNT <= 3ANDestimated_files_max <= 5ANDchange_classis notfeature(S10 Single case). If SPEC has exactly 1 slice (F0 only) → Single Ticket always. - Epic/Feature: Otherwise (S10 Epic case). Create a parent Epic/Feature and decompose into sub-tasks with 1 SUB-TASK PER SLICE ID. DO NOT create sub-tasks that group multiple slices into one. F0 is ALWAYS the first sub-ticket, critical_path=True.
- Single Ticket: If
Step 2: Content Formatting (MANDATORY TEMPLATE)
Every ticket (single or sub-task) MUST follow this structure to ensure alignment with Specflow Phase 3 and CANONICAL #0 Vertical Slicing:
# [ID] [COLLABORATION_TAG] Title (Short & Action-oriented)
> **Tag**: [AI-Assisted] | [Human-Driven] | [Collaborative]
> **Roadmap Phase**: [ID from roadmap.md] (Specflow Phase 2)
> **Strategic Intent**: [Link to intent.md] (Specflow Phase 1)
> **🔴 Vertical Slice Ref (CANONICAL #0)**: [F0 | F1 | F2 | ... FN — EXACT ID from SPEC §4.5 VERTICAL SLICES table. Single ticket = F0 always. Epic Parent = F0..FN range. HORIZONTAL_OVERRIDE ticket = F<N>-H-OVERRIDE-1 if applicable.]
> **Layers Touched (≥2 required, unless override)**: [list 2+ top-level folders from SPEC §4.5 column 4, e.g. pages/ · app/api/ · packages/db/. Single-layer tickets PROHIBITED unless override logged.]
> **🔵 Wrapper Boundaries Touched (CANONICAL #1 Reversibility)**: [List §4.6.1 V19a wrapper globs + external dependency names that this slice modifies. If this task imports ANY SDK outside its wrapper boundary → BLOCK in che-act §0.5. Leave "N/A" if zero external deps.]
> **🟣 Assertion IDs Delivered (CANONICAL #3 DbC)**: [List A-1..N from §4.7 V20 whose invariant enforcement code is added/modified by this ticket. If scope touches ≥3 B-IDs this list must be non-empty. Leave "-" otherwise.]
> **🟤 DRY Rules Touched (V21 DRY Knowledge)**: [List Business Rule rows from §4.8 V21 whose authoritative source is touched. If any rule's single-source module is edited → annotate so downstream consumers are notified in PR review.]
## 📝 Problem Description
[Extract from SPEC §1 WHY]
## 🛠 Functional Requirements
[Extract from SPEC §4.2 Behaviors relevant ONLY to the Vertical Slice Ref listed above — DO NOT include behaviours from other slices. 1 B-ID minimum = F0 ticket.]
## ⚙️ Non-Functional Requirements
[Extract from SPEC §3 Contracts & §7 Hints — relevant to THIS slice only.]
## ⚖️ Mandatory Business Rules
[Extract from SPEC §4.1 Key Rules — rules that apply to B-IDs within THIS vertical slice only.]
## ✅ Acceptance Criteria (BDD Style)
- **Scenario**: [B-ID / AB-ID title — from §4.2 / §4.3 rows covered by this slice per SPEC §4.5 column 3.]
- **Given** [Given column]
- **When** [When column]
- **Then** [Then column]
Step 3: Epic Decomposition (if applicable)
If Epic structure is chosen:
- Parent Ticket: Contains a high-level description, Goals, and a Task Graph (Mermaid) showing execution order and critical path. Parent MUST explicitly list the vertical slice IDs:
F0 → F1 → F2 → ... → FNas nodes. F0 is ALWAYS the first node, marked critical path. - Sub-tasks:
- PROHIBITED ANTI-PATTERN (HARD FAIL if detected): NEVER group B-IDs into layer-based logical tasks such as "Data Layer", "API Layer", "UI Layer", "Models only", "Routes only", "Pages only". If keywords
data layer|api layer|ui layer|models|create all|build all endpoints|design all pages(case-insensitive) appear in ANY sub-task title or description AND no EXPLICIT_OVERRIDE_HORIZONTAL_PLAN logged → HARD REJECT decomposition, log attempt[HORIZONTAL_TICKET_BLOCKED]in decisions.log with timestamp + spec_slug + bad_task_title, require user confirmation or override insertion into SPEC §2 before retry. - CANONICAL DECOMPOSITION (MANDATORY): Group B-IDs EXACTLY ONE SUB-TASK PER VERTICAL SLICE from SPEC §4.5 table. Order = F0 first, then F1, F2, ... FN. Each sub-task title PREFIX =
[<slice_id>](e.g. "[F0] Tracer: Save Event → Dashboard Return"). Each sub-task inherits BDD scenarios ONLY from the B-IDs listed in that slice's "B-IDs / AB-IDs Covered" column of §4.5. NEVER mix B-IDs from 2 different slices into one sub-task unless EXPLICIT_OVERRIDE. - Each sub-task gets its own ticket with the Step 2 template above. Vertical Slice Ref field MUST be filled with the EXACT slice ID.
- Dependencies: Establish "blocked by" relations ONLY between consecutive vertical slices:
F0 blocks F1 → F1 blocks F2 → .... NEVER create "API blocks UI" layer-style dependencies. If a slice legitimately depends on a previous slice's DB migration or route schema — the dependency is slice-to-slice (vertical), not layer-to-layer. Dependencies that cross slices horizontally (e.g. "all DB must be done first") are PROHIBITED unless the parent ticket contains EXPLICIT_OVERRIDE_HORIZONTAL_PLAN justification verbatim AND decision.log entry exists.
- PROHIBITED ANTI-PATTERN (HARD FAIL if detected): NEVER group B-IDs into layer-based logical tasks such as "Data Layer", "API Layer", "UI Layer", "Models only", "Routes only", "Pages only". If keywords
Step 4: External Tool Execution
- Ask user for:
- Target Tool: Linear (Recommended), ClickUp, or Jira.
- Project/Board: Where the tickets should live.
- Language: English (Default).
- Call appropriate tool (e.g.,
save_issuefor Linear,clickup_create_taskfor ClickUp). - If creating an Epic, save the Parent first to get its ID, then set
parentIdfor sub-tasks.
§2 RETURN VALUES
Print the results of the creation:
PLAN_STRUCTURE=Single|EpicPARENT_TICKET_ID=<id>SUBTASKS_COUNT=<count>TOOL_URL=<link-to-tickets>
§3 QUALITY GATES
- BDD Check: Every sub-task MUST have at least one B-ID or AB-ID mapped to a BDD scenario.
- Dependency Check: Epic MUST have at least one dependency link between sub-tasks if
count > 1. - Language Consistency: Do not mix languages in the same field.
- Simplicity Bias Check (engineering-contracts §1): Prefer the smallest slice that delivers the behaviour; do NOT split or add sub-tasks for completeness. A sub-task MUST NOT carry edge cases the SPEC §1 Non-goals deferred by design.
- 🔴 Gate #4: Vertical Decomposition Compliance (G-VS-2 — CANONICAL #0): Run ALL 5 sub-checks below. Any fail → HARD STOP before tool tickets are created; return structured error to user.
- Every sub-task has Vertical Slice Ref filled: Parse
> **🔴 Vertical Slice Ref (CANONICAL #0)**:line in every ticket template. If any is empty,TODO, or does not match a valid ID from SPEC §4.5 table → FAIL: "Sub-task TITLE missing or invalid Vertical Slice Ref. Must be exactly F0 or F1..FN from the approved SPEC §4.5 VERTICAL SLICES table." - Sub-task count = SPEC slice count: If Epic structure: count of sub-tasks generated MUST EQUAL count of non-empty rows in SPEC §4.5 VERTICAL SLICES table. If override case (H-OVERRIDE tickets): slice count may be ≤ 1 per H-OVERRIDE-* tag suffix. Otherwise FAIL: "Number of sub-tasks ($N) ≠ number of slices in §4.5 table ($M). 1 sub-task per vertical slice is the canonical rule. Either add the missing slices to §4.5 table in SPEC or declare override."
- No single-layer sub-tasks without override: Parse each sub-task Layers Touched line. Split on separator
·or,. Count distinct top-level path prefixes. If any sub-task has distinct_layers < 2 AND the sub-task title/description does NOT contain suffix-H-OVERRIDE-→ FAIL with: "Sub-task [$slice_ref] has only $distinct_layers layer(s) touched — this is horizontal decomposition disguised as slice. Either add at least 1 more architectural layer (UI + API, or API + DB, etc.) OR declare EXPLICIT_OVERRIDE_HORIZONTAL_PLAN in SPEC §2, re-approve SPEC, re-run /che-plan." - F0 is first, critical path true: If Epic structure → first generated sub-task is F0 (sorted order), AND Parent ticket Task Graph Mermaid has F0 as entry node, AND F0 dependencies = 0 (blocks all others). FAIL: "F0 (Tracer) MUST be the first sub-task in execution order with no blockers. Any other task depends on F0 being green (vertical plumbing proven)."
- No layer-based keywords without override: Keyword scan all sub-task titles + descriptions for regex
(Data Layer|API Layer|UI Layer|all models|create all|build all endpoints|all pages first|schema first then). If any hit AND SPEC §2 does NOT containEXPLICIT_OVERRIDE_HORIZONTAL_PLAN:literal → FAIL with: "Layer-based anti-pattern keywords detected in sub-task. Use canonical decomposition: 1 sub-task per F0..FN vertical slice from §4.5 SPEC table. Each slice touches ≥2 layers. Override only possible via EXPLICIT_OVERRIDE_HORIZONTAL_PLAN + decision.log."
- Every sub-task has Vertical Slice Ref filled: Parse
- 🔴 Gate #5: Canonical Trio Propagation Compliance (Reversibility + DbC + DRY — CANONICAL #1/#3): Any sub-task generated for a scope where V19/V20/V21 TRIGGER fired MUST have the 3 new header rows filled (non-empty, not "TODO", not "-" unless genuinely N/A). Enforce:
- Reversibility (CANONICAL #1) gate: If SPEC has ≥ 1 row in §4.6.1 Wrapper Boundary (V19a), and a sub-task's "Files Affected" list (from §4.5 Layers / Files TOUCHED column, filtered by slice) intersects ANY wrapper glob file → "🔵 Wrapper Boundaries Touched" row MUST list at least 1 wrapper glob + SDK name. If EMPTY → FAIL: "Sub-task [$slice_id] touches files inside wrapper boundary(s) listed in §4.6.1 but header row 🔵 is empty. Must list which wrapper + SDK(s) are affected."
- DbC Assertions (CANONICAL #3) gate: If B_COUNT ≥ 3 (V20 TRIGGER fired) AND sub-task's B-IDs touch rows in §4.7 whose column 3 ("Where Enforced") paths overlap with this slice's file list → "🟣 Assertion IDs Delivered" row MUST list ≥ 1 A-N assertion ID. If EMPTY → FAIL: "Sub-task touches code paths of assertions from §4.7 but header 🟣 is empty. List A-IDs implemented or refactor so assertion enforcement is delivered in THIS slice (not delayed)."
- DRY Knowledge (V21) gate: If B_COUNT ≥ 5 (V21 TRIGGER fired) AND sub-task's file list intersects §4.8 col 2 "Authoritative Single-Source Absolute Path" paths for ≥ 1 business rule → "🟤 DRY Rules Touched" row MUST list ≥ 1 rule. If EMPTY → FAIL: "Sub-task edits the Authoritative Single-Source for a DRY business rule listed in §4.8 but header 🟤 is empty. List it so downstream consumers are alerted in PR review."