tlc-claude-code 2.0.1 → 2.1.0

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 (86) hide show
  1. package/.claude/commands/tlc/deploy.md +194 -2
  2. package/.claude/commands/tlc/e2e-verify.md +214 -0
  3. package/.claude/commands/tlc/guard.md +191 -0
  4. package/.claude/commands/tlc/help.md +32 -0
  5. package/.claude/commands/tlc/init.md +73 -37
  6. package/.claude/commands/tlc/llm.md +19 -4
  7. package/.claude/commands/tlc/preflight.md +134 -0
  8. package/.claude/commands/tlc/review.md +17 -4
  9. package/.claude/commands/tlc/watchci.md +159 -0
  10. package/.claude/hooks/tlc-block-tools.sh +41 -0
  11. package/.claude/hooks/tlc-capture-exchange.sh +50 -0
  12. package/.claude/hooks/tlc-post-build.sh +38 -0
  13. package/.claude/hooks/tlc-post-push.sh +22 -0
  14. package/.claude/hooks/tlc-prompt-guard.sh +69 -0
  15. package/.claude/hooks/tlc-session-init.sh +123 -0
  16. package/CLAUDE.md +12 -0
  17. package/bin/install.js +171 -2
  18. package/bin/postinstall.js +45 -26
  19. package/dashboard-web/dist/assets/index-CdS5CHqu.css +1 -0
  20. package/dashboard-web/dist/assets/index-CwNPPVpg.js +483 -0
  21. package/dashboard-web/dist/assets/index-CwNPPVpg.js.map +1 -0
  22. package/dashboard-web/dist/index.html +2 -2
  23. package/docker-compose.dev.yml +18 -12
  24. package/package.json +3 -1
  25. package/server/index.js +228 -2
  26. package/server/lib/capture-bridge.js +242 -0
  27. package/server/lib/capture-bridge.test.js +363 -0
  28. package/server/lib/capture-guard.js +140 -0
  29. package/server/lib/capture-guard.test.js +182 -0
  30. package/server/lib/command-runner.js +159 -0
  31. package/server/lib/command-runner.test.js +92 -0
  32. package/server/lib/deploy/runners/dependency-runner.js +106 -0
  33. package/server/lib/deploy/runners/dependency-runner.test.js +148 -0
  34. package/server/lib/deploy/runners/secrets-runner.js +174 -0
  35. package/server/lib/deploy/runners/secrets-runner.test.js +127 -0
  36. package/server/lib/deploy/security-gates.js +11 -24
  37. package/server/lib/deploy/security-gates.test.js +9 -2
  38. package/server/lib/deploy-engine.js +182 -0
  39. package/server/lib/deploy-engine.test.js +147 -0
  40. package/server/lib/docker-api.js +137 -0
  41. package/server/lib/docker-api.test.js +202 -0
  42. package/server/lib/docker-client.js +297 -0
  43. package/server/lib/docker-client.test.js +308 -0
  44. package/server/lib/input-sanitizer.js +86 -0
  45. package/server/lib/input-sanitizer.test.js +117 -0
  46. package/server/lib/launchd-agent.js +225 -0
  47. package/server/lib/launchd-agent.test.js +185 -0
  48. package/server/lib/memory-api.js +3 -1
  49. package/server/lib/memory-api.test.js +3 -5
  50. package/server/lib/memory-bridge-e2e.test.js +160 -0
  51. package/server/lib/memory-committer.js +18 -4
  52. package/server/lib/memory-committer.test.js +21 -0
  53. package/server/lib/memory-hooks-capture.test.js +69 -4
  54. package/server/lib/memory-hooks-integration.test.js +98 -0
  55. package/server/lib/memory-hooks.js +42 -4
  56. package/server/lib/memory-store-adapter.js +105 -0
  57. package/server/lib/memory-store-adapter.test.js +141 -0
  58. package/server/lib/memory-wiring-e2e.test.js +93 -0
  59. package/server/lib/nginx-config.js +114 -0
  60. package/server/lib/nginx-config.test.js +82 -0
  61. package/server/lib/ollama-health.js +91 -0
  62. package/server/lib/ollama-health.test.js +74 -0
  63. package/server/lib/port-guard.js +44 -0
  64. package/server/lib/port-guard.test.js +65 -0
  65. package/server/lib/project-scanner.js +37 -2
  66. package/server/lib/project-scanner.test.js +152 -0
  67. package/server/lib/remember-command.js +2 -0
  68. package/server/lib/remember-command.test.js +23 -0
  69. package/server/lib/security/crypto-utils.test.js +2 -2
  70. package/server/lib/semantic-recall.js +1 -1
  71. package/server/lib/semantic-recall.test.js +17 -0
  72. package/server/lib/ssh-client.js +184 -0
  73. package/server/lib/ssh-client.test.js +127 -0
  74. package/server/lib/vps-api.js +184 -0
  75. package/server/lib/vps-api.test.js +208 -0
  76. package/server/lib/vps-bootstrap.js +124 -0
  77. package/server/lib/vps-bootstrap.test.js +79 -0
  78. package/server/lib/vps-monitor.js +126 -0
  79. package/server/lib/vps-monitor.test.js +98 -0
  80. package/server/lib/workspace-api.js +182 -1
  81. package/server/lib/workspace-api.test.js +474 -0
  82. package/server/package-lock.json +737 -0
  83. package/server/package.json +3 -0
  84. package/dashboard-web/dist/assets/index-Uhc49PE-.css +0 -1
  85. package/dashboard-web/dist/assets/index-W36XHPC5.js +0 -431
  86. package/dashboard-web/dist/assets/index-W36XHPC5.js.map +0 -1
