tlc-claude-code 2.5.0 → 2.6.1

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 (76) hide show
  1. package/.claude/commands/tlc/autofix.md +34 -1
  2. package/.claude/commands/tlc/build.md +164 -6
  3. package/.claude/commands/tlc/ci.md +178 -414
  4. package/.claude/commands/tlc/coverage.md +34 -0
  5. package/.claude/commands/tlc/deploy.md +19 -6
  6. package/.claude/commands/tlc/discuss.md +34 -0
  7. package/.claude/commands/tlc/docs.md +35 -1
  8. package/.claude/commands/tlc/e2e.md +300 -0
  9. package/.claude/commands/tlc/edge-cases.md +35 -1
  10. package/.claude/commands/tlc/init.md +38 -8
  11. package/.claude/commands/tlc/new-project.md +46 -4
  12. package/.claude/commands/tlc/plan.md +33 -0
  13. package/.claude/commands/tlc/quick.md +33 -0
  14. package/.claude/commands/tlc/release.md +85 -135
  15. package/.claude/commands/tlc/restore.md +14 -0
  16. package/.claude/commands/tlc/review.md +76 -1
  17. package/.claude/commands/tlc/tlc.md +134 -0
  18. package/.claude/commands/tlc/verify.md +64 -65
  19. package/.claude/commands/tlc/watchci.md +10 -0
  20. package/.claude/hooks/tlc-block-tools.sh +13 -0
  21. package/.claude/hooks/tlc-session-init.sh +29 -0
  22. package/CODING-STANDARDS.md +35 -10
  23. package/package.json +1 -1
  24. package/server/lib/block-tools-hook.js +23 -0
  25. package/server/lib/e2e/acceptance-parser.js +132 -0
  26. package/server/lib/e2e/acceptance-parser.test.js +110 -0
  27. package/server/lib/e2e/framework-detector.js +47 -0
  28. package/server/lib/e2e/framework-detector.test.js +94 -0
  29. package/server/lib/e2e/log-assertions.js +107 -0
  30. package/server/lib/e2e/log-assertions.test.js +68 -0
  31. package/server/lib/e2e/test-generator.js +159 -0
  32. package/server/lib/e2e/test-generator.test.js +121 -0
  33. package/server/lib/e2e/verify-runner.js +191 -0
  34. package/server/lib/e2e/verify-runner.test.js +167 -0
  35. package/server/lib/hooks/block-tools-hook.test.js +54 -0
  36. package/server/lib/orchestration/cli-dispatch.js +16 -1
  37. package/server/lib/orchestration/cli-dispatch.test.js +94 -8
  38. package/server/lib/orchestration/completion-checker.js +101 -0
  39. package/server/lib/orchestration/completion-checker.test.js +177 -0
  40. package/server/lib/orchestration/result-verifier.js +143 -0
  41. package/server/lib/orchestration/result-verifier.test.js +291 -0
  42. package/server/lib/orchestration/session-dispatcher.js +99 -0
  43. package/server/lib/orchestration/session-dispatcher.test.js +215 -0
  44. package/server/lib/orchestration/session-status.js +147 -0
  45. package/server/lib/orchestration/session-status.test.js +130 -0
  46. package/server/lib/release/agent-runner-updates.js +24 -0
  47. package/server/lib/release/agent-runner-updates.test.js +22 -0
  48. package/server/lib/release/changelog-generator.js +142 -0
  49. package/server/lib/release/changelog-generator.test.js +113 -0
  50. package/server/lib/release/ci-watcher.js +83 -0
  51. package/server/lib/release/ci-watcher.test.js +81 -0
  52. package/server/lib/release/health-checker.js +111 -0
  53. package/server/lib/release/health-checker.test.js +121 -0
  54. package/server/lib/release/release-pipeline.js +187 -0
  55. package/server/lib/release/release-pipeline.test.js +262 -0
  56. package/server/lib/release/version-bumper.js +183 -0
  57. package/server/lib/release/version-bumper.test.js +142 -0
  58. package/server/lib/routing-preamble.integration.test.js +12 -0
  59. package/server/lib/routing-preamble.js +13 -2
  60. package/server/lib/routing-preamble.test.js +49 -0
  61. package/server/lib/scaffolding/ci-detector.js +139 -0
  62. package/server/lib/scaffolding/ci-detector.test.js +198 -0
  63. package/server/lib/scaffolding/ci-scaffolder.js +347 -0
  64. package/server/lib/scaffolding/ci-scaffolder.test.js +157 -0
  65. package/server/lib/scaffolding/deploy-detector.js +135 -0
  66. package/server/lib/scaffolding/deploy-detector.test.js +106 -0
  67. package/server/lib/scaffolding/health-scaffold.js +374 -0
  68. package/server/lib/scaffolding/health-scaffold.test.js +99 -0
  69. package/server/lib/scaffolding/logger-scaffold.js +196 -0
  70. package/server/lib/scaffolding/logger-scaffold.test.js +146 -0
  71. package/server/lib/scaffolding/migration-detector.js +78 -0
  72. package/server/lib/scaffolding/migration-detector.test.js +127 -0
  73. package/server/lib/scaffolding/snapshot-manager.js +142 -0
  74. package/server/lib/scaffolding/snapshot-manager.test.js +225 -0
  75. package/server/lib/task-router-config.js +50 -20
  76. package/server/lib/task-router-config.test.js +29 -15
