ctx-cc 4.0.0 → 4.1.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.
package/commands/ctx.md CHANGED
@@ -120,29 +120,29 @@ Call Task 4 times in a SINGLE message with these parameters:
120
120
 
121
121
  ```
122
122
  Task 1:
123
- subagent_type: "gsd-codebase-mapper"
124
- prompt: "Focus area: TECH. Analyze technology stack. Write to .ctx/codebase/TECH.md with languages, frameworks, dependencies, build tools, versions."
123
+ subagent_type: "ctx-tech-mapper"
124
+ prompt: "Analyze technology stack. Write to .ctx/codebase/TECH.md with languages, frameworks, dependencies, build tools, versions."
125
125
  model: "haiku"
126
126
  run_in_background: true
127
127
  description: "Map tech stack"
128
128
 
129
129
  Task 2:
130
- subagent_type: "gsd-codebase-mapper"
131
- prompt: "Focus area: ARCH. Analyze architecture. Write to .ctx/codebase/ARCH.md with patterns, layers, modules, entry points, data flow."
130
+ subagent_type: "ctx-arch-mapper"
131
+ prompt: "Analyze architecture. Write to .ctx/codebase/ARCH.md with patterns, layers, modules, entry points, data flow."
132
132
  model: "haiku"
133
133
  run_in_background: true
134
134
  description: "Map architecture"
135
135
 
136
136
  Task 3:
137
- subagent_type: "gsd-codebase-mapper"
138
- prompt: "Focus area: QUALITY. Analyze code quality. Write to .ctx/codebase/QUALITY.md with test coverage, linting, type safety, documentation, code smells."
137
+ subagent_type: "ctx-quality-mapper"
138
+ prompt: "Analyze code quality. Write to .ctx/codebase/QUALITY.md with test coverage, linting, type safety, documentation, code smells."
139
139
  model: "haiku"
140
140
  run_in_background: true
141
141
  description: "Map quality"
142
142
 
143
143
  Task 4:
144
- subagent_type: "gsd-codebase-mapper"
145
- prompt: "Focus area: CONCERNS. Analyze risks and concerns. Write to .ctx/codebase/CONCERNS.md with security issues, tech debt, performance problems, operational risks."
144
+ subagent_type: "ctx-concerns-mapper"
145
+ prompt: "Analyze risks and concerns. Write to .ctx/codebase/CONCERNS.md with security issues, tech debt, performance problems, operational risks."
146
146
  model: "haiku"
147
147
  run_in_background: true
148
148
  description: "Map concerns"
@@ -264,7 +264,7 @@ If .ctx/codebase/ doesn't exist, run quick mapping first.
264
264
  **Spawn debugger agent:**
265
265
  ```
266
266
  Task:
267
- subagent_type: "debugger"
267
+ subagent_type: "ctx-debugger"
268
268
  prompt: "Investigate this issue: [user's problem]. Use scientific method: reproduce, isolate, fix, verify. The codebase analysis is in .ctx/codebase/. Write debug session to .ctx/debug/SESSION-[timestamp].md"
269
269
  description: "Debug issue"
270
270
  ```
@@ -283,7 +283,7 @@ Task:
283
283
  **Spawn QA agent:**
284
284
  ```
285
285
  Task:
286
- subagent_type: "qa-engineer"
286
+ subagent_type: "ctx-qa"
287
287
  prompt: "Run comprehensive QA validation on this codebase. Test user flows, validate accessibility, check for regressions. Write report to .ctx/qa/REPORT-[timestamp].md"
288
288
  description: "QA validation"
