instar 1.2.65 → 1.2.66

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.
@@ -0,0 +1,52 @@
1
+ /**
2
+ * installCodexHooks — wire instar's safety gates into a Codex CLI agent's
3
+ * native hook system, the Codex mirror of `installClaudeSettings`.
4
+ *
5
+ * Spec: docs/specs/codex-enforcement-hook-layer.md
6
+ *
7
+ * WHY: on Claude agents, instar's gates (external-operation, response-review,
8
+ * grounding, deferral, session-start, topic-context) are enforced via
9
+ * `.claude/settings.json` hooks. On Codex agents nothing enforced them — the
10
+ * gates were awareness-only. Codex CLI supports a Claude-compatible blocking
11
+ * hook system (verified: developers.openai.com/codex/hooks — PreToolUse can
12
+ * deny via `permissionDecision` or exit-2; events incl. SessionStart,
13
+ * PreToolUse, PermissionRequest, PostToolUse, UserPromptSubmit, Stop). This
14
+ * writes the gate registrations into Codex's discovery path.
15
+ *
16
+ * SCOPING (correctness-critical): writes the **per-project**
17
+ * `<projectDir>/.codex/hooks.json`, NOT the global `~/.codex/hooks.json`.
18
+ * The global root is shared with the operator's personal desktop Codex and
19
+ * every other Codex project on the machine — global enforcement hooks would
20
+ * intercept the operator's personal sessions. Per-project `.codex/` is a
21
+ * documented Codex discovery path and scopes the gates to this agent only.
22
+ *
23
+ * Invocation contract (Codex): the command receives the event JSON on stdin
24
+ * (no args), runs with the session cwd as working directory. We register
25
+ * absolute paths so discovery does not depend on cwd. The gate scripts'
26
+ * Codex-payload parsing is handled by the framework shim (spec P2); this
27
+ * module only writes the registrations.
28
+ *
29
+ * Idempotent + merge-safe: instar-owned entries are identified by a command
30
+ * path under `.instar/hooks/instar/` and replaced on every run; any
31
+ * user-added Codex hooks are preserved untouched.
32
+ */
33
+ /** Marker that identifies an instar-owned hook command (for merge-safe replace). */
34
+ export declare const INSTAR_HOOK_PATH_MARKER = ".instar/hooks/instar/";
35
+ interface CodexHookHandler {
36
+ type: 'command';
37
+ command: string;
38
+ timeout?: number;
39
+ }
40
+ interface CodexHookGroup {
41
+ matcher?: string;
42
+ hooks: CodexHookHandler[];
43
+ }
44
+ /** Build the instar-owned hook groups for each Codex event, with absolute script paths. */
45
+ export declare function buildInstarCodexHookGroups(projectDir: string): Record<string, CodexHookGroup[]>;
46
+ /**
47
+ * Write/merge instar gate hooks into `<projectDir>/.codex/hooks.json`.
48
+ * Preserves any user-added hooks; replaces instar-owned entries.
49
+ */
50
+ export declare function installCodexHooks(projectDir: string): string;
51
+ export {};
52
+ //# sourceMappingURL=installCodexHooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installCodexHooks.d.ts","sourceRoot":"","sources":["../../src/core/installCodexHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAKH,oFAAoF;AACpF,eAAO,MAAM,uBAAuB,0BAA0B,CAAC;AAE/D,UAAU,gBAAgB;IACxB,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AACD,UAAU,cAAc;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,gBAAgB,EAAE,CAAC;CAC3B;AAMD,2FAA2F;AAC3F,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,MAAM,GACjB,MAAM,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC,CA4ClC;AAQD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAwB5D"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * installCodexHooks — wire instar's safety gates into a Codex CLI agent's
3
+ * native hook system, the Codex mirror of `installClaudeSettings`.
4
+ *
5
+ * Spec: docs/specs/codex-enforcement-hook-layer.md
6
+ *
7
+ * WHY: on Claude agents, instar's gates (external-operation, response-review,
8
+ * grounding, deferral, session-start, topic-context) are enforced via
9
+ * `.claude/settings.json` hooks. On Codex agents nothing enforced them — the
10
+ * gates were awareness-only. Codex CLI supports a Claude-compatible blocking
11
+ * hook system (verified: developers.openai.com/codex/hooks — PreToolUse can
12
+ * deny via `permissionDecision` or exit-2; events incl. SessionStart,
13
+ * PreToolUse, PermissionRequest, PostToolUse, UserPromptSubmit, Stop). This
14
+ * writes the gate registrations into Codex's discovery path.
15
+ *
16
+ * SCOPING (correctness-critical): writes the **per-project**
17
+ * `<projectDir>/.codex/hooks.json`, NOT the global `~/.codex/hooks.json`.
18
+ * The global root is shared with the operator's personal desktop Codex and
19
+ * every other Codex project on the machine — global enforcement hooks would
20
+ * intercept the operator's personal sessions. Per-project `.codex/` is a
21
+ * documented Codex discovery path and scopes the gates to this agent only.
22
+ *
23
+ * Invocation contract (Codex): the command receives the event JSON on stdin
24
+ * (no args), runs with the session cwd as working directory. We register
25
+ * absolute paths so discovery does not depend on cwd. The gate scripts'
26
+ * Codex-payload parsing is handled by the framework shim (spec P2); this
27
+ * module only writes the registrations.
28
+ *
29
+ * Idempotent + merge-safe: instar-owned entries are identified by a command
30
+ * path under `.instar/hooks/instar/` and replaced on every run; any
31
+ * user-added Codex hooks are preserved untouched.
32
+ */
33
+ import fs from 'node:fs';
34
+ import path from 'node:path';
35
+ /** Marker that identifies an instar-owned hook command (for merge-safe replace). */
36
+ export const INSTAR_HOOK_PATH_MARKER = '.instar/hooks/instar/';
37
+ /** Build the instar-owned hook groups for each Codex event, with absolute script paths. */
38
+ export function buildInstarCodexHookGroups(projectDir) {
39
+ const node = (script) => ({
40
+ type: 'command',
41
+ command: `node ${path.join(projectDir, INSTAR_HOOK_PATH_MARKER, script)}`,
42
+ timeout: 5000,
43
+ });
44
+ const sh = (script) => ({
45
+ type: 'command',
46
+ command: `bash ${path.join(projectDir, INSTAR_HOOK_PATH_MARKER, script)}`,
47
+ timeout: 5000,
48
+ });
49
+ return {
50
+ // Pre-action gate. matcher '.*' = all tool calls (Codex treats the matcher as
51
+ // a regex against the tool name; a bare '*' is an invalid quantifier that
52
+ // matches NOTHING, so the gate silently never fires — '.*' is required.
53
+ // Verified live 2026-05-24: with '.*', dangerous-command-guard fires on Codex's
54
+ // exec_command tool and blocks `rm -rf /`; with '*'/'' it did not fire at all).
55
+ // Each script classifies and decides: dangerous-command-guard covers Codex's
56
+ // native shell/exec_command (the main destructive surface); external-operation-gate
57
+ // covers mcp__* tools; grounding-before-messaging gates messaging commands. All
58
+ // read the command from Codex's stdin payload — Codex's exec_command puts it in
59
+ // tool_input.cmd (Claude uses tool_input.command); the scripts shim arg→stdin and
60
+ // accept both field names.
61
+ PreToolUse: [
62
+ { matcher: '.*', hooks: [sh('dangerous-command-guard.sh'), node('external-operation-gate.js'), sh('grounding-before-messaging.sh')] },
63
+ ],
64
+ // Codex-only checkpoint. Routes to the same gate; the trust system
65
+ // auto-decides (allow/deny) with NO human prompt so autonomy is preserved.
66
+ PermissionRequest: [
67
+ { matcher: '.*', hooks: [node('external-operation-gate.js')] },
68
+ ],
69
+ // End-of-turn review: coherence/tone + deferral detection.
70
+ Stop: [
71
+ { matcher: '', hooks: [{ ...node('response-review.js'), timeout: 10000 }, node('deferral-detector.js')] },
72
+ ],
73
+ // Identity/context injection.
74
+ SessionStart: [
75
+ { matcher: '', hooks: [sh('session-start.sh')] },
76
+ ],
77
+ UserPromptSubmit: [
78
+ { matcher: '', hooks: [sh('telegram-topic-context.sh')] },
79
+ ],
80
+ };
81
+ }
82
+ function groupIsInstarOwned(group) {
83
+ return (group.hooks ?? []).some((h) => typeof h.command === 'string' && h.command.includes(INSTAR_HOOK_PATH_MARKER));
84
+ }
85
+ /**
86
+ * Write/merge instar gate hooks into `<projectDir>/.codex/hooks.json`.
87
+ * Preserves any user-added hooks; replaces instar-owned entries.
88
+ */
89
+ export function installCodexHooks(projectDir) {
90
+ const codexDir = path.join(projectDir, '.codex');
91
+ fs.mkdirSync(codexDir, { recursive: true });
92
+ const hooksPath = path.join(codexDir, 'hooks.json');
93
+ let config = {};
94
+ if (fs.existsSync(hooksPath)) {
95
+ try {
96
+ const parsed = JSON.parse(fs.readFileSync(hooksPath, 'utf-8'));
97
+ if (parsed && typeof parsed === 'object')
98
+ config = parsed;
99
+ }
100
+ catch {
101
+ // Corrupted — start fresh rather than block install.
102
+ }
103
+ }
104
+ const hooks = (config.hooks ??= {});
105
+ const desired = buildInstarCodexHookGroups(projectDir);
106
+ for (const [event, instarGroups] of Object.entries(desired)) {
107
+ const userGroups = (hooks[event] ?? []).filter((g) => !groupIsInstarOwned(g));
108
+ hooks[event] = [...userGroups, ...instarGroups];
109
+ }
110
+ fs.writeFileSync(hooksPath, JSON.stringify(config, null, 2) + '\n');
111
+ return hooksPath;
112
+ }
113
+ //# sourceMappingURL=installCodexHooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installCodexHooks.js","sourceRoot":"","sources":["../../src/core/installCodexHooks.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "1.2.65",
3
+ "version": "1.2.66",
4
4
  "description": "Coherence infrastructure for self-evolving AI agents — on the Claude Code or Codex subscription you already have.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-05-25T01:39:18.241Z",