@@ -97,6 +97,40 @@ process.stdout.write(JSON.stringify(result));" 2>/dev/null
97
97
 
98
98
  **Override:** Pass `--model <name>` to route this specific run to a different model.
99
99
 
100
+ After `resolveRouting` returns, immediately write `.tlc/.discuss-routing-active` with the active provider name from `models[0]` before doing any other discuss work. Remove `.tlc/.discuss-routing-active` on completion, cancellation, or failure cleanup.
101
+
102
+ **Routing decision:**
103
+ - If routing says external provider (`models[0] !== 'claude'`), follow **ONLY ORCHESTRATOR MODE** below.
104
+ - If routing says Claude (`models[0] === 'claude'`), follow **INLINE MODE** below.
105
+
106
+ ## ORCHESTRATOR MODE
107
+
108
+ Use this mode only when `models[0]` is **NOT** `claude`.
109
+
110
+ Claude does not execute the discussion instructions inline in this path. Claude acts as the orchestrator for the routed provider run:
111
+
112
+ 1. Claude acts as the orchestrator for the routed implementation discussion instead of running the interview inline.
113
+ 2. Scan the roadmap, discussion history, relevant code, recent changes, and project conventions before dispatching discussion work.
114
+ 3. Package a prompt that asks the routed provider to propose a concrete implementation approach first, then surface only the highest-value confirm-or-correct questions.
115
+ 4. Dispatch through the provider CLI path, using `codex exec` for Codex-style providers or `gemini -p` for Gemini-style providers, preferably via the shared dispatch layer when available.
116
+ 5. Verify the routed discussion output before accepting it:
117
+ - Confirm it reflects the actual repo context instead of asking the user to restate known facts.
118
+ - Confirm it leads with a recommendation, then asks only material decision questions.
119
+ - Reject vague brainstorming output or question lists that do not advance the phase.
120
+ 6. If the routed response misses key architectural context or asks low-value questions, issue a focused follow-up dispatch to tighten the discussion.
121
+ 7. Handle failures explicitly:
122
+ - If dispatch fails because of model mismatch, auth, or missing CLI, check `.tlc/.router-state.json` for the provider's actual available model and retry once with the corrected model.
123
+ - If retry still fails, stop and report the exact failure to the user. Do not silently fall back to Claude inline execution.
124
+ - If the provider returns weak discovery output, reject it and rerun with explicit context and decision targets.
125
+ 8. When finished, display the routed discussion result, persist any captured memory, remove `.tlc/.discuss-routing-active`, and stop. Do **not** execute Inline Mode afterward.
126
+
127
+ ## INLINE MODE
128
+
129
+ Use this mode only when `models[0]` **IS** `claude`.
130
+
131
+ The existing discussion instructions below are the Inline Mode instructions and should be followed unchanged.
132
+
133
+
100
134
  ## What This Does
101
135
 
102
136
  Runs a short implementation interview for the current phase using a silent expansion workflow:
@@ -95,7 +95,41 @@ process.stdout.write(JSON.stringify(result));" 2>/dev/null
95
95
  - Execute inline (Claude) AND dispatch to CLI models simultaneously
96
96
  - Collect and merge results
97
97
 