289
289
  ```
package/commands/help.md CHANGED
@@ -4,18 +4,18 @@ description: Show CTX commands and usage guide
4
4
  ---
5
5
 
6
6
  <objective>
7
- Display the CTX 3.5 command reference.
7
+ Display the CTX 4.0 command reference.
8
8
 
9
9
  Output ONLY the reference content below. Do NOT add project-specific analysis.
10
10
  </objective>
11
11
 
12
12
  <reference>
13
- # CTX 3.5 Command Reference
13
+ # CTX 4.0 Command Reference
14
14
 
15
15
  **CTX** (Continuous Task eXecution) - Intelligent workflow orchestration for Claude Code.
16
16
 
17
17
  **Conversational-first.** Just describe what you want - no commands to memorize.
18
- 21 agents. 5 skills. Deterministic hooks. Agency-grade design. Phase-based lifecycle.
18
+ 26 agents. 7 skills. Deterministic hooks. Three-stage review gate with Codex cross-model review. Phase-based lifecycle.
19
19
 
20
20
  ## Quick Start
21
21
 
@@ -115,6 +115,7 @@ Or use commands directly:
115
115
  | `/ctx plan [goal]` | Force research + planning |
116
116
  | `/ctx verify` | Force three-level verification |
117
117
  | `/ctx quick "task"` | Quick task bypass |
118
+ | `/ctx cross-review [range] [--focus=area]` | On-demand Codex cross-model review (any project) |
118
119
 
119
120
  ### Debug
120
121
  | Command | Purpose |
@@ -269,7 +270,7 @@ Or use commands directly:
269
270
  |-------|---------|
270
271
  | ctx-orchestrator | Pipeline execution, lifecycle, autonomous mode |
271
272
  | ctx-state | STATE.json management, phase transitions |
272
- | ctx-review-gate | Two-stage review (spec compliance + code quality) |
273
+ | ctx-review-gate | Three-stage review (spec compliance + code quality + optional Codex cross-review) |
273
274
  | ctx-design-system | W3C DTCG tokens, Figma sync, theme management |
274
275
  | ctx-visual-qa | Pixel-perfect measurement, accessibility audit |
275
276
  | ctx-ml-experiment | ML experiment lifecycle, hypothesis tracking |
@@ -354,5 +355,5 @@ npx ctx-cc --force
354
355
  ```
355
356
 
356
357
  ---
357
- *CTX 3.5 - Learning. Prediction. Self-healing. Voice control.*
358
+ *CTX 4.0 - Learning. Prediction. Self-healing. Cross-model review. Voice control.*
358
359
  </reference>
package/commands/init.md CHANGED
@@ -20,6 +20,7 @@ Initialize a new CTX project through unified flow: questioning → research →
20
20
  - `.ctx/STATE.md` — Living project state
21
21
  - `.ctx/PRD.json` — Requirements contract
22
22
  - `.ctx/config.json` — Workflow preferences
23
+ - `.ctx/capability-manifest.json` — Tool restrictions read by the PreToolUse hook
23
24
  - `.ctx/research/` — Domain research (ArguSeek)
24
25
  - `.ctx/ROADMAP.md` — Phase structure
25
26
 
@@ -136,6 +137,29 @@ cat > .ctx/.gitignore << 'EOF'
136
137
  *.secrets
137
138
  credentials.json
138
139
  EOF
140
+
141
+ # Seed the capability manifest used by the PreToolUse hook.
142
+ # The plugin install step generates this template; prefer the global install,
143
+ # fall back to project-local, warn if neither exists (enforcement is optional).
144
+ # If an older-version manifest already exists, back it up before copying.
145
+ CTX_TEMPLATE_DIR="${HOME}/.claude/ctx/templates"
146
+ if [ ! -f "${CTX_TEMPLATE_DIR}/capability-manifest.json" ]; then
147
+ CTX_TEMPLATE_DIR=".claude/ctx/templates"
148
+ fi
149
+ if [ -f "${CTX_TEMPLATE_DIR}/capability-manifest.json" ]; then
150
+ if [ -f .ctx/capability-manifest.json ]; then
151
+ OLD_VER=$(grep -oE '"_version"\s*:\s*[0-9]+' .ctx/capability-manifest.json | grep -oE '[0-9]+$' || echo "0")
152
+ NEW_VER=$(grep -oE '"_version"\s*:\s*[0-9]+' "${CTX_TEMPLATE_DIR}/capability-manifest.json" | grep -oE '[0-9]+$' || echo "0")
153
+ if [ "${OLD_VER}" != "${NEW_VER}" ]; then
154
+ mv .ctx/capability-manifest.json ".ctx/capability-manifest.v${OLD_VER}.backup.json"
155
+ fi
156
+ fi
157
+ cp "${CTX_TEMPLATE_DIR}/capability-manifest.json" .ctx/capability-manifest.json
158
+ else
159
+ echo "WARN: capability-manifest.json template not found in ${HOME}/.claude/ctx/templates or .claude/ctx/templates"
160
+ echo " The PreToolUse hook will silently no-op until the manifest is seeded."
161
+ echo " Reinstall ctx-cc (npx ctx-cc --force) to regenerate it."
162
+ fi
139
163
  ```
140
164
 
141
165
  ## Phase 5: Write STATE.md
@@ -181,6 +205,7 @@ EOF
181
205
 
182
206
  ```bash
