jdi-cli 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +6 -0
  2. package/core/agents/jdi-architect.md +19 -0
  3. package/core/agents/jdi-researcher.md +2 -1
  4. package/core/commands/jdi-add-phase.md +171 -0
  5. package/core/commands/jdi-remove-phase.md +228 -0
  6. package/core/skills/clean-architecture/SKILL.md +134 -0
  7. package/core/skills/ddd/SKILL.md +140 -0
  8. package/core/skills/hexagonal/SKILL.md +127 -0
  9. package/core/skills/onion/SKILL.md +133 -0
  10. package/core/skills/the-method/SKILL.md +139 -0
  11. package/core/skills/vertical-slice/SKILL.md +127 -0
  12. package/package.json +1 -1
  13. package/runtimes/antigravity/agents.md +4 -0
  14. package/runtimes/antigravity/skills/clean-architecture/SKILL.md +125 -0
  15. package/runtimes/antigravity/skills/ddd/SKILL.md +131 -0
  16. package/runtimes/antigravity/skills/hexagonal/SKILL.md +118 -0
  17. package/runtimes/antigravity/skills/jdi-add-phase/SKILL.md +171 -0
  18. package/runtimes/antigravity/skills/jdi-architect/SKILL.md +19 -0
  19. package/runtimes/antigravity/skills/jdi-remove-phase/SKILL.md +228 -0
  20. package/runtimes/antigravity/skills/jdi-researcher/SKILL.md +2 -1
  21. package/runtimes/antigravity/skills/onion/SKILL.md +124 -0
  22. package/runtimes/antigravity/skills/the-method/SKILL.md +130 -0
  23. package/runtimes/antigravity/skills/vertical-slice/SKILL.md +118 -0
  24. package/runtimes/claude/CLAUDE.md +4 -0
  25. package/runtimes/claude/agents/jdi-architect.md +19 -0
  26. package/runtimes/claude/agents/jdi-researcher.md +2 -1
  27. package/runtimes/claude/commands/jdi-add-phase.md +171 -0
  28. package/runtimes/claude/commands/jdi-remove-phase.md +228 -0
  29. package/runtimes/claude/skills/clean-architecture/SKILL.md +120 -0
  30. package/runtimes/claude/skills/ddd/SKILL.md +125 -0
  31. package/runtimes/claude/skills/hexagonal/SKILL.md +112 -0
  32. package/runtimes/claude/skills/onion/SKILL.md +119 -0
  33. package/runtimes/claude/skills/the-method/SKILL.md +124 -0
  34. package/runtimes/claude/skills/vertical-slice/SKILL.md +113 -0
  35. package/runtimes/copilot/agents/jdi-architect.agent.md +19 -0
  36. package/runtimes/copilot/agents/jdi-researcher.agent.md +2 -1
  37. package/runtimes/copilot/copilot-instructions.md +4 -0
  38. package/runtimes/copilot/prompts/jdi-add-phase.prompt.md +171 -0
  39. package/runtimes/copilot/prompts/jdi-remove-phase.prompt.md +228 -0
  40. package/runtimes/opencode/AGENTS.md +4 -0
  41. package/runtimes/opencode/agents/jdi-architect.md +19 -0
  42. package/runtimes/opencode/agents/jdi-researcher.md +2 -1
  43. package/runtimes/opencode/commands/jdi-add-phase.md +171 -0
  44. package/runtimes/opencode/commands/jdi-remove-phase.md +228 -0
  45. package/runtimes/opencode/skills/clean-architecture/SKILL.md +120 -0
  46. package/runtimes/opencode/skills/ddd/SKILL.md +125 -0
  47. package/runtimes/opencode/skills/hexagonal/SKILL.md +112 -0
  48. package/runtimes/opencode/skills/onion/SKILL.md +119 -0
  49. package/runtimes/opencode/skills/the-method/SKILL.md +124 -0
  50. package/runtimes/opencode/skills/vertical-slice/SKILL.md +113 -0
package/README.md CHANGED
@@ -27,6 +27,10 @@ Full-blown AI workflows (33+ agents, 60+ commands, 100+ subworkflows) burn token
27
27
  /jdi-do <N> <- execute via doer specialist (SUMMARY.md)
28
28
  /jdi-verify <N> <- gates via reviewer (REVIEW.md)
29
29
  /jdi-ship <N> <- update ROADMAP, advance phase