98
- **Override:** Pass `--model <name>` to route this specific run to a different model.
98
+ **Override:** Pass `--model <name>` to route this specific run to a different model.
99
+
100
+ After `resolveRouting` returns, immediately write `.tlc/.docs-routing-active` with the active provider name from `models[0]` before doing any other docs work. Remove `.tlc/.docs-routing-active` on completion, cancellation, or failure cleanup.
101
+
102
+ **Routing decision:**
103
+ - If routing says external provider (`models[0] !== 'claude'`), follow **ONLY ORCHESTRATOR MODE** below.
104
+ - If routing says Claude (`models[0] === 'claude'`), follow **INLINE MODE** below.
105
+
106
+ ## ORCHESTRATOR MODE
107
+
108
+ Use this mode only when `models[0]` is **NOT** `claude`.
109
+
110
+ Claude does not execute the documentation instructions inline in this path. Claude acts as the orchestrator for the routed provider run:
111
+
112
+ 1. Claude acts as the orchestrator for routed documentation work instead of maintaining docs inline.
113
+ 2. Gather the relevant repository context, documentation targets, configured docs settings, and any screenshot or API-doc generation expectations before dispatch.
114
+ 3. Break the docs work into focused slices when useful, such as README updates, API docs generation, screenshot capture guidance, or automation setup.
115
+ 4. Dispatch through the provider CLI path, using `codex exec` for Codex-style providers or `gemini -p` for Gemini-style providers, preferably via the shared dispatch layer when available.
116
+ 5. Verify the routed result before accepting it:
117
+ - Confirm the documentation changes match the current codebase and command intent.
118
+ - Confirm generated instructions or automation steps are specific enough to execute in this repo.
119
+ - Reject stale, generic, or obviously hallucinated documentation output.
120
+ 6. If the routed work comes back incomplete, dispatch follow-up tasks for the missing documentation slices rather than declaring success.
121
+ 7. Handle failures explicitly:
122
+ - If dispatch fails because of model mismatch, auth, or missing CLI, check `.tlc/.router-state.json` for the provider's actual available model and retry once with the corrected model.
123
+ - If retry still fails, stop and report the exact failure to the user. Do not silently fall back to Claude inline execution.
124
+ - If the provider returns low-confidence docs or broken setup steps, request a targeted correction before continuing.
125
+ 8. When finished, display the routed documentation result, persist any captured memory, remove `.tlc/.docs-routing-active`, and stop. Do **not** execute Inline Mode afterward.
126
+
127
+ ## INLINE MODE
128
+
129
+ Use this mode only when `models[0]` **IS** `claude`.
130
+
131
+ The existing documentation instructions below are the Inline Mode instructions and should be followed unchanged.
132
+
99
133
 
100
134
  ## Usage
101
135
 