183
207
  git add .ctx/STATE.md .ctx/.gitignore
208
+ [ -f .ctx/capability-manifest.json ] && git add .ctx/capability-manifest.json
184
209
  git commit -m "docs: initialize CTX project - {{project_name}}"
185
210
  ```
186
211
 
@@ -4,7 +4,7 @@ description: Metrics dashboard - understand AI productivity impact with stories
4
4
  ---
5
5
 
6
6
  <objective>
7
- CTX 3.5 Metrics Dashboard - Comprehensive productivity analytics for understanding AI development impact.
7
+ CTX 4.0 Metrics Dashboard - Comprehensive productivity analytics for understanding AI development impact.
8
8
  </objective>
9
9
 
10
10
  <usage>
@@ -4,7 +4,7 @@ description: Milestone workflow - list, audit, complete, and start new milestone
4
4
  ---
5
5
 
6
6
  <objective>
7
- CTX 3.5 Milestone Workflow - Full release management with audit, archive, and git tagging.
7
+ CTX 4.0 Milestone Workflow - Full release management with audit, archive, and git tagging.
8
8
  </objective>
9
9
 
10
10
  <usage>
@@ -4,7 +4,7 @@ description: Self-healing deployments - connect to error tracking (Sentry/LogRoc
4
4
  ---
5
5
 
6
6
  <objective>
7
- CTX 3.5 Self-Healing Deployments - Monitor production errors and automatically create fix stories or even auto-fix with PR creation.
7
+ CTX 4.0 Self-Healing Deployments - Monitor production errors and automatically create fix stories or even auto-fix with PR creation.
8
8
  </objective>
9
9
 
10
10
  <usage>
package/commands/voice.md CHANGED
@@ -4,7 +4,7 @@ description: Voice control for CTX - speak your requirements and commands using
4
4
  ---
5
5
 
6
6
  <objective>
7
- CTX 3.5 Voice Control - Speak your requirements instead of typing. Natural language processing converts speech to CTX commands and story descriptions.
7
+ CTX 4.0 Voice Control - Speak your requirements instead of typing. Natural language processing converts speech to CTX commands and story descriptions.
8
8
  </objective>
9
9
 
10
10
  <usage>
@@ -63,7 +63,8 @@ if (agentName && agentName.startsWith('ctx-')) {
63
63
  if (fs.existsSync(manifestPath)) {
64
64
  const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
65
65
  for (const [category, cfg] of Object.entries(manifest)) {
66
- if (cfg.agents.includes(agentName + '.md') && cfg.denied.includes(toolName)) {
66
+ if (category.startsWith('_')) continue; // skip metadata keys like _version
67
+ if (cfg?.agents?.includes(agentName + '.md') && cfg.denied.includes(toolName)) {
67
68
  process.stderr.write(`CTX: Tool "${toolName}" blocked for ${category} agent "${agentName}".\n`);
68
69
  fs.appendFileSync(
69
70
  path.join(ctxDir, 'violations.log'),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ctx-cc",
3
- "version": "4.0.0",
4
- "description": "CTX 4.0 — Intelligent workflow orchestration for Claude Code. 21 subagents, 3 skills, deterministic hooks. Phase-based lifecycle with autonomous execution.",
3
+ "version": "4.1.1",
4
+ "description": "CTX 4.0 — Intelligent workflow orchestration for Claude Code. 26 subagents, 7 skills, deterministic hooks. Phase-based lifecycle with autonomous execution.",
5
5
  "keywords": [
6
6
  "claude",
7
7
  "claude-code",
package/plugin.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ctx",
3
3
  "version": "4.0.0",
4
- "description": "CTX — Intelligent workflow orchestration for Claude Code. 21 specialized agents, phase-based lifecycle, two-stage review gate, autonomous execution.",
4
+ "description": "CTX — Intelligent workflow orchestration for Claude Code. Specialized agents, phase-based lifecycle, three-stage review gate with OpenAI Codex cross-model review, autonomous execution.",
5
5
  "author": "jufjuf",
6
6
  "license": "MIT",
7
7
  "homepage": "https://github.com/jufjuf/CTX",
@@ -38,6 +38,7 @@
38
38
  },
39
39
  "settings": {
40
40
  "reviewGate": true,
41
+ "codexReview": true,
41
42
  "tddMode": "off",
42
43
  "maxReviewCycles": 3,
43
44
  "maxAutoIterations": 5
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  name: ctx-review-gate
3
3
  description: |
4
- WHEN: Code has been implemented and needs quality verification before marking a story complete. Runs two-stage review: spec compliance then code quality.
4
+ WHEN: Code has been implemented and needs quality verification before marking a story complete. Runs three-stage review: spec compliance, code quality, and optional cross-model adversarial review via OpenAI Codex.
5
5
  WHEN NOT: During planning, research, or when review gate is disabled in config.
6
6
  ---
7
7
 
8
- # CTX Two-Stage Review Gate
8
+ # CTX Three-Stage Review Gate
9
9
 
10
10
  Automated quality gate that runs after execution and before verification.
11
11
 
12
- ## Two Stages
12
+ ## Three Stages
13
13
 
14
14
  ### Stage 1: Spec Compliance (ctx-reviewer)
15
15
  Checks whether the code satisfies the story's acceptance criteria.
@@ -23,18 +23,39 @@ Agent({
23
23
  })
24
24
  ```