@@ -262,9 +262,21 @@ All implementation follows **Red → Green → Refactor**:
262
262
  3. **Refactor**: Clean up while keeping tests green
263
263
  ```
264
264
 
265
- ### 9b. Create Claude Settings for Bash Permissions (Automatic)
265
+ ### 9b. Create Claude Settings with Permissions AND Hooks (Automatic)
266
266
 
267
- **Always create `.claude/settings.json` during init.** This is not optional — TLC requires these permissions to run tests, commit, and build without interruption.
267
+ **Always create `.claude/settings.json` during init.** This is not optional — TLC requires permissions for uninterrupted work AND hooks for the plugin system (enforcement, auto-verification, memory capture).
268
+
269
+ **Also create `.claude/hooks/` directory** and copy all hook scripts from the TLC package. The hooks power the plugin system — without them, TLC is commands-only with no automation.
270
+
271
+ Create `.claude/hooks/` with these scripts (copy from the installed TLC package at `~/.claude/hooks/` or from the npm package):
272
+ - `tlc-block-tools.sh` — Blocks non-TLC planning tools (EnterPlanMode, TaskCreate, etc.)
273
+ - `tlc-prompt-guard.sh` — Smart intent detection: parses user message for plan/build/fix/deploy intent and routes to the correct TLC command
274
+ - `tlc-session-init.sh` — Initializes TLC state and ensures server is running
275
+ - `tlc-post-push.sh` — Auto-triggers CI monitoring after `git push`
276
+ - `tlc-post-build.sh` — Auto-triggers guard + e2e verification after build/plan
277
+ - `tlc-capture-exchange.sh` — Captures conversations to team memory
278
+
279
+ Make all hook scripts executable: `chmod +x .claude/hooks/*.sh`
268
280
 
269
281
  Create `.claude/settings.json`:
270
282
 
@@ -272,46 +284,70 @@ Create `.claude/settings.json`:
272
284
  {
273
285
  "permissions": {
274
286
  "allow": [
275
- "Bash(npm *)",
276
- "Bash(npx *)",
277
- "Bash(node *)",
278
- "Bash(git *)",
279
- "Bash(gh *)",
280
- "Bash(ssh *)",
281
- "Bash(scp *)",
282
- "Bash(rsync *)",
283
- "Bash(curl *)",
284
- "Bash(wget *)",
285
- "Bash(docker *)",
286
- "Bash(docker-compose *)",
287
- "Bash(pytest*)",
288
- "Bash(python *)",
289
- "Bash(pip *)",
290
- "Bash(go *)",
291
- "Bash(cargo *)",
292
- "Bash(make *)",
293
- "Bash(cat *)",
294
- "Bash(ls *)",
295
- "Bash(pwd*)",
296
- "Bash(cd *)",
297
- "Bash(mkdir *)",
298
- "Bash(cp *)",
299
- "Bash(mv *)",
300
- "Bash(which *)",
301
- "Bash(echo *)",
302
- "Bash(jq *)",
303
- "Bash(wc *)",
304
- "Bash(head *)",
305
- "Bash(tail *)",
306
- "Bash(sort *)",
307
- "Bash(uniq *)",
308
- "Bash(xargs *)"
287
+ "Bash(npm *)", "Bash(npx *)", "Bash(node *)", "Bash(git *)",
288
+ "Bash(gh *)", "Bash(ssh *)", "Bash(scp *)", "Bash(rsync *)",
289
+ "Bash(curl *)", "Bash(wget *)", "Bash(docker *)", "Bash(docker-compose *)",
290
+ "Bash(pytest*)", "Bash(python *)", "Bash(pip *)", "Bash(go *)",
291
+ "Bash(cargo *)", "Bash(make *)", "Bash(cat *)", "Bash(ls *)",
292
+ "Bash(pwd*)", "Bash(cd *)", "Bash(mkdir *)", "Bash(cp *)",
293
+ "Bash(mv *)", "Bash(which *)", "Bash(echo *)", "Bash(jq *)",
294
+ "Bash(wc *)", "Bash(head *)", "Bash(tail *)", "Bash(sort *)",
295
+ "Bash(uniq *)", "Bash(xargs *)"
309
296
  ]
297
+ },
298
+ "hooks": {
299
+ "PreToolUse": [{
300
+ "matcher": "EnterPlanMode|TaskCreate|TaskUpdate|TaskList|TaskGet|ExitPlanMode",
301
+ "hooks": [{
302
+ "type": "command",
303
+ "command": "bash $CLAUDE_PROJECT_DIR/.claude/hooks/tlc-block-tools.sh",
304
+ "timeout": 5
305
+ }]
306
+ }],
307
+ "UserPromptSubmit": [{
308
+ "hooks": [{
309
+ "type": "command",
310
+ "command": "bash $CLAUDE_PROJECT_DIR/.claude/hooks/tlc-prompt-guard.sh",
311
+ "timeout": 5
312
+ }]
313
+ }],
314
+ "SessionStart": [{
315
+ "hooks": [{
316
+ "type": "command",
317
+ "command": "bash $CLAUDE_PROJECT_DIR/.claude/hooks/tlc-session-init.sh",
318
+ "timeout": 5
319
+ }]
320
+ }],
321
+ "PostToolUse": [
322
+ {
323
+ "matcher": "Bash",
324
+ "hooks": [{
325
+ "type": "command",
326
+ "command": "bash $CLAUDE_PROJECT_DIR/.claude/hooks/tlc-post-push.sh",
327
+ "timeout": 5
328
+ }]
329
+ },
330
+ {
331
+ "matcher": "Skill",
332
+ "hooks": [{
333
+ "type": "command",
334
+ "command": "bash $CLAUDE_PROJECT_DIR/.claude/hooks/tlc-post-build.sh",
335
+ "timeout": 5
336
+ }]
337
+ }
338
+ ],
339
+ "Stop": [{
340
+ "hooks": [{
341
+ "type": "command",
342
+ "command": "bash \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/tlc-capture-exchange.sh",
343
+ "timeout": 30
344
+ }]
345
+ }]
310
346
  }
311
347
  }
312
348
  ```
313
349
 
314
- If `.claude/settings.json` already exists, merge the permissions (don't overwrite user's existing config).
350
+ If `.claude/settings.json` already exists, merge: preserve existing permissions (union), add hooks section if missing (don't overwrite existing hooks).
315
351
 
316
352
  ### 10. Create or Update PROJECT.md
317
353
 
@@ -28,20 +28,35 @@ Interactive setup to configure providers in `.tlc.json`:
28
28
 
29
29
  ### /tlc:llm status
30
30
 
31
- Show current configuration:
31
+ Read from **`.tlc/.router-state.json`** (persistent state) and `.tlc.json` (config):
32
32
 
33
33
  ```
34
+ LLM Router Status
35
+ ══════════════════════════════════════════════
36
+
37
+ State: .tlc/.router-state.json
38
+ Probed: 2026-03-20T02:15:00Z (12 min ago)
39
+ TTL: 3600s (fresh)
40
+
34
41
  Providers:
35
42
  claude ✓ /usr/local/bin/claude [review, code-gen, refactor]
36
43
  codex ✓ /usr/local/bin/codex [review, code-gen]
37
44
  gemini ✗ not found [design, vision]
38
45
 
39
46
  Capabilities:
40
- review → claude, codex (fallback: claude)
41
- code-gen → claude
42
- vision → gemini (unavailable)
47
+ review → claude, codex (fallback: claude) 2/2 available
48
+ code-gen → claude 1/1 available
49
+ vision → gemini (unavailable) 0/1 available
50
+
51
+ Pipeline Integration:
52
+ Post-build review: claude + codex (consensus required)
53
+ Post-push e2e: claude (in-session)
43
54
  ```
44
55
 
56
+ The state file is written by the `SessionStart` hook and re-probed every hour. All skills read from this file — no ad-hoc `which` calls.
57
+
58
+ **Force re-probe:** `/tlc:llm probe` (deletes state file, next skill invocation re-probes)
59
+
45
60
  ### /tlc:llm models
46
61
 
47
62
  List models available from each provider.
@@ -0,0 +1,134 @@
1
+ # /tlc:preflight - Completeness Check Before Done
2
+
3
+ Never declare a task complete without running this. Catches gaps, loose ends, and half-solutions before they ship.
4
+
5
+ ## Philosophy
6
+
7
+ **Assume nothing is complete.** Every task has edges you didn't think about. This skill forces you to actively look for what's missing rather than confirming what's present.
8
+
9
+ ## When This Runs
10
+
11
+ This is a **plugin** — it fires automatically via PostToolUse hook whenever Claude is about to declare work "done." You don't invoke it manually.
12
+
13
+ It also runs:
14
+ - After `/tlc:build` (via guard + preflight chain)
15
+ - After any multi-file change
16
+ - Before recommending a commit or push
17
+
18
+ ## Process
19
+
20
+ ### Step 1: Inventory What Was Changed
21
+
22
+ List every file that was created, modified, or deleted in this session. For each one:
23
+ - What was the intent?
24
+ - Was the change completed or left partial?
25
+
26
+ ### Step 2: Trace All References
27
+
28
+ For every file changed, check:
29
+ - **Is it registered/imported where needed?** (e.g., new module added to an index, new command added to a commands array, new route added to a router)
30
+ - **Does anything else reference it?** (e.g., config files, package.json, install scripts, documentation)
31
+ - **Are there parallel systems that need the same update?** (e.g., install.js AND postinstall.js, package.json `files` AND `bin`, CLAUDE.md AND help.md)
32
+
33
+ This is the #1 source of half-solutions: changing the thing but not updating everything that points to the thing.
34
+
35
+ ### Step 3: Check Consistency Across Layers
36
+
37
+ For each change, verify consistency across ALL layers:
38
+
39
+ | Layer | Check |
40
+ |-------|-------|
41
+ | **Source files** | Does the code do what was intended? |
42
+ | **Tests** | Do tests exist and pass? |
43
+ | **Config** | Are config files updated (package.json, .tlc.json, settings.json)? |
44
+ | **Distribution** | Will this ship to end users? (files array, install scripts, postinstall) |
45
+ | **Documentation** | Is the change reflected in docs, help text, command tables? |
46
+ | **Integration** | Do other systems that depend on this still work? |
47
+
48
+ ### Step 4: Ask the Hard Questions
49
+
50
+ Before declaring done, explicitly answer each:
51
+
52
+ 1. **"If someone installs this fresh right now, will it work?"**
53
+ - Not "does it work on my machine" — does it work from a clean install?
54
+
55
+ 2. **"What did I assume exists that might not?"**
56
+ - Files, directories, env vars, running services, permissions
57
+
58
+ 3. **"What's the blast radius?"**
59
+ - What else touches the same files/systems I changed?
60
+ - Did I update ALL of those touchpoints?
61
+
62
+ 4. **"Is there a parallel path I forgot?"**
63
+ - Two install scripts? Two config files? Multiple places the same list appears?
64
+
65
+ 5. **"What would a user try that I didn't test?"**
66
+ - Edge cases in usage, not just happy path
67
+
68
+ ### Step 5: Report
69
+
70
+ **If gaps found:**
71
+ ```
72
+ PREFLIGHT CHECK — GAPS FOUND
73
+
74
+ Changes made: 3 files created, 2 files modified
75
+
76
+ Gaps:
77
+ 1. Created new-feature.md but not added to COMMANDS array in install.js
78
+ 2. Modified settings.json but init.md template not updated to match
79
+ 3. No test file for new utility function
80
+
81
+ Fix these before declaring done.
82
+ ```
83
+
84
+ **If clean:**
85
+ ```
86
+ PREFLIGHT CHECK — CLEAR
87
+
88
+ Changes made: 3 files created, 2 files modified
89
+ All references updated: ✅
90
+ Distribution verified: ✅
91
+ Tests exist: ✅
92
+ Config consistent: ✅
93
+
94
+ Task is complete.
95
+ ```
96
+
97
+ ## Common Gap Patterns
98
+
99
+ These are the most frequent gaps this skill catches:
100
+
101
+ | Pattern | Example |
102
+ |---------|---------|
103
+ | **Registry miss** | New file created but not added to install array, export list, or index |
104
+ | **Parallel system miss** | Updated install.js but not postinstall.js |
105
+ | **Config drift** | Changed settings.json but init.md still generates the old version |
106
+ | **Distribution miss** | File exists in repo but won't ship (not in package.json files) |
107
+ | **Doc drift** | New command added but not in CLAUDE.md dispatch table or help.md |
108
+ | **Test miss** | New code without corresponding test |
109
+ | **Cross-reference miss** | Renamed something but didn't grep for all references |
110
+
111
+ ## Example
112
+
113
+ ```
114
+ PREFLIGHT CHECK — GAPS FOUND
115
+
116
+ Session changes:
117
+ + .claude/commands/tlc/watchci.md (new skill)
118
+ + .claude/commands/tlc/e2e-verify.md (new skill)
119
+ + .claude/commands/tlc/guard.md (new skill)
120
+ + .claude/hooks/tlc-post-push.sh (new hook)
121
+ + .claude/hooks/tlc-post-build.sh (new hook)
122
+ ~ .claude/settings.json (added PostToolUse hooks)
123
+ ~ CLAUDE.md (added dispatch entries)
124
+
125
+ Gaps:
126
+ ❌ watchci.md, e2e-verify.md, guard.md not in COMMANDS array (bin/install.js)
127
+ ❌ .claude/hooks/ not in package.json files array — won't ship
128
+ ❌ postinstall.js doesn't copy hooks — fresh install broken
129
+ ❌ init.md settings template doesn't include new hooks
130
+ ❌ help.md doesn't list new commands
131
+ ❌ bootstrap.md was already missing from COMMANDS array (pre-existing gap)
132
+
133
+ 6 gaps found. Fix before declaring done.
134
+ ```
@@ -41,19 +41,32 @@ TLC automatically uses ALL providers configured for the `review` capability in `
41
41
 
42
42
  ## Process
43
43
 
44
- ### Step 1: Load Router Configuration
44
+ ### Step 1: Load Router State (Persistent)
45
45
 
46
- Read `.tlc.json` to get configured review providers:
46
+ **Always read from the router state file first**, then fall back to config:
47
47
 
48
48
  ```javascript
49
+ // 1. Read persistent router state (written by session-init hook)
50
+ const routerState = JSON.parse(fs.readFileSync('.tlc/.router-state.json', 'utf-8'));
51
+
52
+ // 2. Read config for capability mappings
49
53
  const config = JSON.parse(fs.readFileSync('.tlc.json', 'utf-8'));
50
54
  const reviewProviders = config.router?.capabilities?.review?.providers || ['claude'];
51
55
  const providers = config.router?.providers || {};
56
+
57
+ // 3. Filter to only AVAILABLE providers (from state file)
58
+ const availableReviewers = reviewProviders.filter(p =>
59
+ routerState.providers[p]?.available === true
60
+ );
52
61
  ```
53
62
 
54
- **Default providers for review:** `['claude', 'codex']`
63
+ **The state file (`.tlc/.router-state.json`) is authoritative for availability.** It's written by the `SessionStart` hook, re-probed every hour, and persists across skill invocations. Never run `which codex` yourself — read the state file.
64
+
65
+ If the state file is missing or stale (>1 hour), probe manually and write a fresh one.
66
+
67
+ **Default providers for review:** `['claude', 'codex']` — but only invoked if the state file confirms they're available.
55
68
 
56
- If Codex is configured and available, it WILL be invoked automatically.
69
+ If Codex is configured AND available in state, it WILL be invoked automatically.
57
70
 
58
71
  ### Step 2: Identify Changes
59
72
 
@@ -0,0 +1,159 @@
1
+ # /tlc:watchci - Watch CI and Fix Until Green
2
+
3
+ After pushing code, monitor the GitHub Actions run and fix failures in a loop until CI passes.
4
+
5
+ ## What This Does
6
+
7
+ 1. **Identifies the GH Actions run** triggered by the latest push
8
+ 2. **Polls until complete** (or fails)
9
+ 3. **On failure**: reads the logs, identifies the issue, fixes it, commits, pushes again
10
+ 4. **Repeats** until green or max attempts reached
11
+ 5. **Reports** final status
12
+
13
+ This is the "I pushed, now babysit CI for me" command.
14
+
15
+ ## Usage
16
+
17
+ ```
18
+ /tlc:watchci
19
+ /tlc:watchci 3 # max 3 fix attempts (default: 5)
20
+ ```
21
+
22
+ ## Process
23
+
24
+ ### Step 1: Find the Active Run
25
+
26
+ ```bash
27
+ gh run list --limit 5 --json databaseId,status,conclusion,headBranch,event,name,createdAt
28
+ ```
29
+
30
+ - Find the most recent run on the current branch
31
+ - If no run is in progress or recently completed, tell the user and exit
32
+ - Show: workflow name, run ID, status
33
+
34
+ ### Step 2: Wait for Completion
35
+
36
+ Poll the run status every 30 seconds:
37
+
38
+ ```bash
39
+ gh run view <run_id> --json status,conclusion
40
+ ```
41
+
42
+ While status is `in_progress` or `queued`:
43
+ - Print a brief status update every 60 seconds (not every poll)
44
+ - Continue waiting
45
+
46
+ ### Step 3: Check Result
47
+
48
+ If `conclusion` is `success`:
49
+ - Report green and exit
50
+
51
+ If `conclusion` is `failure`:
52
+ - Move to Step 4
53
+
54
+ ### Step 4: Read Failure Logs
55
+
56
+ ```bash
57
+ gh run view <run_id> --log-failed
58
+ ```
59
+
60
+ - Parse the failed step(s) and their log output
61
+ - Identify the root cause:
62
+ - **Test failure**: Which test, what assertion, what file
63
+ - **Build failure**: Which compilation error, what file/line
64
+ - **Lint failure**: Which rule, what file/line
65
+ - **Dependency issue**: Which package, what version conflict
66
+ - **Other**: Extract the relevant error message
67
+
68
+ ### Step 5: Fix the Issue
69
+
70
+ Based on the failure type:
71
+
72
+ **Test failure:**
73
+ - Read the failing test file and the source file it tests
74
+ - Understand what broke
75
+ - Fix the source code (not the test, unless the test itself is wrong)
76
+ - Run the test locally first to verify: `npm test` or `npx vitest run <file>`
77
+
78
+ **Build failure:**
79
+ - Read the file with the compilation error
80
+ - Fix the type error, missing import, etc.
81
+ - Verify locally: `npm run build` or `npx tsc --noEmit`
82
+
83
+ **Lint failure:**
84
+ - Read the file and fix the lint issue
85
+ - Verify locally: `npm run lint`
86
+
87
+ **Dependency issue:**
88
+ - Fix package.json or lock file as needed
89
+ - Verify locally: `npm ci`
90
+
91
+ ### Step 6: Commit and Push
92
+
93
+ - Stage only the files you changed
94
+ - Commit with message: `fix: resolve CI failure - <brief description>`
95
+ - Push to the same branch
96
+ - **Ask user before pushing** (per TLC rules)
97
+
98
+ ### Step 7: Loop Back
99
+
100
+ - Return to Step 1 to watch the new run
101
+ - Track attempt count
102
+ - If max attempts (default 5) reached without green, stop and report:
103
+ - What was tried
104
+ - What's still failing
105
+ - Suggestion for manual investigation
106
+
107
+ ## Guard Rails
108
+
109
+ - **Never push without asking.** Even in a fix loop, confirm before each push.
110
+ - **Never modify tests to make CI pass** unless the test itself has a genuine bug (not a "make the assertion match the wrong output" fix).
111
+ - **Local verification first.** Always run the fix locally before pushing.
112
+ - **Max attempts.** Default 5. Don't loop forever.
113
+ - **Don't mask failures.** If a test is legitimately catching a bug, fix the bug. Don't skip the test.
114
+
115
+ ## Example
116
+
117
+ ```
118
+ > /tlc:watchci
119
+
120
+ Watching CI for branch: feature/auth-module
121
+ Run #4521 (CI) — in progress...
122
+
123
+ ⏳ Waiting... (2m elapsed)
124
+ ⏳ Waiting... (3m elapsed)
125
+
126
+ ❌ Run #4521 failed
127
+
128
+ Failed step: "Run tests"
129
+ Error: FAIL server/lib/auth/auth.test.js
130
+ ● validateToken › should reject expired tokens
131
+ Expected: "TOKEN_EXPIRED"
132
+ Received: "INVALID_TOKEN"
133
+
134
+ Reading auth.test.js and auth.service.js...
135
+
136
+ Found: validateToken returns generic "INVALID_TOKEN" for expired tokens
137
+ instead of the specific "TOKEN_EXPIRED" error code.
138
+
139
+ Fix: Update the expiry check in auth.service.js to return "TOKEN_EXPIRED"
140
+
141
+ Running locally... ✅ Test passes
142
+
143
+ Ready to commit and push fix? (Y/n)
144
+ > y
145
+
146
+ Pushed. Watching new run...
147
+
148
+ Run #4522 (CI) — in progress...
149
+ ⏳ Waiting... (2m elapsed)
150
+
151
+ ✅ Run #4522 passed! CI is green.
152
+ ```
153
+
154
+ ## When to Use
155
+
156
+ - After pushing and you want CI monitored automatically
157
+ - After `/tlc:build` when you've pushed your work
158
+ - When CI keeps failing and you want the fix loop automated
159
+ - Pair with `/tlc:e2e-verify` for full verification after CI is green
@@ -0,0 +1,41 @@
1
+ #!/bin/bash
2
+ # TLC Enforcement Layer 1: Hard-block non-TLC planning tools
3
+ # Fires on PreToolUse for banned tools and DENIES them.
4
+ # Claude cannot bypass this - the tool call never executes.
5
+
6
+ INPUT=$(cat)
7
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty')
8
+
9
+ case "$TOOL" in
10
+ EnterPlanMode)
11
+ REASON="BLOCKED by TLC. Use /tlc:plan instead. Plans go in .planning/phases/ files."
12
+ ;;
13
+ TaskCreate)
14
+ REASON="BLOCKED by TLC. Tasks live in .planning/phases/{N}-PLAN.md with [ ] markers."
15
+ ;;
16
+ TaskUpdate)
17
+ REASON="BLOCKED by TLC. Update task markers in .planning/phases/{N}-PLAN.md files."
18
+ ;;
19
+ TaskGet)
20
+ REASON="BLOCKED by TLC. Read tasks from .planning/phases/{N}-PLAN.md files."
21
+ ;;
22
+ TaskList)
23
+ REASON="BLOCKED by TLC. Use /tlc:progress to check task status."
24
+ ;;
25
+ ExitPlanMode)
26
+ REASON="BLOCKED by TLC. Plans are approved via /tlc:build, not ExitPlanMode."
27
+ ;;
28
+ *)
29
+ exit 0
30
+ ;;
31
+ esac
32
+
33
+ cat <<EOF
34
+ {
35
+ "hookSpecificOutput": {
36
+ "hookEventName": "PreToolUse",
37
+ "permissionDecision": "deny",
38
+ "permissionDecisionReason": "${REASON}"
39
+ }
40
+ }
41
+ EOF
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env bash
2
+ # TLC Memory Capture - Claude Code Stop Hook
3
+ #
4
+ # Reads Stop hook JSON from stdin, extracts the assistant response,
5
+ # and sends it to the TLC server for memory processing.
6
+ # Falls back to local spool when server is unreachable.
7
+ #
8
+ # This script MUST exit 0 always - capture failures never block Claude.
9
+
10
+ set -o pipefail
11
+
12
+ # Read stdin (Stop hook provides JSON)
13
+ INPUT=$(cat)
14
+
15
+ # Quick exit if no input
16
+ [ -z "$INPUT" ] && exit 0
17
+
18
+ # Use the capture-bridge Node.js module for reliable processing
19
+ PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
20
+ BRIDGE_SCRIPT="$PROJECT_DIR/server/lib/capture-bridge.js"
21
+
22
+ if [ -f "$BRIDGE_SCRIPT" ]; then
23
+ echo "$INPUT" | node -e "
24
+ const bridge = require('$BRIDGE_SCRIPT');
25
+ let input = '';
26
+ process.stdin.on('data', d => input += d);
27
+ process.stdin.on('end', async () => {
28
+ const parsed = bridge.parseStopHookInput(input);
29
+ if (!parsed || !parsed.assistantMessage) process.exit(0);
30
+
31
+ const userMessage = parsed.transcriptPath
32
+ ? bridge.extractLastUserMessage(parsed.transcriptPath)
33
+ : null;
34
+
35
+ await bridge.captureExchange({
36
+ cwd: parsed.cwd || '$PROJECT_DIR',
37
+ assistantMessage: parsed.assistantMessage,
38
+ userMessage,
39
+ sessionId: parsed.sessionId,
40
+ });
41
+
42
+ const path = require('path');
43
+ const spoolDir = path.join(parsed.cwd || '$PROJECT_DIR', '.tlc', 'memory');
44
+ await bridge.drainSpool(spoolDir);
45
+ });
46
+ " 2>/dev/null
47
+ fi
48
+
49
+ # Always exit 0 - never block Claude
50
+ exit 0
@@ -0,0 +1,38 @@
1
+ #!/bin/bash
2
+ # TLC Plugin: Post-build and post-plan automation chain
3
+ # Fires on PostToolUse for Skill.
4
+ #
5
+ # After /tlc:build (code written):
6
+ # guard → preflight → review (Claude + Codex) → if APPROVED → offer push + PR
7
+ #
8
+ # After /tlc:plan:
9
+ # guard plan → validate structure
10
+ #
11
+ # After /tlc:quick:
12
+ # preflight → review → offer push
13
+
14
+ INPUT=$(cat)
15
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty')
16
+
17
+ # Only care about Skill tool
18
+ [ "$TOOL" != "Skill" ] && exit 0
19
+
20
+ SKILL=$(echo "$INPUT" | jq -r '.tool_input.skill // empty')
21
+
22
+ case "$SKILL" in
23
+ tlc:build)
24
+ echo "[TLC-PLUGIN] Build phase complete. Mandatory post-build chain:
25
+ (1) Run /tlc:guard to validate TLC process compliance (test-first, coverage, no skipped tests).
26
+ (2) Run /tlc:preflight to check for gaps (references, registries, configs, distribution).
27
+ (3) Run /tlc:review to invoke multi-LLM review — Claude reviews in-session, THEN invoke Codex CLI for second opinion. BOTH must APPROVE.
28
+ (4) If review APPROVED: ask user for permission to push to remote and create a PR for main.
29
+ (5) If review CHANGES_REQUESTED: fix the issues and re-run the review. Do NOT push.
30
+ Do NOT skip any step. Do NOT push without review approval."
31
+ ;;
32
+ tlc:plan)
33
+ echo "[TLC-PLUGIN] Plan created. Now automatically run /tlc:guard plan to validate the plan has proper task breakdown, acceptance criteria, and dependency ordering. Do NOT skip."
34
+ ;;
35
+ tlc:quick)
36
+ echo "[TLC-PLUGIN] Quick task complete. Run /tlc:preflight then /tlc:review (Claude + Codex). If APPROVED, ask user for permission to push and create PR."
37
+ ;;
38
+ esac
@@ -0,0 +1,22 @@
1
+ #!/bin/bash
2
+ # TLC Plugin: Post-push automation chain
3
+ # Fires on PostToolUse for Bash. Detects git push.
4
+ #
5
+ # After git push:
6
+ # watchci (monitor GH Actions) → if green → e2e-verify (screenshots + logs)
7
+
8
+ INPUT=$(cat)
9
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty')
10
+
11
+ # Only care about Bash tool
12
+ [ "$TOOL" != "Bash" ] && exit 0
13
+
14
+ # Check if the command was a git push
15
+ COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
16
+ if echo "$COMMAND" | grep -qE '^git push'; then
17
+ echo "[TLC-PLUGIN] git push detected. Mandatory post-push chain:
18
+ (1) Run /tlc:watchci — monitor the GitHub Actions run, read failure logs, fix issues, and push again until CI is green.
19
+ (2) Once CI is green, run /tlc:e2e-verify — start the app, take screenshots, read them visually, check server and console logs for errors.
20
+ (3) If e2e-verify finds issues, fix them and push again (which restarts this chain).
21
+ Do NOT skip any step."
22
+ fi