@@ -0,0 +1,300 @@
1
+ # /tlc:e2e - Generate Phase E2E Tests
2
+
3
+ Parse acceptance criteria from a phase `PLAN.md`, generate matching E2E test files, scaffold an E2E framework if missing, run the generated tests to verify they execute, and commit the result.
4
+
5
+ ## Routing
6
+
7
+ This command supports multi-model routing via `~/.tlc/config.json`.
8
+
9
+ **Before executing this command:**
10
+
11
+ 1. Read routing config:
12
+ ```bash
13
+ node -e "const fs = require('fs');
14
+ const path = require('path');
15
+ const os = require('os');
16
+ function readJson(filePath, fileSystem) {
17
+ try {
18
+ return JSON.parse(fileSystem.readFileSync(filePath, 'utf8'));
19
+ } catch {
20
+ return null;
21
+ }
22
+ }
23
+ function loadPersonalConfig(options) {
24
+ const configPath = path.join(options.homeDir, '.tlc', 'config.json');
25
+ return readJson(configPath, options.fs);
26
+ }
27
+ function loadProjectOverride(options) {
28
+ const configPath = path.join(options.projectDir, '.tlc.json');
29
+ const data = readJson(configPath, options.fs);
30
+ return data && data.task_routing_override ? data.task_routing_override : null;
31
+ }
32
+ function resolveRouting(options) {
33
+ let models = ['claude'];
34
+ let strategy = 'single';
35
+ let source = 'shipped-defaults';
36
+ let providers;
37
+ const personal = loadPersonalConfig({ homeDir: options.homeDir, fs: options.fs });
38
+ if (personal) {
39
+ if (personal.model_providers) {
40
+ providers = personal.model_providers;
41
+ }
42
+ const personalRouting = personal.task_routing && personal.task_routing[options.command];
43
+ if (personalRouting) {
44
+ if (Array.isArray(personalRouting.models)) {
45
+ models = personalRouting.models.slice();
46
+ } else if (typeof personalRouting.model === 'string') {
47
+ models = [personalRouting.model];
48
+ }
49
+ if (personalRouting.strategy) {
50
+ strategy = personalRouting.strategy;
51
+ }
52
+ source = 'personal-config';
53
+ }
54
+ }
55
+ const projectOverride = loadProjectOverride({ projectDir: options.projectDir, fs: options.fs });
56
+ if (projectOverride) {
57
+ const overrideEntry = projectOverride[options.command];
58
+ if (overrideEntry) {
59
+ if (Array.isArray(overrideEntry.models)) {
60
+ models = overrideEntry.models.slice();
61
+ } else if (typeof overrideEntry.model === 'string') {
62
+ models = [overrideEntry.model];
63
+ }
64
+ if (overrideEntry.strategy) {
65
+ strategy = overrideEntry.strategy;
66
+ }
67
+ source = 'project-override';
68
+ }
69
+ }
70
+ if (options.flagModel) {
71
+ models = [options.flagModel];
72
+ strategy = 'single';
73
+ source = 'flag-override';
74
+ }
75
+ const result = { models, strategy, source };
76
+ if (providers) {
77
+ result.providers = providers;
78
+ }
79
+ return result;
80
+ }
81
+ const result = resolveRouting({ command: \"e2e\", flagModel: process.argv[1], projectDir: process.cwd(), homeDir: process.env.HOME || os.homedir(), fs });
82
+ process.stdout.write(JSON.stringify(result));" 2>/dev/null
83
+ ```
84
+
85
+ 2. If `models[0]` is NOT `claude`:
86
+ - Read `PROJECT.md`, the target phase `PLAN.md`, and `.tlc.json`
87
+ - Package the agent prompt below with project context
88
+ - Dispatch to the routed CLI
89
+ - Display the CLI output and stop
90
+
91
+ 3. If `models[0]` IS `claude`:
92
+ - Execute the agent prompt below as normal
93
+
94
+ 4. If `strategy` is `parallel`:
95
+ - Execute inline and dispatch to external providers simultaneously
96
+ - Collect and merge results
97
+
98
+ **Override:** Pass `--model <name>` to route this specific run to a different model.
99
+
100
+ After `resolveRouting` returns, immediately write `.tlc/.e2e-routing-active` with the active provider name from `models[0]` before doing any other e2e work. Remove `.tlc/.e2e-routing-active` on completion, cancellation, or failure cleanup.
101
+
102
+ ## What This Does
103
+
104
+ 1. Resolves the target phase
105
+ 2. Reads the phase `PLAN.md`
106
+ 3. Parses task acceptance criteria into automatable E2E scenarios
107
+ 4. Detects or scaffolds an E2E framework
108
+ 5. Generates E2E test files
109
+ 6. Runs only the generated tests to verify they execute
110
+ 7. Reports `N generated, M skipped (manual)`
111
+ 8. Commits the generated files and framework scaffolding
112
+
113
+ ## Usage
114
+
115
+ ```text
116
+ /tlc:e2e
117
+ /tlc:e2e 7
118
+ ```
119
+
120
+ If no phase is provided, auto-detect the active phase from `ROADMAP.md` or fall back to the latest incomplete phase plan.
121
+
122
+ ## Process
123
+
124
+ ### Step 1: Resolve the Target Phase
125
+
126
+ Determine the phase in this order:
127
+
128
+ 1. Explicit `[phase]` argument
129
+ 2. Active/current/in-progress phase in `ROADMAP.md`
130
+ 3. Highest-numbered `.planning/phases/*-PLAN.md` without a matching `*-VERIFIED.md`
131
+
132
+ Target file:
133
+
134
+ ```text
135
+ .planning/phases/{N}-PLAN.md
136
+ ```
137
+
138
+ If the plan file does not exist, stop and report the missing path.
139
+
140
+ ### Step 2: Load Plan Context
141
+
142
+ Read:
143
+ - `.planning/phases/{N}-PLAN.md`
144
+ - `.planning/phases/{N}-DISCUSSION.md` if present
145
+ - `PROJECT.md` if present
146
+ - `.tlc.json` if present
147
+
148
+ Extract each task block and its acceptance criteria. Use the acceptance criteria as the source of truth for E2E generation.
149
+
150
+ ### Step 3: Parse Acceptance Criteria
151
+
152
+ Use `server/lib/e2e/acceptance-parser.js` to normalize acceptance criteria for each task.
153
+
154
+ Rules:
155
+ - Parse task-by-task, not as one giant phase blob
156
+ - Preserve the task title as the scenario name
157
+ - Treat parser items with `type: 'manual'` as manual verification only
158
+ - Do not generate automated tests for manual-only criteria
159
+ - If a task has both automatable and manual criteria, generate tests for the automatable criteria and count the manual criteria as skipped
160
+
161
+ Summary counters:
162
+ - `generated`: number of generated E2E files written
163
+ - `skipped (manual)`: number of acceptance criteria skipped because they require manual verification
164
+
165
+ ### Step 4: Detect or Scaffold the E2E Framework
166
+
167
+ Use `server/lib/e2e/framework-detector.js`.
168
+
169
+ Framework selection rules:
170
+ - If Playwright is already configured, use Playwright
171
+ - Else if the repo already uses `supertest` for API-level E2E coverage, use Supertest
172
+ - Else scaffold Playwright by default
173
+
174
+ When scaffolding Playwright:
175
+ - Add `playwright.config.ts` if missing
176
+ - Create `tests/e2e/` if no E2E directory exists
177
+ - Add `@playwright/test` to `devDependencies` if missing
178
+ - Add or update package scripts so generated tests can run cleanly
179
+
180
+ When scaffolding Supertest:
181
+ - Only choose this path for service-only repos with an existing Vitest/Jest-style API test setup
182
+ - Reuse the project's current test runner instead of inventing a new one
183
+
184
+ Do not replace an established framework just because another one is available.
185
+
186
+ ### Step 5: Generate Test Files
187
+
188
+ Use `server/lib/e2e/test-generator.js` to generate the file bodies, then write the files into the detected E2E directory.
189
+
190
+ Generation rules:
191
+ - One generated file per task/scenario
192
+ - Generated files must map directly to that task's acceptance criteria
193
+ - Add a short generated header comment at the top of each file:
194
+ `Generated by /tlc:e2e from .planning/phases/{N}-PLAN.md`
195
+ - Prefer stable filenames derived from the task title slug
196
+ - Keep generated files idempotent: if the command is run again, update previously generated files in place
197
+ - Never overwrite clearly hand-written E2E files that do not contain the generated header comment
198
+
199
+ If a target file already exists and appears hand-written:
200
+ - Skip it
201
+ - Report it separately as a preserved manual file
202
+ - Do not include it in `skipped (manual)` unless the acceptance criteria were also classified as manual
203
+
204
+ ### Step 6: Run the Generated Tests
205
+
206
+ Run only the generated files.
207
+
208
+ Playwright:
209
+ ```bash
210
+ npx playwright test <generated-files> --reporter=list
211
+ ```
212
+
213
+ Supertest with Vitest:
214
+ ```bash
215
+ npx vitest run <generated-files>
216
+ ```
217
+
218
+ Verification rules:
219
+ - The generated tests must be discovered by the runner
220
+ - They must execute without syntax errors, import errors, or framework bootstrapping failures
221
+ - If the framework was scaffolded, verify the scaffolding in the same run
222
+ - If execution fails because the repo is missing dependencies, install the minimum required dependencies and rerun
223
+ - If execution still fails, stop and report the exact failure instead of committing broken scaffolding
224
+
225
+ ### Step 7: Commit
226
+
227
+ Commit when done. This is mandatory if generation and execution verification succeed.
228
+
229
+ Stage only the files created or updated for this command:
230
+ - Generated E2E files
231
+ - Framework config or package manifest changes required for E2E
232
+ - Lockfile updates if dependencies were installed
233
+
234
+ Commit message:
235
+
236
+ ```bash
237
+ git commit -m "test(e2e): generate phase {N} coverage"
238
+ ```
239
+
240
+ ### Step 8: Report
241
+
242
+ Return a compact summary:
243
+
244
+ ```text
245
+ Phase {N} E2E generation complete
246
+ Framework: playwright | supertest
247
+ Generated: {N}
248
+ Skipped (manual): {M}
249
+ Preserved manual files: {K}
250
+ Verification: passed
251
+ Commit: {sha}
252
+ ```
253
+
254
+ If verification failed, report:
255
+ - framework used
256
+ - generated file count
257
+ - skipped manual count
258
+ - exact command run
259
+ - exact error
260
+ - whether files were left uncommitted
261
+
262
+ ## Guard Rails
263
+
264
+ - Do not invent scenarios not grounded in acceptance criteria
265
+ - Do not overwrite hand-written E2E tests
266
+ - Do not claim success if the generated tests were not actually executed
267
+ - Do not commit if execution verification failed
268
+ - Keep generation scoped to the requested phase
269
+ - Prefer preserving existing repo conventions over TLC defaults
270
+
271
+ ## Example
272
+
273
+ ```text
274
+ > /tlc:e2e 7
275
+
276
+ Loading .planning/phases/7-PLAN.md...
277
+ Parsing acceptance criteria...
278
+
279
+ Detected framework: none
280
+ Scaffolding Playwright...
281
+
282
+ Generating E2E files...
283
+ Created tests/e2e/user-login.test.ts
284
+ Created tests/e2e/reset-password.test.ts
285
+ Created tests/e2e/session-timeout.test.ts
286
+
287
+ Running generated tests...
288
+ 3 files discovered
289
+ 3 files executed successfully
290
+
291
+ Committed: test(e2e): generate phase 7 coverage
292
+
293
+ Phase 7 E2E generation complete
294
+ Framework: playwright
295
+ Generated: 3
296
+ Skipped (manual): 2
297
+ Preserved manual files: 0
298
+ Verification: passed
299
+ Commit: abc1234
300
+ ```
@@ -95,7 +95,41 @@ process.stdout.write(JSON.stringify(result));" 2>/dev/null
95
95
  - Execute inline (Claude) AND dispatch to CLI models simultaneously