25
25
 
26
- ### Stage 2: Code Quality (ctx-auditor)
27
- Checks security, performance, and code quality. **Only runs if Stage 1 passes.**
26
+ ### Stage 2: Code Quality (ctx-reviewer)
27
+ Reuses ctx-reviewer with a quality-focused prompt: security, performance, error handling, style. **Only runs if Stage 1 passes.**
28
+
29
+ (Note: earlier versions of this skill called `ctx-auditor` here. That was a miscast — `ctx-auditor` is an audit-trail/compliance agent, not a code-quality reviewer. `ctx-reviewer` already covers type checks, imports, security scans, and best-practice enforcement, so it handles both stages with different framings.)
28
30
 
29
31
  Spawn:
30
32
  ```
31
33
  Agent({
32
- subagent_type: "ctx-auditor",
34
+ subagent_type: "ctx-reviewer",
33
35
  prompt: "Review recent changes for CODE QUALITY. Check: security vulnerabilities, performance, error handling, style. Output VERDICT: PASS or FAIL with ISSUES list.",
34
- description: "Code quality audit"
36
+ description: "Code quality review"
35
37
  })
36
38
  ```
37
39
 
40
+ ### Stage 3: Cross-Model Review (ctx-codex-reviewer) — optional
41
+ Sends the diff to OpenAI Codex via MCP for a second-pair-of-eyes review with different model priors. **Only runs if Stage 2 passes AND `config.codexReview !== false`.**
42
+
43
+ Short-circuits on docs-only, test-only, or trivial (<20 LOC) diffs. Fails soft — if the Codex MCP is unavailable, rate-limited, or unauthenticated, returns `SKIP` rather than `FAIL` so infrastructure problems never block the gate.
44
+
45
+ Spawn:
46
+ ```
47
+ Agent({
48
+ subagent_type: "ctx-codex-reviewer",
49
+ prompt: "Cross-model review story <ID>. Dispatch the current diff to Codex via mcp__codex__codex with sandbox=read-only. Acceptance criteria: <list>. Output VERDICT: PASS, FAIL, or SKIP.",
50
+ description: "Codex adversarial review"
51
+ })
52
+ ```
53
+
54
+ Prerequisites (user-side, not automated by CTX):
55
+ - Codex CLI installed (`npm i -g @openai/codex`)
56
+ - Signed in via ChatGPT subscription (`codex login` — no `--api-key` flag)
57
+ - MCP registered (`claude mcp add codex -- codex mcp-server`)
58
+
38
59
  ## Flow
