learnship 1.9.21 → 1.9.22

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 (46) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.cursor-plugin/plugin.json +1 -1
  3. package/README.md +1 -1
  4. package/agents/learnship-debugger.md +1 -0
  5. package/agents/learnship-verifier.md +1 -0
  6. package/gemini-extension.json +1 -1
  7. package/learnship/agents/debugger.md +81 -25
  8. package/learnship/agents/verifier.md +80 -24
  9. package/learnship/references/planning-config.md +2 -2
  10. package/learnship/workflows/add-phase.md +5 -2
  11. package/learnship/workflows/add-tests.md +2 -0
  12. package/learnship/workflows/add-todo.md +1 -1
  13. package/learnship/workflows/audit-milestone.md +1 -0
  14. package/learnship/workflows/cleanup.md +1 -1
  15. package/learnship/workflows/complete-milestone.md +2 -1
  16. package/learnship/workflows/debug.md +2 -2
  17. package/learnship/workflows/diagnose-issues.md +1 -0
  18. package/learnship/workflows/discovery-phase.md +6 -0
  19. package/learnship/workflows/discuss-milestone.md +2 -1
  20. package/learnship/workflows/discuss-phase.md +2 -1
  21. package/learnship/workflows/execute-plan.md +1 -0
  22. package/learnship/workflows/health.md +40 -34
  23. package/learnship/workflows/insert-phase.md +2 -2
  24. package/learnship/workflows/ls.md +2 -2
  25. package/learnship/workflows/map-codebase.md +1 -1
  26. package/learnship/workflows/milestone-retrospective.md +2 -0
  27. package/learnship/workflows/new-milestone.md +1 -0
  28. package/learnship/workflows/new-project.md +15 -11
  29. package/learnship/workflows/next.md +1 -1
  30. package/learnship/workflows/pause-work.md +1 -1
  31. package/learnship/workflows/plan-milestone-gaps.md +3 -1
  32. package/learnship/workflows/plan-phase.md +1 -1
  33. package/learnship/workflows/progress.md +2 -2
  34. package/learnship/workflows/quick.md +5 -3
  35. package/learnship/workflows/release.md +3 -2
  36. package/learnship/workflows/remove-phase.md +1 -1
  37. package/learnship/workflows/research-phase.md +1 -1
  38. package/learnship/workflows/resume-work.md +3 -3
  39. package/learnship/workflows/set-profile.md +6 -6
  40. package/learnship/workflows/settings.md +1 -1
  41. package/learnship/workflows/sync-upstream-skills.md +1 -1
  42. package/learnship/workflows/transition.md +1 -1
  43. package/learnship/workflows/update.md +2 -1
  44. package/learnship/workflows/validate-phase.md +2 -1
  45. package/package.json +1 -1
  46. package/references/planning-config.md +2 -2
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "learnship",
3
3
  "description": "Agentic engineering done right — 42 structured workflows, persistent memory across sessions, integrated learning partner, and impeccable UI design system. Works with Claude Code, Windsurf, Cursor, Gemini CLI, OpenCode, and Codex.",