96
96
  - Collect and merge results
97
97
 
98
- **Override:** Pass `--model <name>` to route this specific run to a different model.
98
+ **Override:** Pass `--model <name>` to route this specific run to a different model.
99
+
100
+ After `resolveRouting` returns, immediately write `.tlc/.edge-cases-routing-active` with the active provider name from `models[0]` before doing any other edge-cases work. Remove `.tlc/.edge-cases-routing-active` on completion, cancellation, or failure cleanup.
101
+
102
+ **Routing decision:**
103
+ - If routing says external provider (`models[0] !== 'claude'`), follow **ONLY ORCHESTRATOR MODE** below.
104
+ - If routing says Claude (`models[0] === 'claude'`), follow **INLINE MODE** below.
105
+
106
+ ## ORCHESTRATOR MODE
107
+
108
+ Use this mode only when `models[0]` is **NOT** `claude`.
109
+
110
+ Claude does not execute the edge-case generation instructions inline in this path. Claude acts as the orchestrator for the routed provider run:
111
+
112
+ 1. Claude acts as the orchestrator for routed edge-case analysis and test generation instead of doing that analysis inline.
113
+ 2. Read the target file or function context, current test setup, and project conventions before dispatching the request.
114
+ 3. Package a prompt that asks the routed provider to identify meaningful edge cases, generate test coverage for them, and keep the output aligned with the project's existing test patterns.
115
+ 4. Dispatch through the provider CLI path, using `codex exec` for Codex-style providers or `gemini -p` for Gemini-style providers, preferably via the shared dispatch layer when available.
116
+ 5. Verify the routed result before accepting it:
117
+ - Confirm the generated edge cases are grounded in the actual target behavior and parameter surface.
118
+ - Confirm the tests are non-duplicative and materially improve coverage.
119
+ - Reject generic or mechanically generated cases that do not map to the real code.
120
+ 6. If the routed output misses important boundary conditions or produces weak tests, dispatch a focused follow-up for the missing scenarios.
121
+ 7. Handle failures explicitly:
122
+ - If dispatch fails because of model mismatch, auth, or missing CLI, check `.tlc/.router-state.json` for the provider's actual available model and retry once with the corrected model.
123
+ - If retry still fails, stop and report the exact failure to the user. Do not silently fall back to Claude inline execution.
124
+ - If the provider returns malformed or low-value test output, reject it and request a constrained retry.
125
+ 8. When finished, display the routed edge-case result, persist any captured memory, remove `.tlc/.edge-cases-routing-active`, and stop. Do **not** execute Inline Mode afterward.
126
+
127
+ ## INLINE MODE
128
+
129
+ Use this mode only when `models[0]` **IS** `claude`.
130
+
131
+ The existing edge-case generation instructions below are the Inline Mode instructions and should be followed unchanged.
132
+
99
133
 