39
60
 
40
61
  ```
@@ -51,6 +72,12 @@ Stage 2: ctx-auditor (code quality)
51
72
  ├── FAIL → Feed issues back to executor, increment cycle
52
73
 
53
74
  ▼ PASS
75
+ Stage 3: ctx-codex-reviewer (cross-model, if enabled)
76
+
77
+ ├── FAIL → Feed issues back to executor, increment cycle
78
+ ├── SKIP → Treat as pass (infra problem, not code problem)
79
+
80
+ ▼ PASS
54
81
  Mark story for verification
55
82
  ```
56
83
 
@@ -85,27 +112,36 @@ Update `.ctx/STATE.json`:
85
112
  "reviewGate": {
86
113
  "cycle": 2,
87
114
  "history": [
88
- { "cycle": 1, "timestamp": "ISO", "stage1": { "passed": true }, "stage2": { "passed": false, "issues": "..." }, "result": "fail" },
89
- { "cycle": 2, "timestamp": "ISO", "stage1": { "passed": true }, "stage2": { "passed": true }, "result": "pass" }
115
+ { "cycle": 1, "timestamp": "ISO", "stage1": { "passed": true }, "stage2": { "passed": false, "issues": "..." }, "stage3": null, "result": "fail" },
116
+ { "cycle": 2, "timestamp": "ISO", "stage1": { "passed": true }, "stage2": { "passed": true }, "stage3": { "passed": true, "threadId": "thr_...", "skipped": false }, "result": "pass" }
90
117
  ]
91
118
  }
92
119
  }