30
+
31
+ # Roadmap mutation (run anytime)
32
+ /jdi-add-phase "<name>" <- append (or --at <pos>) a new phase
33
+ /jdi-remove-phase <N> <- remove a future/pending phase
30
34
  ```
31
35
 
32
36
  ### Brownfield (existing project)
@@ -527,6 +531,8 @@ See [AGENTS.md](AGENTS.md) for full details.
527
531
  | `/jdi-do <N>` | phase number | `--sequential` (force sequential execution even if waves permit parallel) | Execute tasks via doer specialist(s) → SUMMARY.md |
528
532
  | `/jdi-verify <N>` | phase number | — | Run reviewer specialist gates → REVIEW.md (verdict APPROVED / APPROVED_WITH_WARNINGS / BLOCKED) |
529
533
  | `/jdi-ship <N>` | phase number | — | Update ROADMAP, advance phase. Gates: verdict must not be BLOCKED |
534
+ | `/jdi-add-phase "<name>"` | phase name (required) | `--goal "<text>"`, `--at <pos>`, `--reason "<text>"` | Append (or insert at position) a new phase in ROADMAP.md. Bumps `total_phases`. Cannot insert at or before `current_phase`. |
535
+ | `/jdi-remove-phase <N>` | phase number (required) | `--force` (required if artifacts exist) | Remove a future or pending phase. Refuses for `done`, current, or past phases. Archives existing artifacts to `.jdi/archive/removed-<NN-slug>/`. Numbers are NOT renumbered (preserves history). |
530
536
 
531
537
  **Brownfield entry (1):**
532
538
 
@@ -411,13 +411,29 @@ Write to `.jdi/agents/jdi-reviewer-{slug}.md`.
411
411
 
412
412
  After writing doer/reviewer, inject `<skills_to_load>` block after `</role>` via Edit.
413
413
 
414
+ **Code-design skill (mandatory) — resolve from `PROJECT.md.Code Design` (LOCKED value) using this mapping:**
415
+
416
+ | Code Design (PROJECT.md) | Skill to load |
417
+ |---|---|
418
+ | The Method | `the-method` |
419
+ | DDD | `ddd` |
420
+ | Clean Architecture | `clean-architecture` |
421
+ | Hexagonal | `hexagonal` |
422
+ | Onion | `onion` |
423
+ | Vertical Slice | `vertical-slice` |
424
+
425
+ The resolved code-design skill is loaded by **both doer and reviewer**. Exactly one code-design skill is loaded. Never load two code-design skills simultaneously — the project uses exactly one design. If the mapping cannot resolve, abort with an error and ask the user to fix `PROJECT.md.Code Design`.
426
+
414
427
  **Doer — always:**
415
428
  ```markdown
416
429
  <skills_to_load>
417
430
  - solid — before creating classes/modules/interfaces. Detects god class, large switches, deep inheritance, dep on concretes.
431
+ - {CODE_DESIGN_SKILL} — INVIOLABLE structural rules for the project's locked code design. Apply on every file created.
418
432
  </skills_to_load>
419
433
  ```
420
434
 
435
+ Replace `{CODE_DESIGN_SKILL}` with the resolved entry from the mapping above (e.g. `the-method`, `ddd`, `clean-architecture`, `hexagonal`, `onion`, `vertical-slice`).
436
+
421
437
  If `has_frontend=true`, append:
422
438
  ```markdown
423
439
  - frontend-rules — when task touches .tsx/.vue/.svelte/.razor/.cshtml/.html/.twig/.erb/.blade.php. WCAG 2.2 AA + UX.
@@ -430,9 +446,12 @@ If `has_frontend=true`, append:
430
446
  - kiss — gate 5: over-engineering — interface with 1 impl, factory for new(), pass-through, deep inheritance.
431
447
  - yagni — gate 5: speculative code — optional params never passed, TODO without ticket, generic with 1 type.
432
448
  - clean-code — bad names, long functions, magic numbers, silent catch, boolean params, redundant comments.
449
+ - {CODE_DESIGN_SKILL} — gate 5: enforce INVIOLABLE structural rules for the project's locked code design. BLOCKED on violations defined by the skill.
433
450
  </skills_to_load>
434
451
  ```
435
452
 
453
+ Replace `{CODE_DESIGN_SKILL}` with the same resolved entry — both doer and reviewer load the SAME code-design skill.
454
+
436
455
  If `has_frontend=true`, append:
437
456
  ```markdown
438
457
  - frontend-rules — gate 5 frontend: <input> without label, button without aria-label, localStorage with token, outline removed.
@@ -90,10 +90,11 @@ Options:
90
90
  - Vertical Slice
91
91
  - Clean Architecture
92
92
  - Hexagonal (Ports & Adapters)
93
+ - Onion Architecture
93
94
  - The Method (Juval Löwy)
94
95
  - "Don't know, suggest" (-> recommend based on type + stack)
95
96
 
96
- Locked for the life of the project (global rule).
97
+ Locked for the life of the project (global rule). Mutually exclusive — the project uses exactly ONE code design. The choice is enforced by a JDI skill loaded into doer + reviewer (one of: `ddd`, `vertical-slice`, `clean-architecture`, `hexagonal`, `onion`, `the-method`).
97
98
 
98
99
  **Q4 — MVP scope**
99
100
  "Which minimum features for the MVP? (comma-separated)"