100
134
  ## What This Does
101
135
 
@@ -136,7 +136,37 @@ Add test scripts to package.json:
136
136
  }
137
137
  ```
138
138
 
139
- ### 5. If Tests Already Exist
139
+ ### 5. Scaffold Observability
140
+
141
+ 1. Detect deploy target: run `server/lib/scaffolding/deploy-detector.js` `detectDeployTarget({ projectDir })`
142
+ - If result is `"unknown"`, ask user: `"Deploy target? 1) Docker Compose 2) Kubernetes/k3s 3) VPS 4) Not sure"`
143
+ - Store result in `.tlc.json` under `deploy.target`
144
+ 2. Scaffold logger: run `server/lib/scaffolding/logger-scaffold.js` `scaffoldLogger({ projectDir, language })`
145
+ - If skipped (existing logger found), report: `"Existing logger detected — skipping"`
146
+ - If generated, report files created and dependencies to install
147
+ 3. Scaffold health endpoint: run `server/lib/scaffolding/health-scaffold.js` `scaffoldHealth({ projectDir, deployTarget, framework })`
148
+ - Report endpoint(s) created
149
+ 4. Enable snapshots: add to `.tlc.json`: `{ snapshots: { enabled: true, maxRetention: 10 } }`
150
+
151
+ ### 6. Detect CI/CD
152
+
153
+ After observability scaffolding, inspect the project's CI/CD posture:
154
+
155
+ 1. Detect CI: run `server/lib/scaffolding/ci-detector.js` `detectCI({ projectDir, fs })`
156
+ - Use the detector result fields: `platform`, `workflows`, and `gaps`
157
+ - Recognize `no-ci`, `missing-test-step`, `missing-deploy-step`, and `missing-coverage-upload`
158
+ 2. If no CI is found (`platform === "none"` or `gaps` includes `no-ci`):
159
+ - Scaffold GitHub Actions using `server/lib/scaffolding/ci-scaffolder.js`
160
+ - Report the workflow files created and any required secrets or environment variables
161
+ 3. If CI exists but has gaps:
162
+ - Report the existing CI platform and workflow files detected
163
+ - Report the missing capabilities from `gaps`
164
+ - Offer to fill the gaps instead of replacing the existing CI
165
+ 4. If CI is complete (`gaps.length === 0`):
166
+ - Report: `"CI/CD OK"`
167
+ - Include detected platform and workflow file paths in the summary
168
+
169
+ ### 7. If Tests Already Exist
140
170
 
141
171
  - Skip framework setup
142
172
  - Note existing test patterns for consistency
@@ -170,7 +200,7 @@ If option 2 selected, create multi-framework config:
170
200
  }
171
201
  ```
172
202
 
173
- ### 6. Analyze Existing Code Structure
203
+ ### 8. Analyze Existing Code Structure
174
204
 
175
205
  Scan the codebase and generate summary:
176
206
  - Main directories and their purpose