93
120
  ```
94
121
 
122
+ `stage3` is `null` when Stage 2 fails (not reached) or when `codexReview` is disabled. When Stage 3 runs, record `threadId` so follow-ups reuse the same Codex session.
123
+
95
124
  ## Save Review Artifacts
96
125
 
97
126
  Write review results to `.ctx/reviews/<story-id>-<timestamp>.json`.
98
127
 
99
128
  ## Configuration
100
129
 
101
- Review gate can be disabled:
130
+ Review gate can be disabled entirely:
102
131
  - Check `.ctx/config.json` for `"reviewGate": false`
103
132
  - If disabled, skip directly to verification
104
133
 
134
+ Stage 3 (Codex cross-review) can be disabled independently:
135
+ - Check `.ctx/config.json` for `"codexReview": false`
136
+ - Useful when offline, when the ChatGPT rate-limit budget is depleted, or when the change is trivial
137
+ - Stages 1 and 2 continue to run normally
138
+
105
139
  ## Rules
106
140
 
107
- - ALWAYS run Stage 1 before Stage 2
108
- - NEVER run Stage 2 if Stage 1 fails (fail-fast)
141
+ - ALWAYS run Stage 1 before Stage 2, Stage 2 before Stage 3 (fail-fast ordering)
142
+ - NEVER run Stage 2 if Stage 1 fails
143
+ - NEVER run Stage 3 if Stage 2 fails, or if `codexReview === false`
144
+ - Stage 3 SKIP (infrastructure failure) is NOT a gate failure — treat as pass
109
145
  - ALWAYS feed review issues back to executor as context on retry
110
146
  - Max 3 cycles — then escalate to human
111
- - Record every cycle in state
147
+ - Record every cycle in state, including `stage3: null` when not reached
@@ -1,9 +1,26 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
3
 
4
+ /**
5
+ * Schema version for the on-disk capability manifest.
6
+ * Bump when adding categories, renaming fields, or changing policy semantics
7
+ * so stale project manifests can be detected and regenerated.
8
+ */
9
+ export const MANIFEST_VERSION = 1;
10
+
4
11
  /**
5
12
  * Default capability manifests per agent category.
6
- * Defines which tools each agent type is allowed to use.
13
+ * Defines which tools each ctx-* agent category is allowed to use.
14
+ *
15
+ * The runtime enforcement point is `hooks/pre-tool-use.js`, which reads
16
+ * `.ctx/capability-manifest.json` (written at project init from this table)
17
+ * and blocks tool calls whose name appears in the agent's `denied` list.
18
+ *
19
+ * `allowed` is the declared whitelist and is used for documentation and tests;
20
+ * the hook itself is denylist-driven so unknown tools default to permissive.
21
+ *
22
+ * Iterators over a loaded manifest MUST skip keys starting with `_`
23
+ * (reserved for metadata like `_version`).
7
24
  */
8
25
  const DEFAULT_CAPABILITIES = {
9
26
  // Planning agents — read-only + write plans
@@ -22,14 +39,22 @@ const DEFAULT_CAPABILITIES = {
22
39
  reason: 'Execution agents should not spawn other agents.',
23
40
  },
24
41
 
25
- // Review agents — read + run tests, no modifications
42
+ // Review agents — read + run tests + Codex cross-review, no modifications
26
43
  review: {
27
- agents: ['ctx-reviewer.md', 'ctx-auditor.md', 'ctx-verifier.md'],
28
- allowed: ['Read', 'Glob', 'Grep', 'Bash'],
44
+ agents: ['ctx-reviewer.md', 'ctx-verifier.md', 'ctx-codex-reviewer.md', 'ctx-ml-reviewer.md'],
45
+ allowed: ['Read', 'Glob', 'Grep', 'Bash', 'mcp__codex__codex'],
29
46
  denied: ['Write', 'Edit', 'NotebookEdit'],
30
47
  reason: 'Review agents should not modify code.',
31
48
  },
32
49
 
50
+ // Audit agents — write audit trails, but never modify source
51
+ audit: {
52
+ agents: ['ctx-auditor.md'],
53
+ allowed: ['Read', 'Write', 'Bash', 'Glob', 'Grep'],
54
+ denied: ['Edit', 'Agent', 'NotebookEdit'],
55
+ reason: 'Audit agents record trails but should not modify source or spawn agents.',
56
+ },
57
+
33
58
  // Mapper agents — read-only analysis
34
59
  mapping: {
35
60
  agents: ['ctx-mapper.md', 'ctx-arch-mapper.md', 'ctx-tech-mapper.md', 'ctx-quality-mapper.md', 'ctx-concerns-mapper.md'],
@@ -69,25 +94,23 @@ const DEFAULT_CAPABILITIES = {
69
94
  denied: ['Edit'],
70
95
  reason: 'QA agents test but should not fix code.',
71
96
  },
72
- };
73
97
 
74
- /**
75
- * Load capability manifest from file, or return defaults.
76
- */
77
- export function loadCapabilityManifest(ctxDir) {
78
- const manifestPath = path.join(ctxDir, 'capability-manifest.json');
79
- try {
80
- return JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
81
- } catch {
82
- return DEFAULT_CAPABILITIES;
83
- }
84
- }
98
+ // ML agents — implement and analyze ML pipelines
99
+ ml: {
100
+ agents: ['ctx-ml-scientist.md', 'ctx-ml-engineer.md', 'ctx-ml-analyst.md'],
101
+ allowed: ['Read', 'Write', 'Edit', 'Bash', 'Glob', 'Grep'],
102
+ denied: ['Agent', 'NotebookEdit'],
103
+ reason: 'ML agents implement and analyze pipelines but should not orchestrate.',
104
+ },
105
+ };
85
106
 
86
107
  /**
87
108
  * Find the category for a given agent file.
109
+ * Skips metadata keys (prefix `_`) so a versioned on-disk manifest still works.
88
110
  */
89
111
  export function findAgentCategory(agentFile, manifest = DEFAULT_CAPABILITIES) {
90
112
  for (const [category, config] of Object.entries(manifest)) {
113
+ if (category.startsWith('_')) continue;
91
114
  if (config.agents.includes(agentFile)) {
92
115
  return { category, ...config };
93
116
  }
@@ -97,12 +120,14 @@ export function findAgentCategory(agentFile, manifest = DEFAULT_CAPABILITIES) {
97
120
 
98
121
  /**
99
122
  * Check if a tool is allowed for an agent.
123
+ * Denylist-driven (matches the runtime hook in hooks/pre-tool-use.js).
124
+ * Unknown agents are permissive by default.
125
+ *
100
126
  * Returns { allowed: boolean, reason: string|null }.
101
127
  */
102
128
  export function checkToolAllowed(agentFile, toolName, manifest = DEFAULT_CAPABILITIES) {
103
129
  const category = findAgentCategory(agentFile, manifest);
104
130
  if (!category) {
105
- // Unknown agent — allow everything (permissive for custom agents)
106
131
  return { allowed: true, reason: null };
107
132
  }
108
133
 
@@ -117,37 +142,66 @@ export function checkToolAllowed(agentFile, toolName, manifest = DEFAULT_CAPABIL
117
142
  }
118
143
 
119
144
  /**
120
- * Generate a PreToolUse hook command that enforces capability restrictions.
121
- * Returns the hook command string.
145
+ * Save the capability manifest to `<ctxDir>/capability-manifest.json`.
146
+ * Called from the install flow to seed the template and from the project
147
+ * init command to materialize the manifest that the PreToolUse hook reads.
122
148
  */
123
- export function generateCapabilityHookCommand(ctxDir) {
124
- return `node -e "
125
- const fs=require('fs'),p=require('path');
126
- const tool=process.env.TOOL_NAME||'';
127
- const agent=process.env.CURRENT_AGENT||'';
128
- if(!agent||!tool)process.exit(0);
129
- const mPath=p.join('${ctxDir}','capability-manifest.json');
130
- let manifest;
131
- try{manifest=JSON.parse(fs.readFileSync(mPath,'utf-8'));}catch{process.exit(0);}
132
- for(const[cat,cfg]of Object.entries(manifest)){
133
- if(cfg.agents.includes(agent)&&cfg.denied.includes(tool)){
134
- console.error('CTX: Tool '+tool+' blocked for '+cat+' agent '+agent);
135
- const logDir=p.join('${ctxDir}','violations.log');
136
- fs.appendFileSync(logDir,new Date().toISOString()+' | '+agent+' | '+tool+' | BLOCKED\\n');
137
- process.exit(2);
138
- }
139
- }
140
- "`.replace(/\n\s*/g, ' ').trim();
149
+ export function saveCapabilityManifest(ctxDir) {
150
+ const manifestPath = path.join(ctxDir, 'capability-manifest.json');
151
+ if (!fs.existsSync(ctxDir)) fs.mkdirSync(ctxDir, { recursive: true });
152
+ const payload = { _version: MANIFEST_VERSION, ...DEFAULT_CAPABILITIES };
153
+ fs.writeFileSync(manifestPath, JSON.stringify(payload, null, 2) + '\n');
154
+ return manifestPath;
141
155
  }