5
- "instarVersion": "1.2.65",
4
+ "generatedAt": "2026-05-25T01:54:04.610Z",
5
+ "instarVersion": "1.2.66",
6
6
  "entryCount": 191,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -11,7 +11,7 @@
11
11
  "domain": "identity",
12
12
  "sourcePath": "src/core/PostUpdateMigrator.ts",
13
13
  "installedPath": ".instar/hooks/instar/session-start.sh",
14
- "contentHash": "298dee6bf9314642a3fbb90885a9e2c6aa8e944ffbd4209219481c5c6fd14df7",
14
+ "contentHash": "12706baa0f474d541a3d47fb6548a02e988727c7b150ac6ac351adaed4480e19",
15
15
  "since": "2025-01-01"
16
16
  },
17
17
  "hook:dangerous-command-guard": {
@@ -20,7 +20,7 @@
20
20
  "domain": "safety",
21
21
  "sourcePath": "src/core/PostUpdateMigrator.ts",
22
22
  "installedPath": ".instar/hooks/instar/dangerous-command-guard.sh",
23
- "contentHash": "298dee6bf9314642a3fbb90885a9e2c6aa8e944ffbd4209219481c5c6fd14df7",
23
+ "contentHash": "12706baa0f474d541a3d47fb6548a02e988727c7b150ac6ac351adaed4480e19",
24
24
  "since": "2025-01-01"
25
25
  },