@@ -0,0 +1,171 @@
1
+ ---
2
+ name: jdi-add-phase
3
+ description: Adds a new phase to ROADMAP.md. Append at end (default) or insert at a specific position. Bumps total_phases. Atomic commit.
4
+ argument_hint: "\"<phase name>\" [--goal \"<goal>\"] [--at <position>]"
5
+ runtime_intent:
6
+ invokes_agent: none
7
+ runtime_overrides:
8
+ claude:
9
+ allowed-tools: [Read, Write, Edit, Bash, Grep, Glob, AskUserQuestion]
10
+ copilot:
11
+ tools: [read, write, edit, grep, glob, terminal]
12
+ opencode:
13
+ subtask: true
14
+ antigravity:
15
+ triggers:
16
+ - "/jdi-add-phase"
17
+ - "add new phase"
18
+ - "create phase"
19
+ ---
20
+
21
+ <objective>
22
+ Adds a new phase to the project's roadmap. Edits `.jdi/ROADMAP.md`. Does not start the phase — only registers it. The user advances via `/jdi-discuss <N>` when ready.
23
+ </objective>
24
+
25
+ <arguments>
26
+ - `name` (required) — short phase name. Quote if it contains spaces.
27
+ - `--goal "<text>"` (optional) — 1-line description of what the phase delivers. If missing, AskUserQuestion will prompt.
28
+ - `--at <position>` (optional) — insert at this position instead of appending. Existing phases at and after `<position>` shift down by 1 (renumbered in ROADMAP only — slugs stay the same in any existing `.jdi/phases/` folders). Default: append.
29
+
30
+ Examples:
31
+ - `/jdi-add-phase "User authentication" --goal "Login + signup + JWT"`
32
+ - `/jdi-add-phase "Performance pass" --at 3`
33
+ - `/jdi-add-phase "Hotfix N+1 query"`
34
+ </arguments>
35
+
36
+ <process>
37
+
38
+ ### Step 1: Validation
39
+ ```bash
40
+ test -d .jdi/ || { echo "Not a JDI project. /jdi-new first."; exit 1; }
41
+ test -f .jdi/ROADMAP.md || { echo "ROADMAP.md missing."; exit 1; }
42
+ test -f .jdi/STATE.md || { echo "STATE.md missing."; exit 1; }
43
+ ```
44
+
45
+ If `<name>` argument missing: AskUserQuestion "Phase name?" (free text). Required.
46
+
47
+ If `--goal` flag missing: AskUserQuestion "Phase goal (1 line)?" (free text). Required.
48
+
49
+ ### Step 2: Compute phase number + slug
50
+
51
+ Read `total_phases` from `.jdi/ROADMAP.md`:
52
+
53
+ ```bash
54
+ TOTAL=$(grep -oE 'total_phases:\s*[0-9]+' .jdi/ROADMAP.md | grep -oE '[0-9]+')
55
+ ```
56
+
57
+ PowerShell:
58
+ ```powershell
59
+ $total = (Select-String -Path .jdi/ROADMAP.md -Pattern 'total_phases:\s*([0-9]+)').Matches[0].Groups[1].Value -as [int]
60
+ ```
61
+
62
+ If `--at <pos>` provided, validate `1 <= pos <= total + 1`. Otherwise `pos = total + 1` (append).
63
+
64
+ If `pos <= current_phase` (read from STATE.md), abort with error: "Cannot insert before current phase {current}. Use --at {current+1} or higher."
65
+
66
+ Generate `slug` from `name`:
67
+ - Lowercase
68
+ - Replace accents (à → a, é → e, ç → c, ñ → n)
69
+ - Non-alphanumeric → `-`
70
+ - Collapse repeated `-`, strip leading/trailing `-`
71
+ - Truncate to 40 chars
72
+
73
+ Phase identifier prefix is the 2-digit position (`NN`): `01`, `02`, ..., zero-padded.
74
+
75
+ ### Step 3: Renumber prefix on shift (only if --at)
76
+
77
+ If `--at <pos>` shifts existing phases:
78
+
79
+ Edit `.jdi/ROADMAP.md` — for every existing `### Phase K:` where `K >= pos`, change to `### Phase K+1:` and bump its `**Slug:**` prefix from `KK-...` to `(K+1)(K+1)-...`.
80
+
81
+ **WARNING (printed):**
82
+ > "Renumbering ROADMAP phases. Any existing `.jdi/phases/<NN-slug>/` folders are NOT renamed — they keep their original slugs and become "history". New work in renumbered phases creates new folders. Commits referencing old `phase {K}` remain valid as history."
83
+
84
+ This is intentional. Do not rename `.jdi/phases/` folders — would break commit history and cross-references in DECISIONS.md.
85
+
86
+ If `--at` not provided (append), skip Step 3.
87
+
88
+ ### Step 4: Append phase section to ROADMAP.md
89
+
90
+ If appending (`pos == total + 1`), append at the bottom of `## Phases`:
91
+
92
+ ```markdown
93
+
94
+ ### Phase {pos}: {name}
95
+ - **Slug:** {NN}-{slug}
96
+ - **Status:** pending
97
+ - **Goal:** {goal}
98
+ ```
99
+
100
+ If inserting (`pos <= total`), insert the new section BEFORE the section that previously had number `pos` (now renumbered to `pos+1`).
101
+
102
+ ### Step 5: Bump total_phases
103
+
104
+ Edit `.jdi/ROADMAP.md`:
105
+ ```
106
+ total_phases: {TOTAL + 1}
107
+ ```
108
+
109
+ ### Step 6: Audit trail in DECISIONS.md (optional, only if user passes --reason)
110
+
111
+ Not required. If user wants to record why this phase was added mid-project, they pass `--reason "<text>"`. When present, append to `.jdi/DECISIONS.md`:
112
+
113
+ ```markdown
114
+ D-{N+1} ({date}, phase {pos}): Phase added mid-project. Reason: {reason}
115
+ ```
116
+
117
+ (N = current max D-X.)
118
+
119
+ ### Step 7: Commit
120
+
121
+ ```bash
122
+ git add .jdi/ROADMAP.md .jdi/DECISIONS.md 2>/dev/null
123
+ git commit -m "chore(jdi): add phase {pos} {NN-slug}"
124
+ ```
125
+
126
+ PowerShell:
127
+ ```powershell
128
+ git add .jdi/ROADMAP.md .jdi/DECISIONS.md 2>$null
129
+ git commit -m "chore(jdi): add phase $pos $NN-$slug"
130
+ ```
131
+
132
+ ### Step 8: Confirm
133
+
134
+ ```
135
+ Phase {pos}: {name} added.
136
+ Slug: {NN}-{slug}
137
+ Goal: {goal}
138
+ Status: pending
139
+ total_phases: {TOTAL + 1}
140
+
141
+ Next: /jdi-discuss {pos} (when ready to start this phase)
142
+ ```
143
+
144
+ </process>
145
+
146
+ <gates>
147
+ - pre: `.jdi/ROADMAP.md` + `.jdi/STATE.md` exist
148
+ - pre: `--at <pos>` (if used) is greater than `current_phase` in STATE.md
149
+ - post: ROADMAP.md has new phase section + bumped total_phases + atomic commit
150
+ </gates>
151
+
152
+ <errors>
153
+ - `.jdi/` missing -> "Run /jdi-new first"
154
+ - `--at <pos>` <= current_phase -> "Cannot insert before current phase. Use --at {current+1} or higher."
155
+ - `--at <pos>` < 1 or > total+1 -> "Position out of range. Valid: 1..{total+1}"
156
+ - Phase name empty -> AskUserQuestion to fill
157
+ - Goal empty -> AskUserQuestion to fill
158
+ </errors>
159
+
160
+ <runtime_notes>
161
+
162
+ **Claude Code:**
163
+ - AskUserQuestion handles missing args interactively.
164
+
165
+ **Copilot:**
166
+ - AskUserQuestion not always available — read missing args from prompt body or fail with clear error.
167
+
168
+ **OpenCode/Antigravity:**
169
+ - Same interactive flow as Claude when supported. Otherwise fail with clear error message asking the user to re-invoke with all args.
170
+
171
+ </runtime_notes>
@@ -0,0 +1,228 @@
1
+ ---
2
+ name: jdi-remove-phase
3
+ description: Removes a phase from ROADMAP.md. Refuses to remove done phases or the current phase. Archives any existing phase artifacts. Atomic commit.
4
+ argument_hint: "<phase_number> [--force]"
5
+ runtime_intent:
6
+ invokes_agent: none
7
+ runtime_overrides:
8
+ claude:
9
+ allowed-tools: [Read, Write, Edit, Bash, Grep, Glob, AskUserQuestion]
10
+ copilot:
11
+ tools: [read, write, edit, grep, glob, terminal]
12
+ opencode:
13
+ subtask: true
14
+ antigravity:
15
+ triggers:
16
+ - "/jdi-remove-phase"
17
+ - "remove phase"
18
+ - "delete phase"
19
+ ---
20
+
21
+ <objective>
22
+ Removes a phase from `.jdi/ROADMAP.md`. Refuses to remove the current phase or any phase already shipped. If the phase has artifacts under `.jdi/phases/<NN-slug>/`, moves them to `.jdi/archive/removed-<NN-slug>/` instead of deleting (preserves history).
23
+ </objective>
24
+
25
+ <arguments>
26
+ - `phase_number` (required) — number of the phase to remove (as listed in ROADMAP.md).
27
+ - `--force` (optional) — required when removing a phase that has any artifacts in `.jdi/phases/`. Without `--force`, the command refuses and explains.
28
+
29
+ Examples:
30
+ - `/jdi-remove-phase 4`
31
+ - `/jdi-remove-phase 5 --force`
32
+ </arguments>
33
+
34
+ <process>
35
+
36
+ ### Step 1: Validation
37
+
38
+ ```bash
39
+ test -d .jdi/ || { echo "Not a JDI project."; exit 1; }
40
+ test -f .jdi/ROADMAP.md || { echo "ROADMAP.md missing."; exit 1; }
41
+ test -f .jdi/STATE.md || { echo "STATE.md missing."; exit 1; }
42
+
43
+ # Argument required
44
+ [ -n "$1" ] || { echo "Phase number required. Usage: /jdi-remove-phase <N> [--force]"; exit 1; }
45
+ ```
46
+
47
+ Parse `phase_number` (positional). Parse `--force` flag.
48
+
49
+ ### Step 2: Read state
50
+
51
+ ```bash
52
+ CURRENT=$(grep -oE 'current_phase:\s*[0-9]+' .jdi/STATE.md | grep -oE '[0-9]+')
53
+ TOTAL=$(grep -oE 'total_phases:\s*[0-9]+' .jdi/ROADMAP.md | grep -oE '[0-9]+')
54
+ PHASE_NUMBER=$1
55
+ ```
56
+
57
+ PowerShell:
58
+ ```powershell
59
+ $current = (Select-String -Path .jdi/STATE.md -Pattern 'current_phase:\s*([0-9]+)').Matches[0].Groups[1].Value -as [int]
60
+ $total = (Select-String -Path .jdi/ROADMAP.md -Pattern 'total_phases:\s*([0-9]+)').Matches[0].Groups[1].Value -as [int]
61
+ $phaseNumber = [int]$args[0]
62
+ ```
63
+
64
+ ### Step 3: Hard refuses (no override)
65
+
66
+ ```bash
67
+ # Must be in range
68
+ if [ "$PHASE_NUMBER" -lt 1 ] || [ "$PHASE_NUMBER" -gt "$TOTAL" ]; then
69
+ echo "Phase $PHASE_NUMBER does not exist. Valid: 1..$TOTAL"
70
+ exit 1
71
+ fi
72
+
73
+ # Cannot remove past phases (preserves history)
74
+ if [ "$PHASE_NUMBER" -lt "$CURRENT" ]; then
75
+ echo "Cannot remove phase $PHASE_NUMBER — already past. current_phase is $CURRENT. Past phases are immutable history."
76
+ exit 1
77
+ fi
78
+
79
+ # Cannot remove the current phase
80
+ if [ "$PHASE_NUMBER" -eq "$CURRENT" ]; then
81
+ echo "Cannot remove the current phase ($CURRENT). Ship or abandon it first, then advance current_phase."
82
+ exit 1
83
+ fi
84
+ ```
85
+
86
+ Read the phase's `Status:` from ROADMAP:
87
+
88
+ ```bash
89
+ STATUS=$(awk "/### Phase $PHASE_NUMBER:/,/^### Phase /" .jdi/ROADMAP.md | grep -oE 'Status:\*\* (pending|ready|done|partial|blocked|in-progress)' | head -1 | awk '{print $2}')
90
+ ```
91
+
92
+ If `STATUS == done`: refuse hard.
93
+ ```
94
+ Phase $PHASE_NUMBER is `done`. Cannot remove. Shipped phases are immutable history.
95
+ ```
96
+
97
+ ### Step 4: Detect artifacts
98
+
99
+ Find the phase folder under `.jdi/phases/`:
100
+
101
+ ```bash
102
+ NN=$(printf '%02d' "$PHASE_NUMBER")
103
+ PHASE_DIR=$(ls -d .jdi/phases/${NN}-*/ 2>/dev/null | head -1 || true)
104
+ ```
105
+
106
+ PowerShell:
107
+ ```powershell
108
+ $nn = '{0:D2}' -f $phaseNumber
109
+ $phaseDir = Get-ChildItem .jdi/phases/ -Directory -Filter "$nn-*" -ErrorAction SilentlyContinue | Select-Object -First 1
110
+ ```
111
+
112
+ If `PHASE_DIR` exists AND `--force` NOT passed: refuse.
113
+ ```
114
+ Phase $PHASE_NUMBER has artifacts in $PHASE_DIR (CONTEXT/PLAN/SUMMARY/REVIEW).
115
+ Re-run with --force to archive these artifacts to .jdi/archive/removed-<NN-slug>/ and proceed.
116
+ ```
117
+
118
+ ### Step 5: Confirm with user (irreversible-ish action)
119
+
120
+ AskUserQuestion (always run, even with --force):
121
+
122
+ > "Remove phase $PHASE_NUMBER: '$PHASE_NAME'?
123
+ >
124
+ > Status: $STATUS
125
+ > Artifacts: ${PHASE_DIR:-none}
126
+ > Action: ROADMAP section removed, total_phases decremented, artifacts (if any) moved to .jdi/archive/removed-<NN-slug>/."
127
+ >
128
+ > Options:
129
+ > - [Yes, remove]
130
+ > - [Cancel]
131
+
132
+ If "Cancel" -> exit clean.
133
+
134
+ ### Step 6: Archive artifacts (if any)
135
+
136
+ ```bash
137
+ if [ -n "$PHASE_DIR" ]; then
138
+ mkdir -p .jdi/archive
139
+ test -f .jdi/archive/index.md || echo "# Archive index" > .jdi/archive/index.md
140
+
141
+ BASENAME=$(basename "$PHASE_DIR")
142
+ TARGET=".jdi/archive/removed-$BASENAME"
143
+ mv "$PHASE_DIR" "$TARGET"
144
+ echo "- removed-$BASENAME (removed $(date -u +%F) via /jdi-remove-phase)" >> .jdi/archive/index.md
145
+ fi
146
+ ```
147
+
148
+ PowerShell:
149
+ ```powershell
150
+ if ($phaseDir) {
151
+ if (-not (Test-Path .jdi/archive)) { New-Item -ItemType Directory .jdi/archive | Out-Null }
152
+ if (-not (Test-Path .jdi/archive/index.md)) { Set-Content .jdi/archive/index.md "# Archive index" }
153
+ $basename = $phaseDir.Name
154
+ $target = ".jdi/archive/removed-$basename"
155
+ Move-Item $phaseDir.FullName $target
156
+ Add-Content .jdi/archive/index.md "- removed-$basename (removed $(Get-Date -Format 'yyyy-MM-dd') via /jdi-remove-phase)"
157
+ }
158
+ ```
159
+
160
+ ### Step 7: Edit ROADMAP.md
161
+
162
+ Remove the entire `### Phase $PHASE_NUMBER: ...` block (header + bullets) up to (but not including) the next `### Phase ` line or end of file.
163
+
164
+ Decrement `total_phases`:
165
+ ```
166
+ total_phases: {TOTAL - 1}
167
+ ```
168
+
169
+ **Do NOT renumber** subsequent phases. Phases after the removed one keep their original numbers. This preserves all references in commit history, `DECISIONS.md`, and archived phase folders. The roadmap simply has a gap (e.g., 1, 2, 3, 5, 6 — 4 was removed).
170
+
171
+ ### Step 8: Audit trail in DECISIONS.md
172
+
173
+ Append:
174
+ ```markdown
175
+ D-{N+1} ({date}): Phase $PHASE_NUMBER removed via /jdi-remove-phase. Artifacts: ${PHASE_DIR:+archived to .jdi/archive/removed-<NN-slug>/}{none if empty}.
176
+ ```
177
+
178
+ ### Step 9: Commit
179
+
180
+ ```bash
181
+ git add .jdi/ROADMAP.md .jdi/DECISIONS.md .jdi/archive/ 2>/dev/null
182
+ git commit -m "chore(jdi): remove phase {PHASE_NUMBER}"
183
+ ```
184
+
185
+ ### Step 10: Confirm
186
+
187
+ ```
188
+ Phase {PHASE_NUMBER} removed.
189
+ {if artifacts:} Artifacts archived: .jdi/archive/removed-{NN-slug}/
190
+ total_phases: {TOTAL - 1}
191
+
192
+ Note: phase numbers are not renumbered — references in commits, DECISIONS, and archive remain valid.
193
+ ```
194
+
195
+ </process>
196
+
197
+ <gates>
198
+ - pre: `.jdi/ROADMAP.md` + `.jdi/STATE.md` exist
199
+ - pre: `phase_number` is in range `1..total_phases`
200
+ - pre: `phase_number > current_phase`
201
+ - pre: phase status != `done`
202
+ - pre: `--force` provided when phase has artifacts
203
+ - post: ROADMAP.md section removed + total_phases decremented + artifacts archived (if any) + DECISIONS.md appended + atomic commit
204
+ </gates>
205
+
206
+ <errors>
207
+ - `.jdi/` missing -> "Run /jdi-new first"
208
+ - `phase_number` missing -> usage hint
209
+ - `phase_number` out of range -> "Valid: 1..{total}"
210
+ - `phase_number < current_phase` -> refuse (past = history)
211
+ - `phase_number == current_phase` -> refuse (ship or abandon first)
212
+ - phase status `done` -> refuse (shipped = history)
213
+ - artifacts exist + no `--force` -> refuse + suggest `--force`
214
+ - user cancels at AskUserQuestion -> exit clean
215
+ </errors>
216
+
217
+ <runtime_notes>
218
+
219
+ **Claude Code:**
220
+ - Confirms via AskUserQuestion.
221
+
222
+ **Copilot:**
223
+ - AskUserQuestion not always available — require explicit `--yes` flag as fallback.
224
+
225
+ **OpenCode/Antigravity:**
226
+ - Same interactive confirm as Claude. Fallback to `--yes` when prompts unsupported.
227
+
228
+ </runtime_notes>
@@ -0,0 +1,134 @@
1
+ ---
2
+ name: clean-architecture
3
+ description: Clean Architecture (Robert C. Martin). 4 concentric layers - Entities, Use Cases, Interface Adapters, Frameworks & Drivers. The Dependency Rule points strictly inward. Language-agnostic rigid rules. Mutually exclusive with The Method, DDD, Hexagonal, Onion, Vertical Slice.
4
+ type: skill
5
+ applies_to: |
6
+ Loaded by doer and reviewer when PROJECT.md `Code Design` is `Clean Architecture`.
7
+ Inviolable design rules. Doer applies during creation. Reviewer enforces at gate 5.
8
+ loaded_by:
9
+ - jdi-doer-{slug}
10
+ - jdi-reviewer-{slug}
11
+ runtime_overrides:
12
+ antigravity:
13
+ triggers:
14
+ - "Clean Architecture"
15
+ - "Robert Martin clean"
16
+ - "Dependency Rule"
17
+ - "Use Cases layer"
18
+ ---
19
+
20
+ # Skill: Clean Architecture
21
+
22
+ Rigid, inviolable rules from Robert C. Martin's *Clean Architecture*. The system is organized as **concentric layers**, and source-code dependencies point only **inward**.
23
+
24
+ Clean Architecture is the ONLY allowed design when PROJECT.md `Code Design: LOCKED: Clean Architecture`. Do not mix with The Method, DDD aggregates as a primary structure, Hexagonal terminology as the primary structure, Onion shells, or Vertical Slice feature folders as the primary structure.
25
+
26
+ ## The 4 layers (mandatory)
27
+
28
+ From innermost to outermost:
29
+
30
+ 1. **Entities (Enterprise Business Rules)** — the most general and high-level rules. Reusable across applications in the enterprise. Pure data + behavior. No knowledge of any other layer.
31
+ 2. **Use Cases (Application Business Rules)** — application-specific business rules. Orchestrate the dance of Entities to satisfy a use case. No knowledge of UI, DB, frameworks, devices, or external systems.
32
+ 3. **Interface Adapters** — convert data between the form most convenient for use cases/entities and the form most convenient for external agents. Controllers, Presenters, Gateways, ViewModels live here. No knowledge of frameworks beyond what is necessary to expose adapter contracts.
33
+ 4. **Frameworks & Drivers** — the outermost layer. Web framework, database, UI framework, file system, devices, external APIs. Glue code only — minimal logic.
34
+
35
+ Every code unit belongs to exactly one of these 4 layers. A unit that does not fit must be redesigned.
36
+
37
+ ## The Dependency Rule (inviolable)
38
+
39
+ **Source-code dependencies point only inward. Nothing in an inner circle may know anything at all about something in an outer circle.**
40
+
41
+ 1. Entities depend on nothing outside the Entities layer.
42
+ 2. Use Cases depend on Entities only. Use Cases do not import, reference, or know the names of anything in Interface Adapters or Frameworks & Drivers.
43
+ 3. Interface Adapters depend on Use Cases and Entities only. They do not depend on Frameworks & Drivers code directly — they depend on framework abstractions only where unavoidable, and never let framework types cross into the inner circles.
44
+ 4. Frameworks & Drivers depend on whatever is convenient (Adapters, libraries, vendor SDKs).
45
+ 5. Names defined in outer circles (e.g., entity names from a DB schema, DTOs from a controller, framework annotations) must not appear in inner-circle code.
46
+
47
+ ## Boundary Crossing rules (inviolable)
48
+
49
+ 1. **Cross boundaries via interfaces owned by the inner side.** Inputs into Use Cases are defined by interfaces in the Use Cases layer; implementations live in Interface Adapters.
50
+ 2. **Cross boundaries via Data Transfer Objects (DTOs) that are simple structures.** No framework objects, no ORM entities, no HTTP request objects cross a boundary.
51
+ 3. **Use Cases never receive framework-specific types** (HTTP request, ORM entity, file handle, socket). The Adapter translates these into the Use Case's input DTOs.
52
+ 4. **Use Cases return DTOs / output ports.** They never return entities directly to outer layers.
53
+ 5. **The Use Case interactor invokes an output port (interface) to deliver results.** The Presenter implements the output port. Use Cases never call presenters or controllers directly.
54
+
55
+ ## Layer purity rules (inviolable)
56
+
57
+ ### Entities
58
+
59
+ 1. Entities are pure. No imports from any other layer.
60
+ 2. Entities encapsulate enterprise-wide business rules; if a rule is application-specific, it does not belong here.
61
+ 3. Entities are not Database records, ORM models, JSON shapes, or API DTOs. If a class plays one of those roles, it is not an Entity.
62
+ 4. Entities have no annotations from persistence, serialization, or web frameworks.
63
+ 5. Entities are not anemic. Behavior lives with data.
64
+
65
+ ### Use Cases
66
+
67
+ 6. Each Use Case has a single, application-specific purpose stated by its name (verb-noun: e.g., `RegisterCustomer`, `RenewSubscription`).
68
+ 7. A Use Case owns its input port (input boundary) and output port (output boundary) as interfaces in the Use Cases layer.
69
+ 8. A Use Case does not import any framework, ORM, HTTP, file-system, or external-API type.
70
+ 9. A Use Case is testable without any infrastructure. If it cannot be tested without spinning up DB / HTTP / queue, the design is wrong.
71
+ 10. A Use Case orchestrates Entities. It does not duplicate enterprise rules that already live in Entities.
72
+
73
+ ### Interface Adapters
74
+
75
+ 11. Controllers translate external input (HTTP request, CLI args, message payload) into Use Case input DTOs and invoke the Use Case.
76
+ 12. Presenters convert Use Case output DTOs into a form suitable for delivery (ViewModel, response body).
77
+ 13. Gateways implement the persistence interfaces declared by the Use Cases.
78
+ 14. Adapters never contain business rules.
79
+ 15. Adapters depend inward on Use Cases / Entities, never outward on Frameworks.
80
+
81
+ ### Frameworks & Drivers
82
+
83
+ 16. Framework code is glue only. It wires Adapters to the framework runtime.
84
+ 17. Web framework controllers in the Frameworks layer call Adapters, not Use Cases directly.
85
+ 18. ORM-mapped models, framework annotations, configuration code, dependency injection wiring live here.
86
+
87
+ ## Composition rules
88
+
89
+ 1. **Composition Root is in the outermost layer.** The main / startup / DI container assembles all components.
90
+ 2. **Inner layers never construct outer layer types.** Dependencies are injected through interfaces defined by the inner layer.
91
+ 3. **Plug-in architecture.** A change in framework, DB, or UI must require changes only in the outer layers. Inner layers stay untouched.
92
+
93
+ ## Forbidden patterns (inviolable)
94
+
95
+ - **Use Cases referencing framework types** (HTTP request, ORM entity, file handle, vendor SDK type).
96
+ - **Entities referencing persistence frameworks** (ORM annotations, database column attributes that encode behavior).
97
+ - **Anemic Entities.** Behavior must accompany data.
98
+ - **Skipping a layer for convenience** (Controller calling a repository directly, Presenter calling the database).
99
+ - **Returning framework / ORM types from a Use Case.**
100
+ - **Use Case knowing the concrete Adapter** (e.g., calling a specific HTTP client class). Use Cases declare interfaces; Adapters implement.
101
+ - **Shared "Util" / "Helper" classes spanning layers** with hidden business rules.
102
+ - **Database-driven design** where the schema dictates Entity shape.
103
+ - **Cross-layer reach-around** (Framework code calling Use Cases bypassing Adapters, Adapters calling Frameworks bypassing the Composition Root).
104
+ - **Concentric layers reorganized as feature folders** that hide which layer a unit belongs to.
105
+
106
+ ## Reviewer enforcement (gate 5)
107
+
108
+ Reviewer rejects (BLOCKED) when:
109
+ - An Entity or Use Case imports a framework, ORM, HTTP, or vendor SDK type.
110
+ - A Use Case returns a framework / ORM / DTO defined in an outer layer.
111
+ - A Controller invokes persistence directly instead of going through a Use Case.
112
+ - An Adapter contains a business rule.
113
+ - An inner-layer file imports an outer-layer file (direct dependency violation).
114
+ - Boundary crossings carry framework-specific types instead of plain DTOs.
115
+ - Use Cases or Entities are not testable without infrastructure.
116
+
117
+ Reviewer warns (APPROVED_WITH_WARNINGS) when:
118
+ - A Use Case is named after a CRUD verb without application semantics.
119
+ - An Entity has only getters/setters (anemic).
120
+ - An Adapter file leaks framework annotations into its public interface.
121
+ - The Composition Root is split across layers instead of living in the outermost layer.
122
+
123
+ ## Anti-patterns
124
+
125
+ - "Service" layer mixing Use Cases with Adapter responsibilities
126
+ - DTOs leaking into Entities
127
+ - ORM entities serving as both Entity and persistence model
128
+ - Controller-with-business-logic
129
+ - Use Case classes that depend on framework annotations
130
+ - Hexagonal-style port terminology used to disguise a violation (the rule is the Dependency Rule, not the port naming)
131
+
132
+ ## Outputs
133
+
134
+ Does NOT produce own files. Modifies parent agent's structural decisions during code authoring and review.