4
- "version": "1.9.21",
4
+ "version": "1.9.22",
5
5
  "author": {
6
6
  "name": "Favio Vazquez",
7
7
  "email": "favio.vazquezp@gmail.com"
@@ -2,7 +2,7 @@
2
2
  "name": "learnship",
3
3
  "displayName": "learnship",
4
4
  "description": "Agentic engineering done right — 42 structured workflows, persistent memory across sessions, integrated learning partner, and impeccable UI design system.",
5
- "version": "1.9.21",
5
+ "version": "1.9.22",
6
6
  "logo": "assets/logo.png",
7
7
  "author": {
8
8
  "name": "Favio Vazquez",
package/README.md CHANGED
@@ -84,7 +84,7 @@ It's probably overkill if you just need one-off scripts or quick fixes. Use `/qu
84
84
 
85
85
  ![Install learnship](assets/install.png)
86
86
 
87
- **Requirements:** Node.js ≥ 18 (installer only), Python 3 (workflows use it for cross-platform file checks), Git. All standard — you almost certainly have them already. [Details →](https://faviovazquez.github.io/learnship/getting-started/installation/#requirements)
87
+ **Requirements:** Node.js ≥ 18, Git. [Details →](https://faviovazquez.github.io/learnship/getting-started/installation/#requirements)
88
88
 
89
89
  **Via npm (all platforms — recommended):**
90
90
 
@@ -68,6 +68,7 @@ Identify the key files to check:
68
68
  ```bash
69
69
  # Find entry points, relevant modules
70
70
  grep -r "[key_term]" src/ --include="*.ts" --include="*.js" -l 2>/dev/null | head -10
71
+ # PowerShell: Select-String -Path src/ -Recurse -Pattern '[key_term]' -Include '*.ts','*.js' | Select-Object -ExpandProperty Path -Unique | Select-Object -First 10
71
72
  ```
72
73
 
73
74
  ### 2b. Trace the code path
@@ -37,6 +37,7 @@ For each must-have in each plan's frontmatter:
37
37
  - If it says "file X exists" → check with `ls [file]`
38
38
  - If it says "file X exports Y" → check with `grep "export.*Y" [file]`
39
39
  - If it says "npm test passes" → run `npm test 2>&1 | tail -5` or equivalent
40
+ (PowerShell: `npm test 2>&1 | Select-Object -Last 5`)
40
41
  - If it says "endpoint /foo returns 200" → mark as `human_needed` (needs running server)
41
42
 
42
43
  Never invent a verification method — use exactly what the must-have specifies.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "learnship",
3
- "version": "1.9.21",
3
+ "version": "1.9.22",
4
4
  "description": "Agentic engineering done right — 42 structured workflows, persistent memory across sessions, integrated learning partner, and impeccable UI design system.",
5
5
  "author": "Favio Vazquez",
6
6
  "homepage": "https://faviovazquez.github.io/learnship/",
@@ -1,55 +1,94 @@
1
- # Debugger Persona
1
+ ---
2
+ name: learnship-debugger
3
+ description: Investigates bugs using systematic hypothesis testing — traces from symptoms to root cause, writes investigation findings to the debug session file. Spawned by debug workflow on platforms with subagent support.
4
+ tools: Read, Write, Bash, Glob, Grep
5
+ color: orange
6
+ ---
2
7
 
3
- You are now operating as the **learnship debugger**. Your job is to investigate bugs using systematic hypothesis testing — tracing from symptoms to the exact root cause.
8
+ <role>
9
+ You are a learnship debugger. You investigate bugs using systematic scientific method — forming hypotheses, testing them against the codebase, and finding the exact root cause.
4
10
 
5
- You are investigating, not fixing. Read first, ask only when genuinely blocked.
11
+ Spawned by `debug` when `parallelization: true` in config.
6
12
 
7
- ## Debugging Philosophy
13
+ Your job: Find the root cause through hypothesis testing and write your findings to the debug session file. You have a fresh, full context budget — use it to read deeply.
8
14
 
9
- **User = Reporter, You = Investigator**
15
+ **CRITICAL: Mandatory Initial Read**
16
+ If the prompt contains a `<files_to_read>` block, you MUST use the Read tool to load every file listed there before performing any other actions.
17
+ </role>
10
18
 
11
- The user knows the symptom and what they expected. You trace the code path.
19
+ <debugging_philosophy>
12
20
 
13
- Do NOT ask for information you can find by reading code. Read first, ask only when genuinely blocked.
21
+ ## User = Reporter, You = Investigator
22
+
23
+ The user knows:
24
+ - What the symptom is
25
+ - What they expected
26
+ - What they've already tried
27
+
28
+ You know:
29
+ - How to trace code paths
30
+ - Where to look for common failure modes
31
+ - How to eliminate hypotheses systematically
32
+
33
+ Do NOT ask the user for information that you can find by reading the code. Read first, ask only when genuinely blocked.
34
+
35
+ ## Scientific Method
14
36
 
15
- **Scientific Method:**
16
37
  1. Form a specific hypothesis: "The bug is caused by X in file Y because Z"
17
38
  2. Find evidence that would confirm or deny it
18
39
  3. Check the evidence (read files, grep, run safe read-only commands)
19
40
  4. Update: confirmed → root cause found; denied → next hypothesis
20
41
  5. Never declare root cause without confirming it explains the symptom
21
42
 
22
- **One Root Cause Rule:** Bugs almost always have one root cause. Don't patch symptoms. Don't propose multiple "could also be" fixes. Find the one thing that, if changed, would make the symptom go away.
43
+ ## One Root Cause Rule
44
+
45
+ Bugs almost always have one root cause. Don't patch symptoms. Don't propose multiple "could also be" fixes. Find the one thing that, if changed, would make the symptom go away.
46
+ </debugging_philosophy>
47
+
48
+ <execution_flow>
23
49
 
24
- ## Before Investigating
50
+ ## Step 1: Load Context
25
51
 
26
- Read:
27
- - The debug session file completely (symptom, triage, hypotheses)
28
- - `./AGENTS.md` (or `./CLAUDE.md` / `./GEMINI.md`) for project conventions
29
- - `.planning/STATE.md` for recent changes and decisions that may have introduced the bug
52
+ Read the debug session file completely. Extract:
53
+ - Symptom description
54
+ - Triage answers (when, expected, frequency, regression)
55
+ - Hypotheses ranked by likelihood
30
56
 
31
- ## Investigation Steps
57
+ Read project context file (`./AGENTS.md`, `./CLAUDE.md`, or `./GEMINI.md` — whichever exists).
58
+
59
+ Read `.planning/STATE.md` for recent changes and decisions.
60
+
61
+ ## Step 2: Investigate Hypotheses
32
62
 
33
63
  For each hypothesis, starting with the most likely:
34
64
 
35
- **1. Plan the investigation** — identify the key files to check:
65
+ ### 2a. Plan the investigation
66
+
67
+ Identify the key files to check:
36
68
  ```bash
69
+ # Find entry points, relevant modules
37
70
  grep -r "[key_term]" src/ --include="*.ts" --include="*.js" -l 2>/dev/null | head -10
71
+ # PowerShell: Select-String -Path src/ -Recurse -Pattern '[key_term]' -Include '*.ts','*.js' | Select-Object -ExpandProperty Path -Unique | Select-Object -First 10
38
72
  ```
39
73
 
40
- **2. Trace the code path:**
41
- - UI symptom → start at component, trace to state, trace to API call, trace to backend
42
- - Data symptom → start at the output, trace backward to where data is transformed
43
- - Crash read the stack trace location, then read that file deeply
74
+ ### 2b. Trace the code path
75
+
76
+ Trace from the user-facing symptom inward:
77
+ - If it's a UI symptom: start at the component, trace to state, trace to API call, trace to backend
78
+ - If it's a data symptom: start at the output, trace backward to where data is transformed
79
+ - If it's a crash: read the stack trace location, then read that file deeply
44
80
 
45
81
  Read all files in the code path. Don't stop at the first suspicious thing — confirm it actually causes the symptom.
46
82
 
47
- **3. Confirm or deny:**
83
+ ### 2c. Confirm or deny
84
+
48
85
  Ask: "If this were fixed, would the symptom definitely go away?"
49
86
  - Yes → root cause found
50
87
  - No → hypothesis denied, move to next
51
88
 
52
- ## Update the Debug Session File
89
+ ## Step 3: Write Investigation Findings
90
+
91
+ Update the debug session file with investigation results:
53
92
 
54
93
  ```markdown
55
94
  ## Investigation
@@ -67,11 +106,11 @@ Ask: "If this were fixed, would the symptom definitely go away?"
67
106
  **Why denied:** [what evidence ruled this out]
68
107
  ```
69
108
 
70
- If all hypotheses denied, form new ones based on what the investigation found and continue.
109
+ If all hypotheses denied, add new ones based on investigation findings and continue.
71
110
 
72
- ## Final Root Cause Entry
111
+ ## Step 4: Conclude
73
112
 
74
- Once confirmed, write to the session file:
113
+ Once root cause is confirmed, write the final conclusion to the session file:
75
114
 
76
115
  ```markdown
77
116
  ## Root Cause
@@ -89,3 +128,20 @@ Once confirmed, write to the session file:
89
128
 
90
129
  **Risk:** [side effects or things to watch for]
91
130
  ```
131
+
132
+ ## Step 5: Return to Orchestrator
133
+
134
+ Output:
135
+ ```
136
+ ## Investigation Complete
137
+
138
+ **Root cause:** [one sentence]
139
+ **Location:** [file:line]
140
+ **Confidence:** high | medium | low
141
+
142
+ **Proposed fix:** [one sentence]
143
+ **Files to change:** [list]
144
+
145
+ Session file updated: [session_file_path]
146
+ ```
147
+ </execution_flow>
@@ -1,54 +1,91 @@
1
- # Verifier Persona
1
+ ---
2
+ name: learnship-verifier
3
+ description: Verifies that a phase goal was actually achieved after execution — checks must_haves, requirement coverage, and integration links. Spawned by execute-phase on platforms with subagent support.
4
+ tools: Read, Bash, Glob, Grep
5
+ color: purple
6
+ ---
7
+
8
+ <role>
9
+ You are a learnship verifier. You verify that a phase was actually completed correctly — not just that code was written, but that the phase goal is genuinely achieved.
2
10
 
3
- You are now operating as the **learnship verifier**. Your job is to verify that a phase goal was actually achieved not just that code was written, but that deliverables genuinely exist and work.
11
+ Spawned by `execute-phase` after all waves complete when `parallelization: true` in config.
4
12
 
5
- You are checking reality, not reviewing quality.
13
+ Your job: Write a VERIFICATION.md with status `passed`, `human_needed`, or `gaps_found`.
6
14
 
7
- ## Verification Principles
15
+ **CRITICAL: Mandatory Initial Read**
16
+ If the prompt contains a `<files_to_read>` block, you MUST use the Read tool to load every file listed there before performing any other actions.
17
+ </role>
8
18
 
9
- **You are NOT checking:**
19
+ <verification_principles>
20
+
21
+ ## Verification is not code review
22
+
23
+ You are NOT checking:
10
24
  - Whether code is elegant or well-structured
11
25
  - Whether there are better approaches
12
- - Whether code follows best practices (beyond what CONTEXT.md specifies)
26
+ - Whether the code follows best practices (beyond what CONTEXT.md specifies)
13
27
 
14
- **You ARE checking:**
28
+ You ARE checking:
15
29
  - Do the deliverables from the phase goal actually exist on disk?
16
- - Do the `must_haves` from each PLAN.md frontmatter pass?
30
+ - Do the must_haves from each PLAN.md frontmatter pass?
17
31
  - Are all requirement IDs for this phase traceable to delivered code?
18
32
  - Do integration links actually work (imports resolve, exports exist)?
19
33
 
20
- ## How to Check must_haves
34
+ ## How to check must_haves
21
35
 
22
36
  For each must-have in each plan's frontmatter:
23
- - "file X exists" → `ls [file] 2>/dev/null && echo EXISTS || echo MISSING`
24
- - "file X exports Y" → `grep "export.*Y" [file]`
25
- - "npm test passes" → `npm test 2>&1 | tail -5` (or equivalent)
26
- - "endpoint /foo returns 200" mark as `human_needed` (needs running server)
37
+ - If it says "file X exists" → check with `ls [file]`
38
+ - If it says "file X exports Y" → check with `grep "export.*Y" [file]`
39
+ - If it says "npm test passes" → run `npm test 2>&1 | tail -5` or equivalent
40
+ (PowerShell: `npm test 2>&1 | Select-Object -Last 5`)
41
+ - If it says "endpoint /foo returns 200" → mark as `human_needed` (needs running server)
27
42
 
28
43
  Never invent a verification method — use exactly what the must-have specifies.
44
+ </verification_principles>
45
+
46
+ <execution_flow>
29
47
 
30
- ## Before Verifying
48
+ ## Step 1: Read Phase Artifacts
31
49
 
32
50
  Read:
33
- - All PLAN.md files in the phase directory (for `must_haves`)
51
+ - All PLAN.md files in the phase directory (for must_haves)
34
52
  - All SUMMARY.md files (what executors report they built)
35
53
  - ROADMAP.md phase section (the phase goal)
36
54
  - REQUIREMENTS.md requirement IDs assigned to this phase
37
- - CONTEXT.md if exists (locked decisions to check against)
55
+ - CONTEXT.md if exists (locked decisions)
38
56
 
39
57
  ```bash
40
58
  ls ".planning/phases/[padded_phase]-[phase_slug]/"
41
59
  ```
42
60
 
43
- ## Verification Steps
61
+ ## Step 2: Check Each must_have
62
+
63
+ For every plan, check every item in `must_haves`:
64
+
65
+ ```bash
66
+ # Example checks
67
+ ls [file] 2>/dev/null && echo "EXISTS" || echo "MISSING"
68
+ grep -c "export" [file] 2>/dev/null
69
+ ```
70
+
71
+ Track result per item: ✓ pass / ✗ fail / ⚠ human_needed
72
+
73
+ ## Step 3: Check Requirement Coverage
44
74
 
45
- **Step 1:** For every plan, check every item in `must_haves.truths`, `must_haves.artifacts`, `must_haves.key_links`. Track: ✓ pass / ✗ fail / ⚠ human_needed.
75
+ For each requirement ID assigned to this phase:
76
+ - Find which plan claims to address it
77
+ - Verify the key deliverable for that requirement exists
46
78
 
47
- **Step 2:** For each requirement ID assigned to this phase — find which plan claims to address it, verify the key deliverable for that requirement exists.
79
+ ## Step 4: Check Integration Links
48
80
 
49
- **Step 3:** For files that are imported by other files verify imports resolve and exported symbols exist.
81
+ For files that are imported by other files in the project:
82
+ ```bash
83
+ grep -r "from.*[module_name]" src/ --include="*.ts" --include="*.js" -l 2>/dev/null
84
+ ```
85
+
86
+ Verify those imports would resolve (the exported symbols exist).
50
87
 
51
- ## VERIFICATION.md Format
88
+ ## Step 5: Write VERIFICATION.md
52
89
 
53
90
  Write to `.planning/phases/[padded_phase]-[phase_slug]/[padded_phase]-VERIFICATION.md`:
54
91
 
@@ -83,16 +120,19 @@ verified: [date]
83
120
 
84
121
  **Score:** [N]/[M] must-haves verified
85
122
 
86
- [If passed:] All automated checks passed. Phase goal achieved.
123
+ [If passed:]
124
+ All automated checks passed. Phase goal achieved.
87
125
 
88
- [If human_needed:] All automated checks passed. [N] items need human testing:
126
+ [If human_needed:]
127
+ All automated checks passed. [N] items need human testing:
89
128
  - [item requiring manual verification]
90
129
 
91
130
  [If gaps_found:]
92
131
  ### Gaps
132
+
93
133
  | Gap | Plan | What's missing |
94
134
  |-----|------|----------------|
95
- | [gap] | [plan ID] | [specific missing deliverable] |
135
+ | [gap description] | [plan ID] | [specific missing deliverable] |
96
136
  ```
97
137
 
98
138
  Commit:
@@ -100,3 +140,19 @@ Commit:
100
140
  git add ".planning/phases/[padded_phase]-[phase_slug]/[padded_phase]-VERIFICATION.md"
101
141
  git commit -m "docs([padded_phase]): add phase verification"
102
142
  ```
143
+
144
+ ## Step 6: Return Result
145
+
146
+ ```
147
+ ## Verification Complete
148
+
149
+ **Phase [N]: [Name]**
150
+ **Status:** passed / human_needed / gaps_found
151
+ **Score:** [N]/[M] must-haves verified
152
+
153
+ [If gaps_found: list gaps with plan IDs]
154
+ [If human_needed: list items needing manual testing]
155
+
156
+ ▶ Next: verify-work [N] (manual UAT)
157
+ ```
158
+ </execution_flow>
@@ -40,7 +40,7 @@ Configuration options for `.planning/` directory behavior.
40
40
 
41
41
  ```bash
42
42
  # Read commit_docs from config.json
43
- COMMIT_DOCS=$(python3 -c "import json; c=json.load(open('.planning/config.json')); print(c.get('planning',{}).get('commit_docs','true'))" 2>/dev/null || echo 'true')
43
+ COMMIT_DOCS=$(node -e "try{const c=JSON.parse(require('fs').readFileSync('.planning/config.json','utf8'));process.stdout.write(String((c.planning||{}).commit_docs??'true'));}catch(e){process.stdout.write('true');}" 2>/dev/null || echo 'true')
44
44
  ```
45
45
 
46
46
  **Auto-detection:** If `.planning/` is gitignored, treat `commit_docs` as `false` regardless of config.json. This prevents git errors.
@@ -139,7 +139,7 @@ To use uncommitted mode:
139
139
 
140
140
  Read config directly:
141
141
  ```bash
142
- python3 -c "import json; c=json.load(open('.planning/config.json')); g=c.get('git',{}); print(g.get('branching_strategy','none'), g.get('phase_branch_template','phase-{phase}-{slug}'), g.get('milestone_branch_template','{milestone}-{slug}'))"
142
+ node -e "const c=JSON.parse(require('fs').readFileSync('.planning/config.json','utf8')),g=c.git||{};console.log(g.branching_strategy||'none',g.phase_branch_template||'phase-{phase}-{slug}',g.milestone_branch_template||'{milestone}-{slug}')"
143
143
  ```
144
144
 
145
145
  **Branch creation:**
@@ -12,7 +12,7 @@ Append a new integer phase to the end of the current milestone. Use when scope g
12
12
 
13
13
  Check that a roadmap exists:
14
14
  ```bash
15
- python3 -c "import os; print('OK' if os.path.exists('.planning/ROADMAP.md') else 'MISSING')"
15
+ node -e "const fs=require('fs'); console.log(fs.existsSync('.planning/ROADMAP.md') ? 'OK' : 'MISSING')"
16
16
  ```
17
17
 
18
18
  If missing: stop — run `new-project` first.
@@ -24,11 +24,13 @@ If no description was provided as an argument, ask: "What does this new phase de
24
24
  Read `.planning/ROADMAP.md` and find the highest existing integer phase number:
25
25
  ```bash
26
26
  grep -E "^## Phase [0-9]+" .planning/ROADMAP.md | tail -1
27
+ # PowerShell: Select-String -Path .planning/ROADMAP.md -Pattern '^## Phase \d+' | Select-Object -Last 1
27
28
  ```
28
29
 
29
30
  Also scan the phases directory for any directories that may not be in the roadmap:
30
31
  ```bash
31
32
  ls .planning/phases/ 2>/dev/null | grep -E "^[0-9]+" | sort -n | tail -3
33
+ # PowerShell: Get-ChildItem .planning/phases/ -ErrorAction SilentlyContinue | Where-Object { $_.Name -match '^[0-9]+' } | Sort-Object Name | Select-Object -Last 3
32
34
  ```
33
35
 
34
36
  Set `NEXT_NUM` = highest found + 1. Pad to 2 digits (01, 02, ..., 10, 11, ...).
@@ -38,7 +40,8 @@ Generate a slug from the description (lowercase, hyphens, max 40 chars).
38
40
  ## Step 3: Create Phase Directory
39
41
 
40
42
  ```bash
41
- mkdir -p ".planning/phases/${NEXT_NUM}-${SLUG}"
43
+ node -e "require('fs').mkdirSync('.planning/phases/${NEXT_NUM}-${SLUG}',{recursive:true})"
44
+ # PowerShell: New-Item -ItemType Directory -Force -Path ".planning/phases/${NEXT_NUM}-${SLUG}"
42
45
  ```
43
46
 
44
47
  ## Step 4: Update ROADMAP.md
@@ -20,6 +20,7 @@ Example: add-tests 3 focus on edge cases in the pricing module
20
20
  Find the phase directory:
21
21
  ```bash
22
22
  ls .planning/phases/ | grep -E "^0*[N]-" | head -1
23
+ # PowerShell: Get-ChildItem .planning/phases/ | Where-Object { $_.Name -match "^0*[N]-" } | Select-Object -First 1 -ExpandProperty Name
23
24
  PHASE_DIR=".planning/phases/[matched]"
24
25
  ```
25
26
 
@@ -45,6 +46,7 @@ Extract the list of files modified by the phase from SUMMARY.md.
45
46
  find . \( -name "jest.config.*" -o -name "vitest.config.*" -o -name "pytest.ini" -o -name "pyproject.toml" -o -name "playwright.config.*" \) -not -path "*/node_modules/*" 2>/dev/null
46
47
 
47
48
  find . \( -name "*.test.*" -o -name "*.spec.*" -o -name "test_*.py" \) -not -path "*/node_modules/*" 2>/dev/null | head -10
49
+ # PowerShell: Get-ChildItem -Recurse | Where-Object { $_.Name -match '\.test\.|spec\.|^test_.*\.py' -and $_.FullName -notmatch 'node_modules' } | Select-Object -First 10
48
50
  ```
49
51
 
50
52
  Identify: test framework, E2E framework (if any), how to run tests, existing test file patterns and locations.
@@ -11,7 +11,7 @@ Capture an idea, task, or issue that surfaces during a session. Fast "thought
11
11
  ## Step 1: Ensure Directories Exist
12
12
 
13
13
  ```bash
14
- mkdir -p .planning/todos/pending .planning/todos/done
14
+ node -e "require('fs').mkdirSync('.planning/todos/pending',{recursive:true});require('fs').mkdirSync('.planning/todos/done',{recursive:true})"
15
15
  ```
16
16
 
17
17
  ## Step 2: Extract Content
@@ -79,6 +79,7 @@ Check:
79
79
 
80
80
  ```bash
81
81
  grep -rn "TODO\|FIXME\|PLACEHOLDER\|return null\|return undefined" src/ --include="*.ts" --include="*.tsx" --include="*.js" 2>/dev/null | grep -v "node_modules\|\.test\." | head -30
82
+ # PowerShell: Select-String -Path src/ -Recurse -Pattern 'TODO|FIXME|PLACEHOLDER|return null|return undefined' -Include '*.ts','*.tsx','*.js' | Where-Object { $_.Path -notmatch 'node_modules|\.test\.' } | Select-Object -First 30
82
83
  ```
83
84
 
84
85
  ## Step 5: Compile Audit Report
@@ -80,7 +80,7 @@ Wait for confirmation. If "no": stop.
80
80
  For each milestone and its phase directories:
81
81
 
82
82
  ```bash
83
- mkdir -p ".planning/milestones/v[X.Y]-phases"
83
+ node -e "require('fs').mkdirSync('.planning/milestones/v[X.Y]-phases',{recursive:true})"
84
84
  mv ".planning/phases/[phase-dir]/" ".planning/milestones/v[X.Y]-phases/"
85
85
  ```
86
86
 
@@ -47,6 +47,7 @@ Ask for confirmation:
47
47
  Read `.planning/STATE.md` and check for existing version tags:
48
48
  ```bash
49
49
  git tag --list "v*" | sort -V | tail -5
50
+ # PowerShell: git tag --list "v*" | Sort-Object | Select-Object -Last 5
50
51
  ```
51
52
 
52
53
  Propose the next version (e.g., `v1.0`, `v1.1`, `v2.0`). Ask for confirmation or let user specify.
@@ -55,7 +56,7 @@ Propose the next version (e.g., `v1.0`, `v1.1`, `v2.0`). Ask for confirmation or
55
56
 
56
57
  Create the milestones archive directory:
57
58
  ```bash
58
- mkdir -p .planning/milestones
59
+ node -e "require('fs').mkdirSync('.planning/milestones',{recursive:true})"
59
60
  ```
60
61
 
61
62
  Archive the roadmap for this milestone:
@@ -11,7 +11,7 @@ Systematic debugging workflow: triage → root cause diagnosis → fix planning
11
11
  ## Step 1: Create Debug Session
12
12
 
13
13
  ```bash
14
- mkdir -p .planning/debug
14
+ node -e "require('fs').mkdirSync('.planning/debug',{recursive:true})"
15
15
  DATE=$(date +%Y%m%d-%H%M)
16
16
  ```
17
17
 
@@ -196,7 +196,7 @@ Update session file:
196
196
 
197
197
  Move to resolved:
198
198
  ```bash
199
- mkdir -p .planning/debug/resolved
199
+ node -e "require('fs').mkdirSync('.planning/debug/resolved',{recursive:true})"
200
200
  mv ".planning/debug/[session-file]" ".planning/debug/resolved/"
201
201
  ```
202
202
 
@@ -15,6 +15,7 @@ Batch-diagnose all open UAT issues after `verify-work`. Groups issues by root ca
15
15
  Find the UAT file for the phase:
16
16
  ```bash
17
17
  ls ".planning/phases/"*[N]*"/"*-UAT.md 2>/dev/null | head -1
18
+ # PowerShell: Get-ChildItem ".planning/phases/" -Recurse -Filter "*-UAT.md" | Where-Object { $_.FullName -match [N] } | Select-Object -First 1
18
19
  ```
19
20
 
20
21
  If no UAT file found: stop — "Run `verify-work [N]` first to log issues."
@@ -33,13 +33,16 @@ Search for code related to the target area using key terms from the phase goal:
33
33
  ```bash
34
34
  # Find files mentioning key terms
35
35
  grep -rl "[key term 1]" src/ 2>/dev/null | head -15
36
+ # PowerShell: Select-String -Path src/ -Recurse -Pattern "[key term 1]" | Select-Object -ExpandProperty Path -Unique | Select-Object -First 15
36
37
  grep -rl "[key term 2]" src/ 2>/dev/null | head -10
38
+ # PowerShell: Select-String -Path src/ -Recurse -Pattern "[key term 2]" | Select-Object -ExpandProperty Path -Unique | Select-Object -First 10
37
39
 
38
40
  # Find related directories
39
41
  find src/ -type d | grep -i "[key term]" 2>/dev/null
40
42
 
41
43
  # Find entry points
42
44
  grep -rn "export\|module.exports\|def " src/ --include="*.ts" --include="*.js" --include="*.py" 2>/dev/null | grep -i "[key term]" | head -20
45
+ # PowerShell: Select-String -Path src/ -Recurse -Pattern 'export|module.exports|def ' | Where-Object { $_.Line -imatch '[key term]' } | Select-Object -First 20
43
46
  ```
44
47
 
45
48
  Read the 5-8 most relevant files. Focus on interfaces, types, exports, and public API — not implementation details.
@@ -51,6 +54,7 @@ For the relevant files, trace what they depend on and what depends on them:
51
54
  **Incoming dependencies** (who calls this code):
52
55
  ```bash
53
56
  grep -rl "import.*[module name]\|require.*[module name]" src/ 2>/dev/null | head -10
57
+ # PowerShell: Select-String -Path src/ -Recurse -Pattern 'import.*[module name]|require.*[module name]' | Select-Object -ExpandProperty Path -Unique | Select-Object -First 10
54
58
  ```
55
59
 
56
60
  **Outgoing dependencies** (what this code calls):
@@ -80,6 +84,7 @@ Look specifically for:
80
84
  ```bash
81
85
  # Files with most lines of code in the area
82
86
  wc -l $(find src/ -name "*.ts" -o -name "*.py" 2>/dev/null | xargs grep -l "[key term]" 2>/dev/null) | sort -n | tail -10
87
+ # PowerShell: Select-String -Path src/ -Recurse -Pattern '[key term]' -Include '*.ts','*.py' | Select-Object -ExpandProperty Path -Unique | ForEach-Object { (Get-Content $_).Count } | Sort-Object | Select-Object -Last 10
83
88
  ```
84
89
 
85
90
  **Test coverage gaps:**
@@ -90,6 +95,7 @@ find . -name "*.test.*" -o -name "test_*.py" | xargs grep -l "[key term]" 2>/dev
90
95
  **TODO/FIXME in the area:**
91
96
  ```bash
92
97
  grep -rn "TODO\|FIXME\|HACK\|XXX" src/ 2>/dev/null | grep -i "[key term]" | head -10
98
+ # PowerShell: Select-String -Path src/ -Recurse -Pattern 'TODO|FIXME|HACK|XXX' | Where-Object { $_.Line -imatch '[key term]' } | Select-Object -First 10
93
99
  ```
94
100
 
95
101
  **Known issues from DECISIONS.md:**
@@ -17,6 +17,7 @@ Read what has already shipped:
17
17
  cat .planning/PROJECT.md
18
18
  cat .planning/STATE.md
19
19
  ls .planning/milestones/ 2>/dev/null | sort -V | tail -3
20
+ # PowerShell: Get-ChildItem .planning/milestones/ -ErrorAction SilentlyContinue | Sort-Object Name | Select-Object -Last 3
20
21
  ```
21
22
 
22
23
  Display the last milestone summary so the conversation starts informed:
@@ -29,7 +30,7 @@ Pending todos: [N] items
29
30
 
30
31
  Check if a MILESTONE-CONTEXT.md already exists:
31
32
  ```bash
32
- python3 -c "import os; print('EXISTS' if os.path.exists('.planning/MILESTONE-CONTEXT.md') else 'MISSING')"
33
+ node -e "const fs=require('fs'); console.log(fs.existsSync('.planning/MILESTONE-CONTEXT.md') ? 'EXISTS' : 'MISSING')"
33
34
  ```
34
35
 
35
36
  If exists: ask "A milestone context file already exists from a prior discussion. Update it or start fresh?"
@@ -29,6 +29,7 @@ Extract from prior CONTEXT.md files: locked preferences, patterns the user has e
29
29
  If `.planning/DECISIONS.md` exists, read it:
30
30
  ```bash
31
31
  cat .planning/DECISIONS.md 2>/dev/null | head -80
32
+ # PowerShell: Get-Content .planning/DECISIONS.md -ErrorAction SilentlyContinue | Select-Object -First 80
32
33
  ```
33
34
 
34
35
  Note any decisions that constrain or inform this phase's approach. Surface them during discussion rather than re-asking decided questions.
@@ -129,7 +130,7 @@ Track deferred ideas internally.
129
130
 
130
131
  Find or create the phase directory:
131
132
  ```bash
132
- mkdir -p ".planning/phases/[padded_phase]-[phase_slug]"
133
+ node -e "require('fs').mkdirSync('.planning/phases/[padded_phase]-[phase_slug]',{recursive:true})"
133
134
  ```
134
135
 
135
136
  Write `.planning/phases/[padded_phase]-[phase_slug]/[padded_phase]-CONTEXT.md`:
@@ -13,6 +13,7 @@ Execute a single PLAN.md file in isolation. Useful when one plan in a phase fail
13
13
  Find the phase directory:
14
14
  ```bash
15
15
  ls .planning/phases/ | grep -E "^0*[phase]-" | head -1
16
+ # PowerShell: Get-ChildItem .planning/phases/ | Where-Object { $_.Name -match "^0*[phase]-" } | Select-Object -First 1 -ExpandProperty Name
16
17
  PHASE_DIR=".planning/phases/[matched]"
17
18
  ```
18
19
 
@@ -15,7 +15,7 @@ Check if `--repair` flag is present.
15
15
  ## Step 2: Check Project Exists
16
16
 
17
17
  ```bash
18
- python3 -c "import os; print('OK' if os.path.isdir('.planning') else 'MISSING')"
18
+ node -e "const fs=require('fs'); console.log(fs.existsSync('.planning') ? 'OK' : 'MISSING')"
19
19
  ```
20
20
 
21
21
  If `.planning/` doesn't exist:
@@ -32,40 +32,49 @@ Run the following checks and classify each as error, warning, or info:
32
32
 
33
33
  ### Required Files
34
34
  ```bash
35
- python3 -c "import os; print('E002: PROJECT.md not found') if not os.path.exists('.planning/PROJECT.md') else None"
36
- python3 -c "import os; print('E003: ROADMAP.md not found') if not os.path.exists('.planning/ROADMAP.md') else None"
37
- python3 -c "import os; print('E004: STATE.md not found (repairable)') if not os.path.exists('.planning/STATE.md') else None"
38
- python3 -c "import os; print('W003: config.json not found (repairable)') if not os.path.exists('.planning/config.json') else None"
35
+ node -e "const fs=require('fs'); if(!fs.existsSync('.planning/PROJECT.md')) console.log('E002: PROJECT.md not found')"
36
+ node -e "const fs=require('fs'); if(!fs.existsSync('.planning/ROADMAP.md')) console.log('E003: ROADMAP.md not found')"
37
+ node -e "const fs=require('fs'); if(!fs.existsSync('.planning/STATE.md')) console.log('E004: STATE.md not found (repairable)')"
38
+ node -e "const fs=require('fs'); if(!fs.existsSync('.planning/config.json')) console.log('W003: config.json not found (repairable)')"
39
39
  ```
40
40
 
41
41
  ### Config Validity
42
42
  ```bash
43
- cat .planning/config.json | python3 -c "import sys,json; json.load(sys.stdin)" 2>&1 || echo "E005: config.json parse error (repairable)"
43
+ node -e "try{JSON.parse(require('fs').readFileSync('.planning/config.json','utf8'))}catch(e){console.log('E005: config.json parse error (repairable)')}"
44
44
  ```
45
45
 
46
46
  ### State / Roadmap Consistency
47
47
  ```bash
48
- # Check if STATE.md references a phase that exists in ROADMAP.md
49
- CURRENT_PHASE=$(grep -E "^Phase:" .planning/STATE.md 2>/dev/null | head -1 | grep -oE "[0-9]+")
50
- if [ -n "$CURRENT_PHASE" ]; then
51
- grep -q "Phase ${CURRENT_PHASE}:" .planning/ROADMAP.md || echo "W002: STATE.md references phase ${CURRENT_PHASE} not found in roadmap (repairable)"
52
- fi
48
+ node -e "
49
+ const fs=require('fs');
50
+ if(!fs.existsSync('.planning/STATE.md')||!fs.existsSync('.planning/ROADMAP.md'))process.exit(0);
51
+ const state=fs.readFileSync('.planning/STATE.md','utf8');
52
+ const m=state.match(/^Phase:\s*(\d+)/m);
53
+ if(m){
54
+ const roadmap=fs.readFileSync('.planning/ROADMAP.md','utf8');
55
+ if(!roadmap.includes('Phase '+m[1]+':'))console.log('W002: STATE.md references phase '+m[1]+' not found in roadmap (repairable)');
56
+ }
57
+ "
53
58
  ```
54
59
 
55
60
  ### Phase Directory Checks
56
61
  ```bash
57
- # Phases in ROADMAP but no directory
58
- grep -oE "Phase [0-9]+:" .planning/ROADMAP.md | while read phase; do
59
- num=$(echo "$phase" | grep -oE "[0-9]+")
60
- padded=$(printf "%02d" $num)
61
- ls .planning/phases/${padded}-* 2>/dev/null | head -1 || echo "W006: Phase ${num} in roadmap but no directory"
62
- done
63
-
64
- # Phase directories not in ROADMAP
65
- for dir in .planning/phases/*/; do
66
- slug=$(basename "$dir" | sed 's/^[0-9]*-//')
67
- grep -q "$slug" .planning/ROADMAP.md || echo "W007: Directory $(basename $dir) not in roadmap"
68
- done
62
+ node -e "
63
+ const fs=require('fs'),path=require('path');
64
+ if(!fs.existsSync('.planning/ROADMAP.md'))process.exit(0);
65
+ const roadmap=fs.readFileSync('.planning/ROADMAP.md','utf8');
66
+ const phases=[...roadmap.matchAll(/^## Phase (\d+):/mg)].map(m=>m[1]);
67
+ const phasesDir='.planning/phases';
68
+ const dirs=fs.existsSync(phasesDir)?fs.readdirSync(phasesDir):[];
69
+ for(const n of phases){
70
+ const pad=n.padStart(2,'0');
71
+ if(!dirs.some(d=>d.startsWith(pad+'-')))console.log('W006: Phase '+n+' in roadmap but no directory');
72
+ }
73
+ for(const d of dirs){
74
+ const slug=d.replace(/^\d+-/,'');
75
+ if(!roadmap.includes(slug))console.log('W007: Directory '+d+' not in roadmap');
76
+ }
77
+ "
69
78
  ```
70
79
 
71
80
  ### Plans Without Summaries
@@ -79,21 +88,18 @@ done
79
88
  ### Uncommitted Changes
80
89
  ```bash
81
90
  git status --short .planning/ 2>/dev/null | head -10
91
+ # PowerShell: git status --short .planning/ 2>$null | Select-Object -First 10
82
92
  ```
83
93
 
84
94
  ### Config Fields
85
95
  ```bash
86
- # Check for required config keys
87
- python3 -c "
88
- import json
89
- cfg = json.load(open('.planning/config.json'))
90
- missing = []
91
- for key in ['mode', 'granularity', 'model_profile', 'learning_mode']:
92
- if key not in cfg:
93
- missing.append(key)
94
- if missing:
95
- print('W004: config.json missing fields: ' + ', '.join(missing))
96
- " 2>/dev/null
96
+ node -e "
97
+ try{
98
+ const cfg=JSON.parse(require('fs').readFileSync('.planning/config.json','utf8'));
99
+ const missing=['mode','granularity','model_profile','learning_mode'].filter(k=>!(k in cfg));
100
+ if(missing.length)console.log('W004: config.json missing fields: '+missing.join(', '));
101
+ }catch(e){}
102
+ "
97
103
  ```
98
104
 
99
105
  ## Step 4: Format Output
@@ -31,7 +31,7 @@ Validate that the after-phase number is an integer.
31
31
  ## Step 2: Validate
32
32
 
33
33
  ```bash
34
- python3 -c "import os; print('OK' if os.path.exists('.planning/ROADMAP.md') else 'MISSING')"
34
+ node -e "const fs=require('fs'); console.log(fs.existsSync('.planning/ROADMAP.md') ? 'OK' : 'MISSING')"
35
35
  ```
36
36
 
37
37
  Check that phase `[N]` exists in ROADMAP.md:
@@ -56,7 +56,7 @@ Generate slug from description (lowercase, hyphens, max 40 chars).
56
56
  ## Step 4: Create Phase Directory
57
57
 
58
58
  ```bash
59
- mkdir -p ".planning/phases/[N].[M]-[SLUG]"
59
+ node -e "require('fs').mkdirSync('.planning/phases/[N].[M]-[SLUG]',{recursive:true})"
60
60
  ```
61
61
 
62
62
  ## Step 5: Update ROADMAP.md
@@ -13,7 +13,7 @@ The quickest way to answer "where am I and what do I do next?" Works for new use
13
13
  ## Step 1: Check for Project
14
14
 
15
15
  ```bash
16
- python3 -c "import os; print('EXISTS' if os.path.exists('.planning/PROJECT.md') else 'MISSING')"
16
+ node -e "const fs=require('fs'); console.log(fs.existsSync('.planning/PROJECT.md') ? 'EXISTS' : 'MISSING')"
17
17
  ```
18
18
 
19
19
  **If MISSING** — no project initialized yet. Display:
@@ -50,7 +50,7 @@ cat .planning/ROADMAP.md
50
50
  Find the 2–3 most recent SUMMARY.md files:
51
51
 
52
52
  ```bash
53
- find .planning -name "*-SUMMARY.md" -type f 2>/dev/null | xargs ls -t 2>/dev/null | head -3
53
+ node -e "const fs=require('fs'),path=require('path');function find(d){let r=[];try{for(const e of fs.readdirSync(d,{withFileTypes:true})){const f=path.join(d,e.name);r=r.concat(e.isDirectory()?find(f):e.name.endsWith('-SUMMARY.md')?[f]:[]);}}catch(e){}return r;}const files=find('.planning').map(f=>({f,t:fs.statSync(f).mtimeMs})).sort((a,b)=>b.t-a.t).slice(0,3).map(x=>x.f);files.forEach(f=>console.log(f));"
54
54
  ```
55
55
 
56
56
  Read each for a one-liner summary of what was accomplished.
@@ -33,7 +33,7 @@ Wait for response before continuing.
33
33
  ## Step 2: Create Output Directory
34
34
 
35
35
  ```bash
36
- mkdir -p .planning/codebase
36
+ node -e "require('fs').mkdirSync('.planning/codebase',{recursive:true})"
37
37
  ```
38
38
 
39
39
  Expected output files:
@@ -15,7 +15,9 @@ A structured learning retrospective after a milestone ships. Five focused questi
15
15
  Read the milestone that just shipped:
16
16
  ```bash
17
17
  ls .planning/milestones/ | sort -V | tail -3
18
+ # PowerShell: Get-ChildItem .planning/milestones/ | Sort-Object Name | Select-Object -Last 3
18
19
  cat .planning/milestones/[VERSION]-ROADMAP.md 2>/dev/null | head -60
20
+ # PowerShell: Get-Content .planning/milestones/[VERSION]-ROADMAP.md -ErrorAction SilentlyContinue | Select-Object -First 60
19
21
  ```
20
22
 
21
23
  Read all phase SUMMARY.md files from this milestone:
@@ -48,6 +48,7 @@ Follow the thread. When you have enough to write clear goals, ask for confirmati
48
48
  Read the last version from `.planning/milestones/`:
49
49
  ```bash
50
50
  ls .planning/milestones/ | grep -E "^v[0-9]" | sort -V | tail -3
51
+ # PowerShell: Get-ChildItem .planning/milestones/ | Where-Object { $_.Name -match '^v[0-9]' } | Sort-Object Name | Select-Object -Last 3
51
52
  ```
52
53
 
53
54
  Propose the next version (e.g., `v1.0 → v1.1`, or `v2.0` for a major scope change). Confirm with user or let them specify.
@@ -21,14 +21,14 @@ Initialize a new project with full context gathering, optional research, require
21
21
 
22
22
  ## Step 1: Setup
23
23
 
24
- <!-- LEARNSHIP_PLATFORM_LABEL -->
24
+ You are running on **Windsurf**. Platform config directory: `.windsurf/`
25
25
 
26
26
  > **Routing protocol suspended.** While this workflow is running, every user message is an answer to a workflow question — not a task to route. Do NOT apply the request routing protocol until `/new-project` is fully complete and `.planning/PROJECT.md` exists.
27
27
 
28
28
  Check if `.planning/PROJECT.md` already exists:
29
29
 
30
30
  ```bash
31
- python3 -c "import os; print('EXISTS' if os.path.exists('.planning/PROJECT.md') else 'NEW')"
31
+ node -e "const fs=require('fs'); console.log(fs.existsSync('.planning/PROJECT.md') ? 'EXISTS' : 'NEW')"
32
32
  ```
33
33
 
34
34
  **If EXISTS:** Stop. Project already initialized. Use the `progress` workflow to see where you are.
@@ -36,11 +36,11 @@ python3 -c "import os; print('EXISTS' if os.path.exists('.planning/PROJECT.md')
36
36
  **Check for an existing codebase:**
37
37
 
38
38
  ```bash
39
- python3 -c "
40
- import os, pathlib
41
- files = [p for p in pathlib.Path('.').rglob('*') if p.is_file() and not any(x in p.parts for x in ['.git', 'node_modules', '.planning', '__pycache__', '.venv'])]
42
- print('HAS_CODE' if len(files) > 2 else 'BLANK')
43
- print(f'{len(files)} files')
39
+ node -e "
40
+ const fs=require('fs'),path=require('path');
41
+ function walk(dir,skip){let n=0;try{for(const e of fs.readdirSync(dir,{withFileTypes:true})){const f=path.join(dir,e.name);if(skip.some(s=>f.includes(s)))continue;n+=e.isDirectory()?walk(f,skip):1;}}catch(e){}return n;}
42
+ const n=walk('.',['/.git/','node_modules','.planning','__pycache__','.venv']);
43
+ console.log(n>2?'HAS_CODE':'BLANK');console.log(n+' files');
44
44
  "
45
45
  ```
46
46
 
@@ -49,7 +49,7 @@ print(f'{len(files)} files')
49
49
  Check if git is initialized:
50
50
 
51
51
  ```bash
52
- python3 -c "import os; print('HAS_GIT' if os.path.isdir('.git') else 'NO_GIT')"
52
+ node -e "const fs=require('fs'); console.log(fs.existsSync('.git') ? 'HAS_GIT' : 'NO_GIT')"
53
53
  ```
54
54
 
55
55
  **If NO_GIT:**
@@ -59,12 +59,12 @@ git init
59
59
 
60
60
  Add the platform config directory to `.gitignore` so AI platform files are not tracked in the project repo:
61
61
  ```bash
62
- <!-- LEARNSHIP_GITIGNORE_CMD -->
62
+ grep -q '.windsurf/' .gitignore 2>/dev/null || echo '.windsurf/' >> .gitignore
63
63
  ```
64
64
 
65
65
  Create the planning directory:
66
66
  ```bash
67
- mkdir -p .planning/research
67
+ node -e "require('fs').mkdirSync('.planning/research',{recursive:true})"
68
68
  ```
69
69
 
70
70
  ## Step 1b: Existing Codebase Scan (only if EXISTING_CODEBASE = true)
@@ -73,6 +73,7 @@ If `EXISTING_CODEBASE = true`, do a quick structural scan before questioning so
73
73
 
74
74
  ```bash
75
75
  find . -maxdepth 3 -not -path './.git/*' -not -path './node_modules/*' -not -path './.planning/*' -not -path './__pycache__/*' -not -path './.venv/*' | sort | head -40
76
+ # PowerShell: Get-ChildItem -Recurse -Depth 3 | Where-Object { $_.FullName -notmatch '\.git|node_modules|\.planning|__pycache__|\.venv' } | Select-Object -First 40
76
77
  ```
77
78
 
78
79
  Note the tech stack, key directories, and any README content internally. Use this ONLY to ask sharper follow-up questions — never to infer the user's intent or skip ceremony steps.
@@ -105,7 +106,9 @@ Ask: "Which workflow agents should be enabled?"
105
106
  - **Plan Check** (recommended) — Verify plans achieve their goals before execution
106
107
  - **Verifier** (recommended) — Confirm deliverables match phase goals after execution
107
108
 
108
- <!-- LEARNSHIP_PARALLEL_BLOCK -->
109
+ **Group D — Parallel execution:**
110
+
111
+ Windsurf does not support real subagents. Parallelization is automatically set to `false`.
109
112
 
110
113
  Ask: "Commit planning docs to git?"
111
114
  - **Yes** (recommended) — Planning docs tracked in version control
@@ -351,6 +354,7 @@ Fill in the placeholder sections using information gathered in this session:
351
354
  **Project Structure** — derive from the project description and any existing directories:
352
355
  ```bash
353
356
  find . -maxdepth 2 -not -path './.git/*' -not -path './node_modules/*' -not -path './.planning/*' -type d | sort | head -20
357
+ # PowerShell: Get-ChildItem -Directory -Recurse -Depth 2 | Where-Object { $_.FullName -notmatch '\.git|node_modules|\.planning' } | Select-Object -First 20
354
358
  ```
355
359
 
356
360
  Populate the `## Project Structure` tree with real directories and one-line descriptions.
@@ -13,7 +13,7 @@ Reads project state and runs the right next workflow automatically. No need to r
13
13
  ## Step 1: Check for Project
14
14
 
15
15
  ```bash
16
- python3 -c "import os; print('EXISTS' if os.path.exists('.planning/PROJECT.md') else 'MISSING')"
16
+ node -e "const fs=require('fs'); console.log(fs.existsSync('.planning/PROJECT.md') ? 'EXISTS' : 'MISSING')"
17
17
  ```
18
18
 
19
19
  **If MISSING:**
@@ -12,7 +12,7 @@ Create a `.continue-here.md` handoff file that captures complete work state. Ena
12
12
 
13
13
  Find the most recently active phase:
14
14
  ```bash
15
- find .planning/phases -name "*-PLAN.md" -type f 2>/dev/null | xargs ls -t 2>/dev/null | head -1
15
+ node -e "const fs=require('fs'),path=require('path');function find(d){let r=[];try{for(const e of fs.readdirSync(d,{withFileTypes:true})){const f=path.join(d,e.name);r=r.concat(e.isDirectory()?find(f):e.name.endsWith('-PLAN.md')?[f]:[]);}}catch(e){}return r;}const files=find('.planning/phases').map(f=>({f,t:fs.statSync(f).mtimeMs})).sort((a,b)=>b.t-a.t);if(files[0])console.log(files[0].f);"
16
16
  ```
17
17
 
18
18
  Extract the phase directory name from the result.
@@ -13,6 +13,7 @@ Create all phases needed to close gaps identified by `audit-milestone`. One work
13
13
  Find the most recent audit file:
14
14
  ```bash
15
15
  ls -t .planning/*-MILESTONE-AUDIT.md 2>/dev/null | head -1
16
+ # PowerShell: Get-ChildItem .planning/*-MILESTONE-AUDIT.md -ErrorAction SilentlyContinue | Sort-Object LastWriteTime -Descending | Select-Object -First 1
16
17
  ```
17
18
 
18
19
  If no audit file exists or status is `passed`:
@@ -74,6 +75,7 @@ Gap: Flow "User stays logged in" broken
74
75
  Find the highest existing phase number:
75
76
  ```bash
76
77
  ls .planning/phases/ | grep -E "^[0-9]" | sort -V | tail -1
78
+ # PowerShell: Get-ChildItem .planning/phases/ | Where-Object { $_.Name -match '^[0-9]' } | Sort-Object Name | Select-Object -Last 1
77
79
  ```
78
80
 
79
81
  Gap closure phases continue from the highest existing phase + 1.
@@ -131,7 +133,7 @@ For each unsatisfied requirement being addressed:
131
133
 
132
134
  ```bash
133
135
  for each gap closure phase:
134
- mkdir -p ".planning/phases/[NN]-[slug]"
136
+ node -e "require('fs').mkdirSync('.planning/phases/[NN]-[slug]',{recursive:true})"
135
137
  done
136
138
  ```
137
139
 
@@ -25,7 +25,7 @@ cat .planning/config.json
25
25
 
26
26
  Create the phase directory if it doesn't exist:
27
27
  ```bash
28
- mkdir -p ".planning/phases/[padded_phase]-[phase_slug]"
28
+ node -e "require('fs').mkdirSync('.planning/phases/[padded_phase]-[phase_slug]',{recursive:true})"
29
29
  ```
30
30
 
31
31
  Check what already exists:
@@ -9,7 +9,7 @@ Check where you are in the project, what's been done, and what comes next.
9
9
  ## Step 1: Check for Planning Structure
10
10
 
11
11
  ```bash
12
- python3 -c "import os; print('EXISTS' if os.path.exists('.planning/PROJECT.md') else 'MISSING')"
12
+ node -e "const fs=require('fs'); console.log(fs.existsSync('.planning/PROJECT.md') ? 'EXISTS' : 'MISSING')"
13
13
  ```
14
14
 
15
15
  If `.planning/` doesn't exist: stop — run `new-project` to initialize.
@@ -24,7 +24,7 @@ cat .planning/ROADMAP.md
24
24
 
25
25
  Find the 2-3 most recent SUMMARY.md files:
26
26
  ```bash
27
- find .planning -name "*-SUMMARY.md" -type f 2>/dev/null | xargs ls -t 2>/dev/null | head -3
27
+ node -e "const fs=require('fs'),path=require('path');function find(d){let r=[];try{for(const e of fs.readdirSync(d,{withFileTypes:true})){const f=path.join(d,e.name);r=r.concat(e.isDirectory()?find(f):e.name.endsWith('-SUMMARY.md')?[f]:[]);}}catch(e){}return r;}const files=find('.planning').map(f=>({f,t:fs.statSync(f).mtimeMs})).sort((a,b)=>b.t-a.t).slice(0,3).map(x=>x.f);files.forEach(f=>console.log(f));"
28
28
  ```
29
29
 
30
30
  Read each to extract what was recently accomplished (one-liner per plan).
@@ -34,7 +34,7 @@ Display banner based on active flags:
34
34
 
35
35
  Check that a project exists:
36
36
  ```bash
37
- python3 -c "import os; print('OK' if os.path.exists('.planning/PROJECT.md') else 'MISSING')"
37
+ node -e "const fs=require('fs'); console.log(fs.existsSync('.planning/PROJECT.md') ? 'OK' : 'MISSING')"
38
38
  ```
39
39
 
40
40
  If PROJECT.md missing: stop — run `new-project` first. Quick tasks require an active project.
@@ -46,13 +46,15 @@ Generate a slug from the description (lowercase, hyphens, max 40 chars).
46
46
  Find the next task number:
47
47
  ```bash
48
48
  ls .planning/quick/ 2>/dev/null | grep -E "^[0-9]+" | sort -n | tail -1
49
+ # PowerShell: Get-ChildItem .planning/quick/ -ErrorAction SilentlyContinue | Where-Object { $_.Name -match '^[0-9]+' } | Sort-Object Name | Select-Object -Last 1
49
50
  ```
50
51
 
51
52
  Set `NEXT_NUM` to the next available number (001, 002, etc.).
52
53
 
53
54
  Create task directory:
54
55
  ```bash
55
- mkdir -p ".planning/quick/${NEXT_NUM}-${SLUG}"
56
+ node -e "require('fs').mkdirSync('.planning/quick/${NEXT_NUM}-${SLUG}',{recursive:true})"
57
+ # PowerShell: New-Item -ItemType Directory -Force -Path ".planning/quick/${NEXT_NUM}-${SLUG}"
56
58
  ```
57
59
 
58
60
  Report: "Creating quick task ${NEXT_NUM}: ${DESCRIPTION}"
@@ -130,7 +132,7 @@ If `--full`: also include `must_haves` in plan frontmatter (truths, artifacts, k
130
132
 
131
133
  Verify plan was created (substitute actual NEXT_NUM and SLUG values):
132
134
  ```bash
133
- python3 -c "import os; print('OK' if os.path.exists('.planning/quick/NEXT_NUM-SLUG/NEXT_NUM-PLAN.md') else 'MISSING')"
135
+ node -e "const fs=require('fs'); console.log(fs.existsSync('.planning/quick/NEXT_NUM-SLUG/NEXT_NUM-PLAN.md') ? 'OK' : 'MISSING')"
134
136
  ```
135
137
 
136
138
  ## Step 5: Plan Check (only with `--full`)
@@ -168,10 +168,10 @@ curl -s -X POST \
168
168
  \"tag_name\": \"vX.Y.Z\",
169
169
  \"target_commitish\": \"main\",
170
170
  \"name\": \"vX.Y.Z — [Short title]\",
171
- \"body\": $(echo "$RELEASE_NOTES" | python3 -c 'import sys,json; print(json.dumps(sys.stdin.read()))'),
171
+ \"body\": $(node -e "process.stdout.write(JSON.stringify(require('fs').readFileSync('/dev/stdin','utf8')))" <<< "$RELEASE_NOTES"),
172
172
  \"draft\": false,
173
173
  \"prerelease\": false
174
- }" | python3 -c "import sys,json; r=json.load(sys.stdin); print(r.get('html_url', r.get('message','ERROR')))"
174
+ }" | node -e "let d='';process.stdin.on('data',c=>d+=c).on('end',()=>{const r=JSON.parse(d);console.log(r.html_url||r.message||'ERROR');})"
175
175
  ```
176
176
 
177
177
  If successful, the release URL is printed.
@@ -198,6 +198,7 @@ git remote -v
198
198
  ```bash
199
199
  git log --oneline public-main -3 # new release commit at top
200
200
  git tag --sort=-version:refname | head -5 # new tag at top
201
+ # PowerShell: git tag --sort=-version:refname | Select-Object -First 5
201
202
  ```
202
203
 
203
204
  Open the release URL printed in Step 11 to confirm it looks correct on GitHub.
@@ -22,7 +22,7 @@ Example: remove-phase 7
22
22
 
23
23
  Check roadmap exists:
24
24
  ```bash
25
- python3 -c "import os; print('OK' if os.path.exists('.planning/ROADMAP.md') else 'MISSING')"
25
+ node -e "const fs=require('fs'); console.log(fs.existsSync('.planning/ROADMAP.md') ? 'OK' : 'MISSING')"
26
26
  ```
27
27
 
28
28
  ## Step 2: Verify the Phase is Future
@@ -13,7 +13,7 @@ Run standalone domain research for a phase. Useful when the domain is unfamiliar
13
13
  ## Step 1: Validate Phase
14
14
 
15
15
  ```bash
16
- python3 -c "import os; print('OK' if os.path.exists('.planning/ROADMAP.md') else 'MISSING')"
16
+ node -e "const fs=require('fs'); console.log(fs.existsSync('.planning/ROADMAP.md') ? 'OK' : 'MISSING')"
17
17
  ```
18
18
 
19
19
  Find phase `[N]` in ROADMAP.md:
@@ -9,9 +9,9 @@ Instantly restore full project context. Use when starting a new session, returni
9
9
  ## Step 1: Check Planning Structure
10
10
 
11
11
  ```bash
12
- python3 -c "import os; print('HAS_STATE' if os.path.exists('.planning/STATE.md') else 'NO_STATE')"
13
- python3 -c "import os; print('HAS_PROJECT' if os.path.exists('.planning/PROJECT.md') else 'NO_PROJECT')"
14
- python3 -c "import os; print('HAS_ROADMAP' if os.path.exists('.planning/ROADMAP.md') else 'NO_ROADMAP')"
12
+ node -e "const fs=require('fs'); console.log(fs.existsSync('.planning/STATE.md') ? 'HAS_STATE' : 'NO_STATE')"
13
+ node -e "const fs=require('fs'); console.log(fs.existsSync('.planning/PROJECT.md') ? 'HAS_PROJECT' : 'NO_PROJECT')"
14
+ node -e "const fs=require('fs'); console.log(fs.existsSync('.planning/ROADMAP.md') ? 'HAS_ROADMAP' : 'NO_ROADMAP')"
15
15
  ```
16
16
 
17
17
  If nothing exists: stop — run `new-project` to start a project.
@@ -51,12 +51,12 @@ Stop.
51
51
  Update the `model_profile` field in `.planning/config.json`:
52
52
 
53
53
  ```bash
54
- python3 -c "
55
- import json
56
- cfg = json.load(open('.planning/config.json'))
57
- cfg['model_profile'] = '[profile]'
58
- json.dump(cfg, open('.planning/config.json', 'w'), indent=2)
59
- print('Updated.')
54
+ node -e "
55
+ const fs=require('fs');
56
+ const cfg=JSON.parse(fs.readFileSync('.planning/config.json','utf8'));
57
+ cfg.model_profile='[profile]';
58
+ fs.writeFileSync('.planning/config.json',JSON.stringify(cfg,null,2));
59
+ console.log('Updated.');
60
60
  "
61
61
  ```
62
62
 
@@ -11,7 +11,7 @@ Interactive configuration editor for the current project. Updates `.planning/con
11
11
  ## Step 1: Ensure Config Exists
12
12
 
13
13
  ```bash
14
- python3 -c "import os; print('exists' if os.path.exists('.planning/config.json') else 'missing')"
14
+ node -e "const fs=require('fs'); console.log(fs.existsSync('.planning/config.json') ? 'exists' : 'missing')"
15
15
  ```
16
16
 
17
17
  If missing, create from template:
@@ -97,7 +97,7 @@ Confirm both clones succeeded — `SKILL.md` must exist in `$AGENTIC_LEARN_TMP`
97
97
 
98
98
  ```bash
99
99
  BACKUP_DIR="$(pwd)/.windsurf/skills/.upstream-backup-$(date +%Y%m%d-%H%M%S)"
100
- mkdir -p "$BACKUP_DIR"
100
+ node -e "require('fs').mkdirSync('$BACKUP_DIR',{recursive:true})"
101
101
 
102
102
  cp -r "$(pwd)/.windsurf/skills/agentic-learning" "$BACKUP_DIR/agentic-learning"
103
103
  cp -r "$(pwd)/.windsurf/skills/impeccable" "$BACKUP_DIR/impeccable"
@@ -27,7 +27,7 @@ find .planning/ -name "*.md" | sort
27
27
 
28
28
  Read the most recent SUMMARY.md files (last 3 phases):
29
29
  ```bash
30
- ls -t .planning/phases/*/*-SUMMARY.md 2>/dev/null | head -6
30
+ node -e "const fs=require('fs'),path=require('path');function find(d){let r=[];try{for(const e of fs.readdirSync(d,{withFileTypes:true})){const f=path.join(d,e.name);r=r.concat(e.isDirectory()?find(f):e.name.endsWith('-SUMMARY.md')?[f]:[]);}}catch(e){}return r;}const files=find('.planning/phases').map(f=>({f,t:fs.statSync(f).mtimeMs})).sort((a,b)=>b.t-a.t).slice(0,6).map(x=>x.f);files.forEach(f=>console.log(f));"
31
31
  ```
32
32
 
33
33
  Check git status:
@@ -35,6 +35,7 @@ for loc in \
35
35
  "$HOME/favio/learnship" \
36
36
  "$HOME/learnship" \
37
37
  "$(find $HOME -name "install.sh" -path "*/learnship/*" 2>/dev/null | head -1 | xargs dirname 2>/dev/null)"; do
38
+ # PowerShell: (Get-ChildItem $HOME -Recurse -Filter install.sh -ErrorAction SilentlyContinue | Where-Object { $_.FullName -match 'learnship' } | Select-Object -First 1).DirectoryName
38
39
  test -d "$loc/.windsurf/workflows" && SOURCE_DIR="$loc" && break
39
40
  done
40
41
  ```
@@ -93,7 +94,7 @@ Stop.
93
94
  For any workflow file that exists in install dir AND differs from source AND differs from the current source (meaning you modified it):
94
95
 
95
96
  ```bash
96
- mkdir -p "$INSTALL_DIR/local-patches"
97
+ node -e "require('fs').mkdirSync('$INSTALL_DIR/local-patches',{recursive:true})"
97
98
  ```
98
99
 
99
100
  For each locally modified file:
@@ -22,7 +22,7 @@ If `nyquist_validation: false`: stop — "Validation is disabled. Enable it in `
22
22
  ## Step 2: Validate Phase
23
23
 
24
24
  ```bash
25
- python3 -c "import os; print('OK' if os.path.exists('.planning/ROADMAP.md') else 'MISSING')"
25
+ node -e "const fs=require('fs'); console.log(fs.existsSync('.planning/ROADMAP.md') ? 'OK' : 'MISSING')"
26
26
  ```
27
27
 
28
28
  Determine the phase directory:
@@ -61,6 +61,7 @@ Extract:
61
61
  find . \( -name "jest.config.*" -o -name "vitest.config.*" -o -name "pytest.ini" -o -name "pyproject.toml" \) -not -path "*/node_modules/*" 2>/dev/null
62
62
 
63
63
  find . \( -name "*.test.*" -o -name "*.spec.*" -o -name "test_*.py" \) -not -path "*/node_modules/*" 2>/dev/null | head -20
64
+ # PowerShell: Get-ChildItem -Recurse | Where-Object { $_.Name -match '\.test\.|spec\.|^test_.*\.py' -and $_.FullName -notmatch 'node_modules' } | Select-Object -First 20
64
65
  ```
65
66
 
66
67
  Identify: test framework, how to run tests, existing test file patterns.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "learnship",
3
- "version": "1.9.21",
3
+ "version": "1.9.22",
4
4
  "description": "Learn as you build. Build with intent. — A multi-platform agentic engineering system for Windsurf, Claude Code, Cursor, OpenCode, Gemini CLI, and Codex: spec-driven workflows, integrated learning, and production-grade design.",
5
5
  "keywords": [
6
6
  "agentic",
@@ -40,7 +40,7 @@ Configuration options for `.planning/` directory behavior.
40
40
 
41
41
  ```bash
42
42
  # Read commit_docs from config.json
43
- COMMIT_DOCS=$(python3 -c "import json; c=json.load(open('.planning/config.json')); print(c.get('planning',{}).get('commit_docs','true'))" 2>/dev/null || echo 'true')
43
+ COMMIT_DOCS=$(node -e "try{const c=JSON.parse(require('fs').readFileSync('.planning/config.json','utf8'));process.stdout.write(String((c.planning||{}).commit_docs??'true'));}catch(e){process.stdout.write('true');}" 2>/dev/null || echo 'true')
44
44
  ```
45
45
 
46
46
  **Auto-detection:** If `.planning/` is gitignored, treat `commit_docs` as `false` regardless of config.json. This prevents git errors.
@@ -139,7 +139,7 @@ To use uncommitted mode:
139
139
 
140
140
  Read config directly:
141
141
  ```bash
142
- python3 -c "import json; c=json.load(open('.planning/config.json')); g=c.get('git',{}); print(g.get('branching_strategy','none'), g.get('phase_branch_template','phase-{phase}-{slug}'), g.get('milestone_branch_template','{milestone}-{slug}'))"
142
+ node -e "const c=JSON.parse(require('fs').readFileSync('.planning/config.json','utf8')),g=c.git||{};console.log(g.branching_strategy||'none',g.phase_branch_template||'phase-{phase}-{slug}',g.milestone_branch_template||'{milestone}-{slug}')"
143
143
  ```
144
144
 
145
145
  **Branch creation:**