@@ -178,7 +208,7 @@ Scan the codebase and generate summary:
178
208
  - Entry points (main files, API routes, etc.)
179
209
  - Dependencies and their roles
180
210
 
181
- ### 7. Identify Untested Code
211
+ ### 9. Identify Untested Code
182
212
 
183
213
  Compare source files against test files to identify:
184
214
  - Modules/components with no corresponding tests
@@ -201,7 +231,7 @@ Untested:
201
231
  Critical paths without tests: 2 (auth, payments)
202
232
  ```
203
233
 
204
- ### 8. Offer Retrospective Test Writing
234
+ ### 10. Offer Retrospective Test Writing
205
235
 
206
236
  Ask the user:
207
237
 
@@ -406,7 +436,7 @@ Create `.claude/settings.json`:
406
436
 
407
437
  If `.claude/settings.json` already exists, merge: preserve existing permissions (union), add hooks section if missing (don't overwrite existing hooks).
408
438
 
409
- ### 10. Create or Update PROJECT.md
439
+ ### 11. Create or Update PROJECT.md
410
440
 
411
441
  If PROJECT.md doesn't exist, create it with:
412
442
 
@@ -441,7 +471,7 @@ Tests are written BEFORE implementation, not after.
441
471
 
442
472
  If PROJECT.md exists, append the TLC section only.
443
473
 
444
- ### 11. Set Up Documentation (Optional)
474
+ ### 12. Set Up Documentation (Optional)
445
475
 
446
476
  If the project doesn't have docs automation:
447
477
 
@@ -459,7 +489,7 @@ Set up documentation automation? (Y/n)
459
489
 
460
490
  If yes, run `/tlc:docs setup`.
461
491
 
462
- ### 12. Enterprise Features (Optional)
492
+ ### 13. Enterprise Features (Optional)
463
493
 
464
494
  After basic setup, offer enterprise features:
465
495
 
@@ -505,7 +535,7 @@ Commands available:
505
535
  /tlc:compliance - SOC 2 compliance dashboard
506
536
  ```
507
537
 
508
- ### 13. Report Summary
538
+ ### 14. Report Summary
509
539
 
510
540
  ```
511
541
  TLC initialized for [project name]
@@ -8,6 +8,7 @@ Initialize a new project with test-led development.
8
8
  2. Suggest tech stack based on your needs
9
9
  3. Create roadmap
10
10
  4. Set up test infrastructure
11
+ 5. Set up baseline CI workflow
11
12
 
12
13
  ## Process
13
14
 
@@ -146,6 +147,7 @@ Create PROJECT.md with tech decisions:
146
147
  | Database | PostgreSQL | Relational data needs |
147
148
  | Architecture | Modular monolith | Start simple |
148
149
  | Hosting | Docker + Railway | Easy CI/CD |
150
+ | CI/CD | GitHub Actions | Baseline test and deploy workflow |
149
151
 
150
152
  ## Constraints
151
153
  - Timeline: MVP in 4 weeks
@@ -272,6 +274,9 @@ Scaffold based on chosen stack:
272
274
  project/
273
275
  ├── src/
274
276
  ├── test/
277
+ ├── .github/
278
+ │ └── workflows/
279
+ │ └── ci.yml
275
280
  ├── .env.example
276
281
  ├── .tlc.json
277
282
  ├── .mocharc.json
@@ -309,7 +314,43 @@ Add to `package.json`:
309
314
  }
310
315
  ```
311
316
 
312
- ### Step 9: Set Up Documentation (Optional)
317
+ ### Step 9: Scaffold Observability
318
+
319
+ During project template generation, scaffold observability alongside the rest of the project setup:
320
+
321
+ 1. Detect deploy target: run `server/lib/scaffolding/deploy-detector.js` `detectDeployTarget({ projectDir })`
322
+ - If result is `"unknown"`, ask user: `"Deploy target? 1) Docker Compose 2) Kubernetes/k3s 3) VPS 4) Not sure"`
323
+ - Store result in `.tlc.json` under `deploy.target`
324
+ 2. Scaffold logger: run `server/lib/scaffolding/logger-scaffold.js` `scaffoldLogger({ projectDir, language })`
325
+ - If skipped (existing logger found), report: `"Existing logger detected — skipping"`
326
+ - If generated, report files created and dependencies to install
327
+ 3. Scaffold health endpoint: run `server/lib/scaffolding/health-scaffold.js` `scaffoldHealth({ projectDir, deployTarget, framework })`
328
+ - Report endpoint(s) created
329
+ 4. Enable snapshots: add to `.tlc.json`: `{ snapshots: { enabled: true, maxRetention: 10 } }`
330
+
331
+ ### Step 10: Detect and Scaffold CI Workflow
332
+
333
+ During project template generation, add CI/CD setup after observability:
334
+
335
+ 1. Detect CI: run `server/lib/scaffolding/ci-detector.js` `detectCI({ projectDir, fs })`
336
+ - Inspect `platform`, `workflows`, and `gaps`
337
+ 2. If no CI is found (`platform === "none"` or `gaps` includes `no-ci`):
338
+ - Scaffold GitHub Actions using `server/lib/scaffolding/ci-scaffolder.js`
339
+ - Include at least one workflow in `.github/workflows/` for tests, coverage, and deploy handoff where appropriate
340
+ - Report files created plus any secrets or variables still required
341
+ 3. If CI already exists but has gaps:
342
+ - Report the existing platform and workflow files
343
+ - Report the gaps found by the detector
344
+ - Offer to fill the gaps without replacing the current CI setup
345
+ 4. If CI is complete (`gaps.length === 0`):
346
+ - Report: `"CI/CD OK"`
347
+
348
+ Add CI metadata to the generated project template where applicable:
349
+ - CI platform: `[github-actions|jenkins|gitlab|circleci|none]`
350
+ - CI workflows: `[paths created or detected]`
351
+ - CI gaps: `[none|gap list]`
352
+
353
+ ### Step 11: Set Up Documentation (Optional)
313
354
 