26
26
  "hook:grounding-before-messaging": {
@@ -29,7 +29,7 @@
29
29
  "domain": "safety",
30
30
  "sourcePath": "src/core/PostUpdateMigrator.ts",
31
31
  "installedPath": ".instar/hooks/instar/grounding-before-messaging.sh",
32
- "contentHash": "298dee6bf9314642a3fbb90885a9e2c6aa8e944ffbd4209219481c5c6fd14df7",
32
+ "contentHash": "12706baa0f474d541a3d47fb6548a02e988727c7b150ac6ac351adaed4480e19",
33
33
  "since": "2025-01-01"
34
34
  },
35
35
  "hook:compaction-recovery": {
@@ -38,7 +38,7 @@
38
38
  "domain": "identity",
39
39
  "sourcePath": "src/core/PostUpdateMigrator.ts",
40
40
  "installedPath": ".instar/hooks/instar/compaction-recovery.sh",
41
- "contentHash": "298dee6bf9314642a3fbb90885a9e2c6aa8e944ffbd4209219481c5c6fd14df7",
41
+ "contentHash": "12706baa0f474d541a3d47fb6548a02e988727c7b150ac6ac351adaed4480e19",
42
42
  "since": "2025-01-01"
43
43
  },
44
44
  "hook:external-operation-gate": {
@@ -47,7 +47,7 @@
47
47
  "domain": "safety",
48
48
  "sourcePath": "src/core/PostUpdateMigrator.ts",
49
49
  "installedPath": ".instar/hooks/instar/external-operation-gate.js",
50
- "contentHash": "298dee6bf9314642a3fbb90885a9e2c6aa8e944ffbd4209219481c5c6fd14df7",
50
+ "contentHash": "12706baa0f474d541a3d47fb6548a02e988727c7b150ac6ac351adaed4480e19",
51
51
  "since": "2025-01-01"
52
52
  },
53
53
  "hook:deferral-detector": {
@@ -56,7 +56,7 @@
56
56
  "domain": "safety",
57
57
  "sourcePath": "src/core/PostUpdateMigrator.ts",
58
58
  "installedPath": ".instar/hooks/instar/deferral-detector.js",
59
- "contentHash": "298dee6bf9314642a3fbb90885a9e2c6aa8e944ffbd4209219481c5c6fd14df7",
59
+ "contentHash": "12706baa0f474d541a3d47fb6548a02e988727c7b150ac6ac351adaed4480e19",
60
60
  "since": "2025-01-01"
61
61
  },
62
62
  "hook:post-action-reflection": {
@@ -65,7 +65,7 @@
65
65
  "domain": "evolution",
66
66
  "sourcePath": "src/core/PostUpdateMigrator.ts",
67
67
  "installedPath": ".instar/hooks/instar/post-action-reflection.js",
68
- "contentHash": "298dee6bf9314642a3fbb90885a9e2c6aa8e944ffbd4209219481c5c6fd14df7",
68
+ "contentHash": "12706baa0f474d541a3d47fb6548a02e988727c7b150ac6ac351adaed4480e19",
69
69
  "since": "2025-01-01"
70
70
  },