142
156
 
143
157
  /**
144
- * Save default capability manifest to .ctx/ for customization.
158
+ * Read the `_version` field from an on-disk manifest.
159
+ * Returns 0 for pre-versioned manifests, null if file missing/invalid.
160
+ * Callers compare against MANIFEST_VERSION to decide whether to regenerate.
145
161
  */
146
- export function saveCapabilityManifest(ctxDir) {
162
+ export function readManifestVersion(ctxDir) {
147
163
  const manifestPath = path.join(ctxDir, 'capability-manifest.json');
148
- if (!fs.existsSync(ctxDir)) fs.mkdirSync(ctxDir, { recursive: true });
149
- fs.writeFileSync(manifestPath, JSON.stringify(DEFAULT_CAPABILITIES, null, 2) + '\n');
150
- return manifestPath;
164
+ try {
165
+ const data = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
166
+ return typeof data._version === 'number' ? data._version : 0;
167
+ } catch {
168
+ return null;
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Migrate an existing project's capability manifest to the current version.
174
+ * - Missing: writes a fresh manifest, returns { action: 'created' }.
175
+ * - Current: no-op, returns { action: 'current' }.
176
+ * - Stale: backs up old manifest as `capability-manifest.v<N>.backup.json`
177
+ * and regenerates, returns { action: 'migrated', backup }.
178
+ *
179
+ * Used by the `ctx-cc update-manifest` CLI subcommand so projects that
180
+ * predate MANIFEST_VERSION can pick up policy changes without re-initting.
181
+ */
182
+ export function updateProjectManifest(ctxDir) {
183
+ const manifestPath = path.join(ctxDir, 'capability-manifest.json');
184
+ const current = readManifestVersion(ctxDir);
185
+
186
+ if (current === null) {
187
+ saveCapabilityManifest(ctxDir);
188
+ return { action: 'created', from: null, to: MANIFEST_VERSION, path: manifestPath };
189
+ }
190
+
191
+ if (current === MANIFEST_VERSION) {
192
+ return { action: 'current', from: current, to: current, path: manifestPath };
193
+ }
194
+
195
+ const backupPath = path.join(ctxDir, `capability-manifest.v${current}.backup.json`);
196
+ fs.copyFileSync(manifestPath, backupPath);
197
+ saveCapabilityManifest(ctxDir);
198
+ return {
199
+ action: 'migrated',
200
+ from: current,
201
+ to: MANIFEST_VERSION,
202
+ path: manifestPath,
203
+ backup: backupPath,
204
+ };
151
205
  }
152
206
 
153
207
  /**
@@ -156,6 +210,7 @@ export function saveCapabilityManifest(ctxDir) {
156
210
  export function formatCapabilities(manifest = DEFAULT_CAPABILITIES) {
157
211
  const lines = [];
158
212
  for (const [category, config] of Object.entries(manifest)) {
213
+ if (category.startsWith('_')) continue;
159
214
  lines.push(` ${category}:`);
160
215
  lines.push(` Agents: ${config.agents.map(a => a.replace('ctx-', '').replace('.md', '')).join(', ')}`);
161
216
  lines.push(` Allowed: ${config.allowed.join(', ')}`);
package/src/install.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
3
  import { fileURLToPath } from 'url';
4
+ import { saveCapabilityManifest } from './capabilities.js';
4
5
 
5
6
  const __filename = fileURLToPath(import.meta.url);
6
7
  const __dirname = path.dirname(__filename);
@@ -28,7 +29,7 @@ function printBanner() {
28
29
  `));
29
30
  console.log(` ${bold('CTX 4.0')} ${dim(`v${VERSION}`)}`);
30
31
  console.log(' Intelligent workflow orchestration for Claude Code.');
31
- console.log(' 21 agents. Skills. Hooks. Phase-based lifecycle.\n');
32
+ console.log(' 26 agents. 7 skills. Hooks. Phase-based lifecycle.\n');
32
33
  }
33
34
 
34
35
  function copyDir(src, dest) {
@@ -170,6 +171,12 @@ export async function install(options) {
170
171
  console.log(green(` ✓`) + ` Installed templates (${count} files)`);
171
172
  }
172
173
 
174
+ // Generate capability-manifest.json template from DEFAULT_CAPABILITIES.
175
+ // /ctx:init copies this into each project's .ctx/ so the PreToolUse hook
176
+ // (hooks/pre-tool-use.js) has a manifest to enforce against.
177
+ saveCapabilityManifest(destTemplates);
178
+ console.log(green(` ✓`) + ` Generated capability-manifest.json template`);
179
+
173
180
  // Write VERSION file
174
181
  fs.writeFileSync(path.join(ctxDir, 'VERSION'), VERSION);
175
182
  console.log(green(` ✓`) + ` Wrote VERSION (${VERSION})`);
@@ -178,8 +185,8 @@ export async function install(options) {
178
185
  console.log(`\n ${green('Done!')} Launch Claude Code and run ${cyan('/ctx:help')}.`);
179
186
  console.log(`
180
187
  ${bold('What was installed:')}
181
- ${dim('Agents:')} ~/.claude/agents/ctx-*.md (21 subagents)
182
- ${dim('Skills:')} ~/.claude/skills/ctx-*/ (3 skills)
188
+ ${dim('Agents:')} ~/.claude/agents/ctx-*.md (26 subagents)
189
+ ${dim('Skills:')} ~/.claude/skills/ctx-*/ (7 skills)
183
190
  ${dim('Commands:')} ~/.claude/commands/ctx/ (slash commands)
184
191
  ${dim('Hooks:')} ~/.claude/hooks/ctx-*.js (3 hook scripts)
185
192
  ${dim('Config:')} ~/.claude/settings.json (hooks registered)