314
355
  Offer to set up documentation automation:
315
356
 
@@ -330,7 +371,7 @@ If yes, run the docs setup:
330
371
  - Add `.github/workflows/docs-sync.yml`
331
372
  - Add npm scripts for docs maintenance
332
373
 
333
- ### Step 10: Enterprise Features (Optional)
374
+ ### Step 12: Enterprise Features (Optional)
334
375
 
335
376
  If compliance requirements were mentioned in Step 1, or for enterprise projects:
336
377
 
@@ -395,5 +436,6 @@ Interactive flow that:
395
436
  3. Lets you adjust
396
437
  4. Creates roadmap
397
438
  5. Sets up tests
398
- 6. Sets up documentation automation
399
- 7. Optionally enables enterprise features
439
+ 6. Scaffolds observability
440
+ 7. Sets up documentation automation
441
+ 8. Optionally enables enterprise features
@@ -97,6 +97,39 @@ process.stdout.write(JSON.stringify(result));" 2>/dev/null
97
97
 
98
98
  **Override:** Pass `--model <name>` to route this specific run to a different model.
99
99
 
100
+ After `resolveRouting` returns, immediately write `.tlc/.plan-routing-active` with the active provider name from `models[0]` before doing any other plan work. Remove `.tlc/.plan-routing-active` on completion, cancellation, or failure cleanup.
101
+
102
+ **Routing decision:**
103
+ - If routing says external provider (`models[0] !== 'claude'`), follow **ONLY ORCHESTRATOR MODE** below.
104
+ - If routing says Claude (`models[0] === 'claude'`), follow **INLINE MODE** below.
105
+
106
+ ## ORCHESTRATOR MODE
107
+
108
+ Use this mode only when `models[0]` is **NOT** `claude`.
109
+
110
+ Claude does not execute the planning instructions inline in this path. Claude acts as the orchestrator for the routed provider run:
111
+
112
+ 1. Read the roadmap, current phase context, discussion artifacts, project constraints, and any existing research before dispatching planning work.
113
+ 2. Prepare a full planning prompt that asks the routed provider to research, decompose, and sequence the phase using the project's architectural and task-quality standards.
114
+ 3. Dispatch through the provider CLI path, using `codex exec` for Codex-style providers or `gemini -p` for Gemini-style providers, preferably via the shared dispatch layer when available.
115
+ 4. Verify the returned plan before accepting it:
116
+ - Confirm it addresses the correct phase and reflects the actual roadmap goal.
117
+ - Confirm tasks are actionable, testable, dependency-aware, and aligned with file/folder sizing constraints.
118
+ - Confirm the plan contains real implementation thinking rather than generic project-management filler.
119
+ 5. If the first routed result is incomplete, contradictory, or too vague to execute, send a focused follow-up planning dispatch that requests the missing structure instead of accepting it.
120
+ 6. Handle failures explicitly:
121
+ - If dispatch fails because of model mismatch, auth, or missing CLI, check `.tlc/.router-state.json` for the provider's actual available model and retry once with the corrected model.
122
+ - If retry still fails, stop and report the exact failure to the user. Do not silently fall back to Claude inline execution.
123
+ - If the provider produces a weak plan, reject it and re-dispatch with tighter scope and success criteria.
124
+ 7. When finished, display the routed planning result, persist any captured memory, remove `.tlc/.plan-routing-active`, and stop. Do **not** execute Inline Mode afterward.
125
+
126
+ ## INLINE MODE
127
+
128
+ Use this mode only when `models[0]` **IS** `claude`.
129
+
130
+ The existing planning instructions below are the Inline Mode instructions and should be followed unchanged.
131
+
132
+
100
133
  ## Architectural Standards
101
134
 
102
135
  **Plan like a principal engineer designing for scale:**