71
71
  "hook:external-communication-guard": {
@@ -74,7 +74,7 @@
74
74
  "domain": "safety",
75
75
  "sourcePath": "src/core/PostUpdateMigrator.ts",
76
76
  "installedPath": ".instar/hooks/instar/external-communication-guard.js",
77
- "contentHash": "298dee6bf9314642a3fbb90885a9e2c6aa8e944ffbd4209219481c5c6fd14df7",
77
+ "contentHash": "12706baa0f474d541a3d47fb6548a02e988727c7b150ac6ac351adaed4480e19",
78
78
  "since": "2025-01-01"
79
79
  },
80
80
  "hook:scope-coherence-collector": {
@@ -83,7 +83,7 @@
83
83
  "domain": "coherence",
84
84
  "sourcePath": "src/core/PostUpdateMigrator.ts",
85
85
  "installedPath": ".instar/hooks/instar/scope-coherence-collector.js",
86
- "contentHash": "298dee6bf9314642a3fbb90885a9e2c6aa8e944ffbd4209219481c5c6fd14df7",
86
+ "contentHash": "12706baa0f474d541a3d47fb6548a02e988727c7b150ac6ac351adaed4480e19",
87
87
  "since": "2025-01-01"
88
88
  },
89
89
  "hook:scope-coherence-checkpoint": {
@@ -92,7 +92,7 @@
92
92
  "domain": "coherence",
93
93
  "sourcePath": "src/core/PostUpdateMigrator.ts",
94
94
  "installedPath": ".instar/hooks/instar/scope-coherence-checkpoint.js",
95
- "contentHash": "298dee6bf9314642a3fbb90885a9e2c6aa8e944ffbd4209219481c5c6fd14df7",
95
+ "contentHash": "12706baa0f474d541a3d47fb6548a02e988727c7b150ac6ac351adaed4480e19",
96
96
  "since": "2025-01-01"
97
97
  },
98
98
  "hook:free-text-guard": {
@@ -101,7 +101,7 @@
101
101
  "domain": "safety",
102
102
  "sourcePath": "src/core/PostUpdateMigrator.ts",
103
103
  "installedPath": ".instar/hooks/instar/free-text-guard.sh",
104
- "contentHash": "298dee6bf9314642a3fbb90885a9e2c6aa8e944ffbd4209219481c5c6fd14df7",
104
+ "contentHash": "12706baa0f474d541a3d47fb6548a02e988727c7b150ac6ac351adaed4480e19",
105
105
  "since": "2025-01-01"
106
106
  },
107
107
  "hook:claim-intercept": {
@@ -110,7 +110,7 @@
110
110
  "domain": "coherence",
111
111
  "sourcePath": "src/core/PostUpdateMigrator.ts",
112
112
  "installedPath": ".instar/hooks/instar/claim-intercept.js",
113
- "contentHash": "298dee6bf9314642a3fbb90885a9e2c6aa8e944ffbd4209219481c5c6fd14df7",
113
+ "contentHash": "12706baa0f474d541a3d47fb6548a02e988727c7b150ac6ac351adaed4480e19",
114
114
  "since": "2025-01-01"
115
115
  },
116
116
  "hook:claim-intercept-response": {
@@ -119,7 +119,7 @@
119
119
  "domain": "coherence",
120
120
  "sourcePath": "src/core/PostUpdateMigrator.ts",
121
121
  "installedPath": ".instar/hooks/instar/claim-intercept-response.js",
122
- "contentHash": "298dee6bf9314642a3fbb90885a9e2c6aa8e944ffbd4209219481c5c6fd14df7",
122
+ "contentHash": "12706baa0f474d541a3d47fb6548a02e988727c7b150ac6ac351adaed4480e19",
123
123
  "since": "2025-01-01"
124
124
  },
125
125
  "hook:auto-approve-permissions": {
@@ -128,7 +128,7 @@
128
128
  "domain": "safety",
129
129
  "sourcePath": "src/core/PostUpdateMigrator.ts",
130
130
  "installedPath": ".instar/hooks/instar/auto-approve-permissions.js",
131
- "contentHash": "298dee6bf9314642a3fbb90885a9e2c6aa8e944ffbd4209219481c5c6fd14df7",
131
+ "contentHash": "12706baa0f474d541a3d47fb6548a02e988727c7b150ac6ac351adaed4480e19",
132
132
  "since": "2025-01-01"
133
133
  },
134
134
  "job:health-check": {
@@ -1472,7 +1472,7 @@
1472
1472
  "type": "subsystem",
1473
1473
  "domain": "updates",
1474
1474
  "sourcePath": "src/core/PostUpdateMigrator.ts",
1475
- "contentHash": "298dee6bf9314642a3fbb90885a9e2c6aa8e944ffbd4209219481c5c6fd14df7",
1475
+ "contentHash": "12706baa0f474d541a3d47fb6548a02e988727c7b150ac6ac351adaed4480e19",
1476
1476
  "since": "2025-01-01"
1477
1477
  },
1478
1478
  "subsystem:scheduler": {
@@ -0,0 +1,57 @@
1
+ # Upgrade Guide — Codex safety hooks now actually fire
2
+
3
+ <!-- bump: patch -->
4
+ <!-- patch = bug fixes, refactors, test additions, doc updates -->
5
+
6
+ ## What Changed
7
+
8
+ **Fix: on Codex (codex-cli) agents, the PreToolUse safety guard now actually fires
9
+ and blocks dangerous commands. Previously it was registered but silently never ran.**
10
+
11
+ Two mismatches between how instar wrote the Codex hook config and how Codex actually
12
+ invokes hooks:
13
+
14
+ 1. **Invalid tool-call matcher.** `installCodexHooks` emitted `matcher: "*"`. Codex
15
+ treats the matcher as a regex against the tool name, and a bare `*` is an invalid
16
+ quantifier that matches nothing — so the gate never fired. Session-level hooks
17
+ (SessionStart, UserPromptSubmit) fired fine because they aren't tool-matched, which
18
+ masked the problem. Changed to `".*"` (match all tool calls).
19
+ 2. **Wrong command field.** Codex's shell tool is `exec_command` and puts the command
20
+ in `tool_input.cmd`; the guard's stdin shim only read `tool_input.command` (Claude's
21
+ shape), so even once it fired it saw an empty command. The shim now reads either.
22
+
23
+ Claude agents are unaffected — their existing argument path is unchanged and still tested.
24
+
25
+ ## What to Tell Your User
26
+
27
+ If I'm running on the Codex engine, my safety guard that blocks catastrophic commands —
28
+ things like wiping a disk — now genuinely stops them before they run. Until this fix the
29
+ guard was installed but never actually triggered on Codex, so dangerous shell commands
30
+ could slip through. Nothing changes if I'm running on Claude; this only closes the gap on
31
+ the Codex side.
32
+
33
+ ## Summary of New Capabilities
34
+
35
+ No new user-facing capabilities — this is a correctness fix to the existing Codex
36
+ enforcement-hook layer. Codex agents that update will have a working PreToolUse safety
37
+ gate (dangerous-command guard + external-operation gate + grounding check) where before it
38
+ was inert. Existing Codex agents receive it on update via PostUpdateMigrator (matcher +
39
+ stdin-shim fixes ship through both the init and update paths).
40
+
41
+ ## Evidence
42
+
43
+ **Live reproduction (real Codex engine, not a simulation).** Regenerated a Codex test
44
+ agent's hooks from freshly-built source via the real `refreshHooksAndSettings` path (no
45
+ hand-editing, no debug instrumentation), launched real interactive Codex v0.133.0, and told
46
+ it to run `echo 'rm -rf /'`.
47
+
48
+ - **Before the fix:** identical setup — Codex ran the command unblocked; the guard never
49
+ fired (debug trace empty).
50
+ - **After the fix:** Codex displayed `• PreToolUse hook (blocked) — BLOCKED: Catastrophic
51
+ command detected: rm -rf /` and did not execute it. First confirmed firing of the Codex
52
+ enforcement guard in the real engine.
53
+
54
+ **Regression coverage:** the integration test now uses Codex's verified payload shape
55
+ (`tool_name: exec_command`, `tool_input.cmd`) — it would have failed before the shim fix —
56
+ plus a Claude-stdin case; a unit test asserts the matcher is `".*"`, not `"*"`. Full Codex
57
+ hook suite: 19 green. `tsc` clean.
@@ -0,0 +1,32 @@
1
+ # Side-Effects Review: Codex enforcement hooks — P1 (installCodexHooks writer + tests)
2
+
3
+ ## Change
4
+ New module `src/core/installCodexHooks.ts` + `tests/unit/installCodexHooks.test.ts` (6 tests). The module writes/merges instar's safety-gate registrations into a Codex agent's per-project `<projectDir>/.codex/hooks.json`, mapping the existing gate scripts (`external-operation-gate.js`, `grounding-before-messaging.sh`, `response-review.js`, `deferral-detector.js`, `session-start.sh`, `telegram-topic-context.sh`) to Codex's verified hook events (PreToolUse, PermissionRequest, Stop, SessionStart, UserPromptSubmit), using the verified Codex hooks.json schema.
5
+
6
+ ## Scope of effect (this commit)
7
+ - **Capability-only, NOT yet wired.** This commit adds the writer + tests; it is NOT yet invoked from the init/refresh path (that is P1b, with a wiring-integrity test). So there is **no runtime behavior change** until the wiring lands — the function is inert until called.
8
+ - When wired, it writes a single file: `<projectDir>/.codex/hooks.json`. Nothing else.
9
+
10
+ ## Scoping (correctness-critical)
11
+ - Writes the **per-project** `.codex/hooks.json`, never the global `~/.codex/`. The global root is shared with the operator's personal desktop Codex and every other Codex project — global hooks would intercept the operator's personal sessions. Per-project scoping confines the gates to this agent's project dir. Unit-tested (asserts the path is not under `~/.codex`).
12
+
13
+ ## Merge-safety
14
+ - Instar-owned entries are identified by command path containing `.instar/hooks/instar/`. On re-run, instar groups are replaced; any user-added Codex hooks are preserved verbatim. Idempotent (re-run yields identical file). Both behaviors unit-tested.
15
+
16
+ ## Signal vs Authority
17
+ - The writer carries no runtime authority. The hooks it registers are low-context triggers that route to the server-side authority gates (`/operations/evaluate`, `/review/evaluate`). The writer just emits config; nothing in it decides allow/deny.
18
+
19
+ ## Over/under-block, abstraction
20
+ - N/A — config writer, not a gate. The registered gates are the existing, unchanged authorities. No new decision boundary introduced here.
21
+
22
+ ## Migration parity
23
+ - Not in this commit. `migrateCodexHooks()` (P3) will backfill existing Codex agents. Tracked in the spec phase plan; not deferred-and-forgotten.
24
+
25
+ ## Rollback
26
+ - Trivial: delete the two files. No deployed effect (unwired). Once wired, removing the instar entries from `.codex/hooks.json` is a clean revert with no data migration.
27
+
28
+ ## Tests
29
+ - 6 unit tests: per-project location (not global), all five events with the verified schema, absolute cwd-independent script paths, idempotency, user-hook preservation + instar replace, pure builder. All passing; tsc clean.
30
+
31
+ ## Publish
32
+ - Feature branch `echo/codex-enforcement-hooks`. Not shipped; no separate publish.
@@ -0,0 +1,29 @@
1
+ # Side-Effects Review: Codex enforcement hooks — P1b (wire installCodexHooks into init/refresh)
2
+
3
+ ## Change
4
+ `src/commands/init.ts`: `refreshHooksAndSettings()` now calls `installCodexHooks(projectDir)` gated on `enabledFrameworks.includes('codex-cli')`, mirroring the existing `claudeEnabled → installClaudeSettings` block. Plus a wiring-integrity test (`tests/unit/codex-hooks-wiring.test.ts`).
5
+
6
+ `refreshHooksAndSettings` is the single path that both `instar init` (line ~1097) and the update path invoke — so this one call site covers BOTH new and existing codex agents.
7
+
8
+ ## Runtime behavior change
9
+ - Codex-cli agents now get `<projectDir>/.codex/hooks.json` written on init AND on every update/refresh. Claude-only agents are unaffected (gated). Both verified by the wiring-integrity test (codex → file created with instar gates; claude-only → no file; both → file created).
10
+
11
+ ## Sequencing risk (IMPORTANT — captured, not deferred-and-forgotten)
12
+ - The wiring registers the existing gate scripts (`external-operation-gate.js`, `response-review.js`, etc.) into Codex's hook events. Those scripts currently parse **Claude's** hook stdin payload; the **Codex-payload shim is P2**. So on a *live* Codex session, the scripts could misbehave (parse errors → potentially an erroneous exit-2 block) until P2 lands.
13
+ - **Why this is safe now:** this is a feature branch, NOT deployed. codey runs the released v1.2.53, which does not carry this wiring. No live codex agent has these hooks yet.
14
+ - **Hard sequencing constraint for the build:** **P2 (gate-script Codex-payload shim) MUST land before the P6 deploy.** The phase plan already orders P2 → P6; this review makes the constraint explicit. Do not deploy P1 wiring without P2.
15
+
16
+ ## Signal vs Authority
17
+ - Unchanged from P1: the hooks route to the server-side authority gates; the wiring just ensures they're registered for codex agents. No new authority.
18
+
19
+ ## Migration parity
20
+ - `instar init` + update both flow through `refreshHooksAndSettings`, so existing codex agents get the wiring on their next update. (A dedicated `migrateCodexHooks` / always-overwrite-instar-owned hardening is P3.)
21
+
22
+ ## Rollback
23
+ - Remove the `codexEnabled` block in `refreshHooksAndSettings` + the import. No deployed effect (branch-only).
24
+
25
+ ## Tests
26
+ - Wiring-integrity: 3 tests (codex → wired, claude-only → not wired, both → wired). Plus the P1a unit suite (6). tsc + lint clean.
27
+
28
+ ## Publish
29
+ - Feature branch. Not shipped.
@@ -0,0 +1,36 @@
1
+ # Side-Effects Review: Codex enforcement hooks — P2 (shell-gate works under Codex)
2
+
3
+ ## Change
4
+ Closes the gap from §4.2d (as-wired-in-P1, Codex's native shell/exec/apply_patch would have passed UNGATED).
5
+ 1. **stdin shim** for the two arg-reading safety scripts so they read `tool_input.command` from Codex's stdin JSON when no positional arg is present (Claude's `$1` path unchanged):
6
+ - `dangerous-command-guard.sh` — both source copies kept consistent: `PostUpdateMigrator.getDangerousCommandGuard()` (always-overwrite/migration canonical) AND the inline duplicate in `init.ts`.
7
+ - `grounding-before-messaging.sh` — `PostUpdateMigrator.getGroundingBeforeMessaging()` (canonical, used by migration + init).
8
+ 2. **Mapping fix:** added `dangerous-command-guard.sh` to `installCodexHooks` `buildInstarCodexHookGroups()` PreToolUse group (coupled with the shim — mapping without shim would be the false-install trap).
9
+
10
+ ## Why
11
+ `external-operation-gate.js` only gates `mcp__*` tools (exits 0 otherwise). Codex's destructive class is native `shell`/`exec`/`apply_patch`, which Claude gates via `dangerous-command-guard` on the Bash matcher. P1 omitted that gate from the Codex mapping, and the script couldn't read Codex's input anyway. Both fixed.
12
+
13
+ ## Over/under-block
14
+ - The blocked catastrophic patterns are identical to Claude's (`rm -rf /`, `mkfs.`, `dd if=`, fork-bomb, etc.) — no Codex-specific over-block. Empty/garbage stdin → INPUT empty → no match → pass (no false-block); tested.
15
+
16
+ ## Signal vs Authority
17
+ - `dangerous-command-guard` is a deterministic low-context guard on catastrophic patterns + a config safety-level gate; nuanced authority remains the server-side gate. Adding it to Codex mirrors Claude's posture — no new authority.
18
+
19
+ ## Near-silence
20
+ - Blocks write the reason to **stderr** (the agent sees it), never a user message. No notification spam.
21
+
22
+ ## Migration parity
23
+ - The scripts are always-overwritten on migration (getDangerousCommandGuard / getGroundingBeforeMessaging), so existing Codex agents get the shim on update; the mapping runs via refreshHooksAndSettings (P1b) on init + update.
24
+
25
+ ## Rollback
26
+ - Revert the 3 shim insertions + the one mapping-line addition. No data migration.
27
+
28
+ ## Tests (real, no mocks)
29
+ - Unit: 9 (incl. new assertion that dangerous-command-guard is in the Codex PreToolUse mapping).
30
+ - **Integration (the proof): 5** — generates the REAL script via refreshHooksAndSettings, then: BLOCKS `rm -rf /` via Codex stdin/no-arg (exit 2), PASSES benign via stdin, still BLOCKS via Claude arg path (regression), no false-block on garbage stdin.
31
+
32
+ ## Sequencing
33
+ - Satisfies the P2 hard-constraint (shell gating works under Codex) before any P6 deploy. Remaining: PermissionRequest exit-2 confirmation (P4), the live codey E2E (P5).
34
+
35
+ ## Publish
36
+ - Feature branch. Not shipped.
@@ -0,0 +1,25 @@
1
+ # Side-Effects Review: Codex enforcement hooks — P3 (migration parity)
2
+
3
+ ## Change
4
+ `PostUpdateMigrator.migrateHooks()` now calls `installCodexHooks(this.config.projectDir)` gated on `getEnabledFrameworks().includes('codex-cli')`, writing the per-project `.codex/hooks.json` for existing Codex agents on update. + import.
5
+
6
+ ## Why (Migration Parity Standard — non-negotiable)
7
+ `installCodexHooks` ran ONLY from init's `refreshHooksAndSettings` (verified: that function's sole caller is `init.ts`). Existing agents update via `PostUpdateMigrator`, which wrote the gate SCRIPTS (with the P2 shim) but NOT the `.codex/hooks.json` registration. So without this, an existing Codex agent would get the updated guard scripts yet never the registration that makes Codex fire them — "works for new agents only" = broken. This closes it.
8
+
9
+ ## Scope
10
+ - On update, codex-cli agents get `.codex/hooks.json` written/refreshed (idempotent; preserves user-added Codex hooks via the command-path ownership check). Claude-only agents unaffected (gated). The referenced gate scripts are written earlier in the same `migrateHooks` pass.
11
+
12
+ ## Idempotency
13
+ - Tested: repeated migration yields exactly one instar PreToolUse group (no accumulation).
14
+
15
+ ## Signal vs Authority / Over-block
16
+ - Unchanged from P1/P2 — this only ensures the registration reaches existing agents. No new authority, no new block patterns.
17
+
18
+ ## Rollback
19
+ - Revert the `migrateHooks` codex block + the import. No data migration.
20
+
21
+ ## Tests
22
+ - 3 migration tests: codex-cli agent → `.codex/hooks.json` written (with dangerous-command-guard in PreToolUse); claude-only → not written; idempotent across repeated migrations. Full P1–P3 sweep: 17 green. tsc + lint clean.
23
+
24
+ ## Publish
25
+ - Feature branch. Not shipped.
@@ -0,0 +1,38 @@
1
+ # Side-Effects Review: Codex enforcement hooks — P5c (the guard actually fires)
2
+
3
+ ## Change
4
+ Two source fixes that make the Codex PreToolUse gate actually fire on the real Codex engine (previously it was registered but silently never invoked):
5
+
6
+ 1. **`src/core/installCodexHooks.ts`** — PreToolUse + PermissionRequest matcher changed `'*'` → `'.*'`. Codex treats the matcher as a regex against the tool name; a bare `*` is an invalid quantifier (no preceding atom) that matches nothing, so the gate never fired. `.*` matches all tool calls.
7
+ 2. **`src/core/PostUpdateMigrator.ts`** (dangerous-command-guard + grounding-before-messaging generators) and **`src/commands/init.ts`** (inline dangerous-command-guard) — the stdin shim now reads `tool_input.command OR tool_input.cmd`. Codex's shell tool is `exec_command` and delivers the command in `tool_input.cmd`; Claude uses `tool_input.command`. The prior shim read only `command`, so even when fired against Codex it saw an empty string.
8
+
9
+ ## Why
10
+ Live verification (host codex-cli v0.133.0, interactive, hooks trusted) showed SessionStart + UserPromptSubmit hooks fired but the PreToolUse dangerous-command-guard did NOT — even trusted. Diagnosing from the Codex session rollout log revealed the matcher was an invalid regex AND the command field name differed. The earlier P5b conclusion ("root cause = hook-trust model") was a red herring for the non-firing symptom: trust gates whether hooks run at all, but with trust granted the guard still failed to fire for these two reasons.
11
+
12
+ ## Scope / blast radius
13
+ - Codex agents only in effect: `.codex/hooks.json` is written solely for `enabledFrameworks.includes('codex-cli')`. Claude-only agents are unaffected (the guard scripts gained a stdin fallback that is inert when `$1` is supplied — Claude's existing arg path is unchanged and still tested).
14
+ - With matcher `.*`, all three PreToolUse hooks now fire on every Codex tool call. Verified non-harmful: `external-operation-gate.js` exits 0 for any non-`mcp__*` tool (so `exec_command` passes straight through); `grounding-before-messaging.sh` only blocks when the command matches its messaging regex; `dangerous-command-guard.sh` only blocks catastrophic/risky patterns. No false-block surface introduced.
15
+ - The `cmd`-field fallback is additive: `command or cmd or ''`. Claude payloads (`command`) are read first and unchanged.
16
+
17
+ ## Signal vs Authority / over-block
18
+ - Unchanged authority model: hooks remain low-context triggers that exit-2 on deterministic catastrophic patterns or route to the server-side gate. No new block patterns added; only the delivery (matcher + field) was corrected so existing patterns reach the guard.
19
+
20
+ ## Migration parity
21
+ - Both the init generator (`init.ts`) and the update generator (`PostUpdateMigrator.ts`) carry the shim fix, so new AND existing Codex agents get the working guard. The matcher fix lives in `installCodexHooks.ts`, called from both `refreshHooksAndSettings` (init) and `migrateHooks` (update, P3).
22
+
23
+ ## Live proof (evidence bar)
24
+ Regenerated codey's hooks from freshly-built source via the real `refreshHooksAndSettings` path (no hand-patch, no debug instrumentation), launched real interactive Codex 0.133, instructed it to run `echo 'rm -rf /'` → Codex displayed `• PreToolUse hook (blocked) — BLOCKED: Catastrophic command detected: rm -rf /` and did not execute it. First confirmed firing of the Codex enforcement guard in the real engine. Before the fix the identical setup ran the command unblocked.
25
+
26
+ ## Tests
27
+ - `tests/integration/codex-dangerous-command-block.test.ts` rewritten to the verified Codex shape (`tool_name: 'exec_command'`, `tool_input: { cmd, yield_time_ms }`) — would have failed before the `cmd` shim; plus a Claude-stdin (`command`) case so both field paths are covered.
28
+ - `tests/unit/installCodexHooks.test.ts` asserts `PreToolUse`/`PermissionRequest` matcher === `'.*'` (regression guard against the invalid `*`).
29
+ - Full codex suite: 19 green (7 + 3 + 3 + 6). tsc clean.
30
+
31
+ ## Rollback
32
+ - Revert the matcher to its prior value and drop the `cmd` fallback in the three generators. No data migration. (Rollback re-breaks Codex enforcement — not advised.)
33
+
34
+ ## Follow-on (tracked, NOT deferred-broken)
35
+ - **P6a managed hooks**: trust remains a separate concern — even `--dangerously-bypass-hook-trust` still pops an interactive trust prompt + a model-upsell prompt (would freeze unattended autonomy), and a trust-gated hook lets the agent decline ("continue without trusting"), so it can disable its own guard. Managed hooks (run-by-policy, agent-can't-disable) fix both. Genuine design fork → paused for Justin's input. Does not block this correctness fix shipping.
36
+
37
+ ## Publish
38
+ - Feature branch `echo/codex-enforcement-hooks`. Targets release v1.2.57 once P6 (awareness + crossreview) completes.