oh-my-customcodex 0.4.15 → 0.5.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 (44) hide show
  1. package/README.md +7 -7
  2. package/dist/cli/index.js +65 -20
  3. package/dist/index.js +40 -4
  4. package/package.json +1 -1
  5. package/templates/.claude/agents/mgr-gitnerd.md +4 -0
  6. package/templates/.claude/agents/mgr-sauron.md +5 -4
  7. package/templates/.claude/hooks/hooks.json +13 -0
  8. package/templates/.claude/hooks/scripts/context-budget-advisor.sh +40 -2
  9. package/templates/.claude/hooks/scripts/cost-cap-advisor.sh +8 -3
  10. package/templates/.claude/hooks/scripts/destructive-git-guard.sh +53 -0
  11. package/templates/.claude/hooks/scripts/omcustom-auto-update.sh +5 -5
  12. package/templates/.claude/hooks/scripts/session-env-check.sh +8 -6
  13. package/templates/.claude/hooks/scripts/stuck-detector.sh +2 -2
  14. package/templates/.claude/ontology/skills.yaml +3 -3
  15. package/templates/.claude/rules/MUST-agent-design.md +1 -0
  16. package/templates/.claude/rules/MUST-orchestrator-coordination.md +6 -0
  17. package/templates/.claude/rules/MUST-safety.md +15 -0
  18. package/templates/.claude/rules/SHOULD-hud-statusline.md +2 -0
  19. package/templates/.claude/skills/gitlab/SKILL.md +346 -0
  20. package/templates/.claude/skills/goal/SKILL.md +5 -3
  21. package/templates/.claude/skills/harness-synthesizer/SKILL.md +32 -0
  22. package/templates/.claude/skills/help/SKILL.md +2 -2
  23. package/templates/.claude/skills/lists/SKILL.md +2 -2
  24. package/templates/.claude/skills/npm-version/SKILL.md +6 -0
  25. package/templates/.claude/skills/omcodex-release-notes/SKILL.md +5 -4
  26. package/templates/.claude/skills/post-release-followup/SKILL.md +1 -1
  27. package/templates/.claude/skills/status/SKILL.md +1 -1
  28. package/templates/.claude/statusline.sh +24 -3
  29. package/templates/AGENTS.md.en +5 -3
  30. package/templates/AGENTS.md.ko +5 -3
  31. package/templates/CLAUDE.md +12 -3
  32. package/templates/CLAUDE.md.en +12 -3
  33. package/templates/CLAUDE.md.ko +12 -3
  34. package/templates/guides/claude-code/04-agent-skills.md +16 -0
  35. package/templates/guides/claude-code/06-mcp.md +6 -0
  36. package/templates/guides/claude-code/13-cli-flags.md +13 -1
  37. package/templates/guides/claude-code/15-version-compatibility.md +59 -0
  38. package/templates/guides/claude-code/index.yaml +5 -0
  39. package/templates/guides/git-safety/README.md +44 -0
  40. package/templates/guides/hook-data-flow/README.md +16 -16
  41. package/templates/guides/index.yaml +6 -0
  42. package/templates/guides/professor-triage/phases.md +324 -0
  43. package/templates/manifest.json +3 -3
  44. package/templates/workflows/auto-dev.yaml +13 -1
package/README.md CHANGED
@@ -13,7 +13,7 @@
13
13
 
14
14
  **[한국어 문서 (Korean)](./README_ko.md)**
15
15
 
16
- 49 agents. 118 skills. 22 rules. One command.
16
+ 49 agents. 119 skills. 22 rules. One command.
17
17
 
18
18
  ```bash
19
19
  npm install -g oh-my-customcodex && cd your-project && omcustomcodex init
@@ -134,7 +134,7 @@ Each agent declares its tools, model, memory scope, and limitations in YAML fron
134
134
 
135
135
  ---
136
136
 
137
- ### Skills (118)
137
+ ### Skills (119)
138
138
 
139
139
  | Category | Count | Includes |
140
140
  |----------|-------|----------|
@@ -147,7 +147,7 @@ Each agent declares its tools, model, memory scope, and limitations in YAML fron
147
147
  | Package | 3 | npm-publish, npm-version, npm-audit |
148
148
  | Optimization | 3 | optimize-analyze, optimize-bundle, optimize-report |
149
149
  | Security | 3 | adversarial-review, cve-triage, jinja2-prompts |
150
- | Other | 12 | codex-exec, claude-native, visual-ralph, visual-verdict, vercel-deploy, skills-sh-search, result-aggregation, writing-clearly-and-concisely, and more |
150
+ | Other | 13 | codex-exec, claude-native, gitlab, visual-ralph, visual-verdict, vercel-deploy, skills-sh-search, result-aggregation, writing-clearly-and-concisely, and more |
151
151
 
152
152
  Skills use a 3-tier scope system: `core` (universal), `harness` (agent/skill maintenance), `package` (project-specific).
153
153
 
@@ -170,7 +170,7 @@ All commands are invoked inside the oh-my-customcodex GPT Codex + OMX session.
170
170
  | `/ambiguity-gate` | Pre-routing ambiguity analysis |
171
171
  | `/pre-generation-arch-check` | Check architecture risks before implementation |
172
172
  | `/adversarial-review` | Attacker-mindset security code review |
173
- | `/goal` | Keep a concrete objective in view through planning, execution, and verification |
173
+ | `/omcustomcodex:goal` | Keep a concrete objective in view through planning, execution, and verification |
174
174
  | `/pipeline` | Execute YAML-defined pipelines |
175
175
  | `/pipeline resume` | Resume a halted pipeline from last failure point |
176
176
 
@@ -228,7 +228,7 @@ Key rules: R010 (orchestrator never writes files), R009 (parallel execution mand
228
228
 
229
229
  ---
230
230
 
231
- ### Guides (47)
231
+ ### Guides (48)
232
232
 
233
233
  Reference documentation covering best practices, architecture decisions, and integration patterns. Located in `guides/` at project root, covering topics from agent design to CI/CD to observability.
234
234
 
@@ -287,8 +287,8 @@ your-project/
287
287
  │ ├── contexts/ # 4 shared context files
288
288
  │ └── ontology/ # Knowledge graph for RAG
289
289
  ├── .agents/
290
- │ └── skills/ # 118 installed skill modules
291
- └── guides/ # 47 reference documents
290
+ │ └── skills/ # 119 installed skill modules
291
+ └── guides/ # 48 reference documents
292
292
  ```
293
293
 
294
294
  ### Source Repository And Compatibility Surfaces
package/dist/cli/index.js CHANGED
@@ -1019,7 +1019,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1019
1019
  this._exitCallback = (err) => {
1020
1020
  if (err.code !== "commander.executeSubCommandAsync") {
1021
1021
  throw err;
1022
- } else {}
1022
+ }
1023
1023
  };
1024
1024
  }
1025
1025
  return this;
@@ -3091,7 +3091,7 @@ var init_package = __esm(() => {
3091
3091
  workspaces: [
3092
3092
  "packages/*"
3093
3093
  ],
3094
- version: "0.4.15",
3094
+ version: "0.5.0",
3095
3095
  requiresCC: ">=2.1.121",
3096
3096
  claudeCode: {
3097
3097
  minimumVersion: "2.1.121",
@@ -10179,6 +10179,23 @@ function sortProjects(projects) {
10179
10179
  return a.name.localeCompare(b.name);
10180
10180
  });
10181
10181
  }
10182
+ async function buildRegistryProjectInfo(projectPath, entry, options, home, currentVersion) {
10183
+ if (!matchesSearchPaths(projectPath, options.paths))
10184
+ return null;
10185
+ if (!isUnderHome(projectPath, home))
10186
+ return null;
10187
+ if (!await fileExists(projectPath))
10188
+ return null;
10189
+ return {
10190
+ name: basename5(projectPath),
10191
+ path: projectPath,
10192
+ version: entry.version || null,
10193
+ installedAt: entry.installedAt || null,
10194
+ updatedAt: entry.updatedAt || null,
10195
+ status: computeStatus(entry.version || null, currentVersion),
10196
+ detectionMethod: "registry"
10197
+ };
10198
+ }
10182
10199
  async function findProjects(options = {}) {
10183
10200
  const currentVersion = await getTemplateVersion();
10184
10201
  const registry = await readRegistry();
@@ -10192,19 +10209,9 @@ async function findProjects(options = {}) {
10192
10209
  const results = [];
10193
10210
  const home = process.env.HOME ?? homedir3();
10194
10211
  for (const [projectPath, entry] of Object.entries(registry.projects)) {
10195
- if (!matchesSearchPaths(projectPath, options.paths))
10196
- continue;
10197
- if (!isUnderHome(projectPath, home))
10198
- continue;
10199
- results.push({
10200
- name: basename5(projectPath),
10201
- path: projectPath,
10202
- version: entry.version || null,
10203
- installedAt: entry.installedAt || null,
10204
- updatedAt: entry.updatedAt || null,
10205
- status: computeStatus(entry.version || null, currentVersion),
10206
- detectionMethod: "registry"
10207
- });
10212
+ const project = await buildRegistryProjectInfo(projectPath, entry, options, home, currentVersion);
10213
+ if (project)
10214
+ results.push(project);
10208
10215
  }
10209
10216
  return sortProjects(results);
10210
10217
  }
@@ -19772,7 +19779,7 @@ var require_dbcs_codec = __commonJS((exports) => {
19772
19779
  if (resCode !== undefined) {
19773
19780
  dbcsCode = resCode;
19774
19781
  nextChar = uCode;
19775
- } else {}
19782
+ }
19776
19783
  }
19777
19784
  seqObj = undefined;
19778
19785
  } else if (uCode >= 0) {
@@ -19837,7 +19844,7 @@ var require_dbcs_codec = __commonJS((exports) => {
19837
19844
  newBuf[j2++] = dbcsCode >> 8;
19838
19845
  newBuf[j2++] = dbcsCode & 255;
19839
19846
  }
19840
- } else {}
19847
+ }
19841
19848
  this.seqObj = undefined;
19842
19849
  }
19843
19850
  if (this.leadSurrogate !== -1) {
@@ -31413,6 +31420,7 @@ async function runFullUpdatePostProcessing(options, result, config) {
31413
31420
  const removed = await removeDeprecatedFiles(options.targetDir, options);
31414
31421
  result.removedDeprecatedFiles = removed;
31415
31422
  if (!options.dryRun) {
31423
+ await ensureStatusLineConfig(options.targetDir);
31416
31424
  await updateEntryDoc(options.targetDir, config, options);
31417
31425
  }
31418
31426
  }
@@ -31431,6 +31439,34 @@ async function runFullUpdatePostProcessing(options, result, config) {
31431
31439
  });
31432
31440
  }
31433
31441
  }
31442
+ async function ensureStatusLineConfig(targetDir) {
31443
+ const layout = getProviderLayout();
31444
+ const settingsPath = join17(targetDir, layout.rootDir, "settings.local.json");
31445
+ const statusLineConfig = {
31446
+ type: "command",
31447
+ command: `${layout.rootDir}/statusline.sh`,
31448
+ padding: 0,
31449
+ refreshInterval: 10
31450
+ };
31451
+ if (!await fileExists(settingsPath)) {
31452
+ await ensureDirectory(join17(settingsPath, ".."));
31453
+ await writeJsonFile(settingsPath, { statusLine: statusLineConfig });
31454
+ return;
31455
+ }
31456
+ const settings = await readJsonFile(settingsPath);
31457
+ const statusLine = settings.statusLine;
31458
+ if (!statusLine || typeof statusLine !== "object" || Array.isArray(statusLine)) {
31459
+ settings.statusLine = statusLineConfig;
31460
+ await writeJsonFile(settingsPath, settings);
31461
+ return;
31462
+ }
31463
+ const mergedStatusLine = statusLine;
31464
+ if (mergedStatusLine.refreshInterval === undefined) {
31465
+ mergedStatusLine.refreshInterval = statusLineConfig.refreshInterval;
31466
+ settings.statusLine = mergedStatusLine;
31467
+ await writeJsonFile(settingsPath, settings);
31468
+ }
31469
+ }
31434
31470
  function compareSemver2(a, b) {
31435
31471
  const pa = a.split(".").map(Number);
31436
31472
  const pb = b.split(".").map(Number);
@@ -31502,6 +31538,15 @@ function checkAndInstallOmxAfterUpdate() {
31502
31538
  }
31503
31539
  }
31504
31540
  }
31541
+ async function handleNoUpdateResult(options, result) {
31542
+ const isFullUpdate = !options.components || options.components.length === 0;
31543
+ if (isFullUpdate && !options.dryRun) {
31544
+ await ensureStatusLineConfig(options.targetDir);
31545
+ }
31546
+ info("update.no_updates");
31547
+ result.success = true;
31548
+ result.skippedComponents = options.components || getAllUpdateComponents();
31549
+ }
31505
31550
  async function update(options) {
31506
31551
  const result = createUpdateResult();
31507
31552
  try {
@@ -31520,9 +31565,7 @@ async function update(options) {
31520
31565
  const updateCheck = await checkForUpdates(options.targetDir);
31521
31566
  result.newVersion = updateCheck.latestVersion;
31522
31567
  if (!updateCheck.hasUpdates && !options.force) {
31523
- info("update.no_updates");
31524
- result.success = true;
31525
- result.skippedComponents = options.components || getAllUpdateComponents();
31568
+ await handleNoUpdateResult(options, result);
31526
31569
  return result;
31527
31570
  }
31528
31571
  await handleBackupIfRequested(options.targetDir, !!options.backup, result);
@@ -32022,8 +32065,10 @@ function reportProjectUpdateResult(project, result, currentVersion) {
32022
32065
  }
32023
32066
  async function updateAllProjects(options) {
32024
32067
  const { findProjects: findProjects2 } = await Promise.resolve().then(() => (init_projects(), exports_projects));
32068
+ const { cleanRegistry: cleanRegistry2 } = await Promise.resolve().then(() => (init_registry(), exports_registry));
32025
32069
  const currentVersion = package_default.version;
32026
32070
  console.log(i18n.t("cli.update.allScanning"));
32071
+ await cleanRegistry2();
32027
32072
  const projects = await findProjects2();
32028
32073
  if (projects.length === 0) {
32029
32074
  console.log(i18n.t("cli.update.allNoneFound"));
package/dist/index.js CHANGED
@@ -2180,7 +2180,7 @@ var package_default = {
2180
2180
  workspaces: [
2181
2181
  "packages/*"
2182
2182
  ],
2183
- version: "0.4.15",
2183
+ version: "0.5.0",
2184
2184
  requiresCC: ">=2.1.121",
2185
2185
  claudeCode: {
2186
2186
  minimumVersion: "2.1.121",
@@ -5015,6 +5015,7 @@ async function runFullUpdatePostProcessing(options, result, config) {
5015
5015
  const removed = await removeDeprecatedFiles(options.targetDir, options);
5016
5016
  result.removedDeprecatedFiles = removed;
5017
5017
  if (!options.dryRun) {
5018
+ await ensureStatusLineConfig(options.targetDir);
5018
5019
  await updateEntryDoc(options.targetDir, config, options);
5019
5020
  }
5020
5021
  }
@@ -5033,6 +5034,34 @@ async function runFullUpdatePostProcessing(options, result, config) {
5033
5034
  });
5034
5035
  }
5035
5036
  }
5037
+ async function ensureStatusLineConfig(targetDir) {
5038
+ const layout = getProviderLayout();
5039
+ const settingsPath = join8(targetDir, layout.rootDir, "settings.local.json");
5040
+ const statusLineConfig = {
5041
+ type: "command",
5042
+ command: `${layout.rootDir}/statusline.sh`,
5043
+ padding: 0,
5044
+ refreshInterval: 10
5045
+ };
5046
+ if (!await fileExists(settingsPath)) {
5047
+ await ensureDirectory(join8(settingsPath, ".."));
5048
+ await writeJsonFile(settingsPath, { statusLine: statusLineConfig });
5049
+ return;
5050
+ }
5051
+ const settings = await readJsonFile(settingsPath);
5052
+ const statusLine = settings.statusLine;
5053
+ if (!statusLine || typeof statusLine !== "object" || Array.isArray(statusLine)) {
5054
+ settings.statusLine = statusLineConfig;
5055
+ await writeJsonFile(settingsPath, settings);
5056
+ return;
5057
+ }
5058
+ const mergedStatusLine = statusLine;
5059
+ if (mergedStatusLine.refreshInterval === undefined) {
5060
+ mergedStatusLine.refreshInterval = statusLineConfig.refreshInterval;
5061
+ settings.statusLine = mergedStatusLine;
5062
+ await writeJsonFile(settingsPath, settings);
5063
+ }
5064
+ }
5036
5065
  function compareSemver(a, b) {
5037
5066
  const pa = a.split(".").map(Number);
5038
5067
  const pb = b.split(".").map(Number);
@@ -5104,6 +5133,15 @@ function checkAndInstallOmxAfterUpdate() {
5104
5133
  }
5105
5134
  }
5106
5135
  }
5136
+ async function handleNoUpdateResult(options, result) {
5137
+ const isFullUpdate = !options.components || options.components.length === 0;
5138
+ if (isFullUpdate && !options.dryRun) {
5139
+ await ensureStatusLineConfig(options.targetDir);
5140
+ }
5141
+ info("update.no_updates");
5142
+ result.success = true;
5143
+ result.skippedComponents = options.components || getAllUpdateComponents();
5144
+ }
5107
5145
  async function update(options) {
5108
5146
  const result = createUpdateResult();
5109
5147
  try {
@@ -5122,9 +5160,7 @@ async function update(options) {
5122
5160
  const updateCheck = await checkForUpdates(options.targetDir);
5123
5161
  result.newVersion = updateCheck.latestVersion;
5124
5162
  if (!updateCheck.hasUpdates && !options.force) {
5125
- info("update.no_updates");
5126
- result.success = true;
5127
- result.skippedComponents = options.components || getAllUpdateComponents();
5163
+ await handleNoUpdateResult(options, result);
5128
5164
  return result;
5129
5165
  }
5130
5166
  await handleBackupIfRequested(options.targetDir, !!options.backup, result);
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "workspaces": [
4
4
  "packages/*"
5
5
  ],
6
- "version": "0.4.15",
6
+ "version": "0.5.0",
7
7
  "requiresCC": ">=2.1.121",
8
8
  "claudeCode": {
9
9
  "minimumVersion": "2.1.121",
@@ -46,8 +46,12 @@ Types: feat, fix, docs, style, refactor, test, chore
46
46
 
47
47
  - NEVER force push to main/master
48
48
  - NEVER reset --hard without confirmation
49
+ - NEVER run `git clean -fd`, broad `git restore`, or `git checkout -- .` without preserving diffs and confirming the exact scope
50
+ - NEVER delete branches with `git branch -D` until merge state and remote backup are checked
49
51
  - NEVER skip pre-commit hooks without reason
50
52
  - ALWAYS create new commits (avoid --amend unless requested)
53
+ - BEFORE release branch creation, check for a local `release` branch that blocks the `release/v*` namespace; rename or remove it only after proving it is merged/backed up
54
+ - AFTER unexpected destructive git output, inspect `git reflog`, `git status`, and `git diff` before any repair attempt
51
55
 
52
56
  ## Push Rules (R016)
53
57
 
@@ -29,10 +29,11 @@ You are an automated verification specialist that executes the mandatory R017 ve
29
29
  5. Verify reference integrity (frontmatter, memory fields, skill refs)
30
30
  6. Verify philosophy compliance (R006-R011)
31
31
  7. Verify Claude-native compatibility
32
- 8. Spec density analysis: detects agents with excessive inline implementation detail (R006 compliance)
33
- 9. Structural linting: routing coverage (unreachable agents), orphan skill detection, circular dependency check, context:fork cap verification, R006 fork-list/frontmatter cross-validation
34
- 10. Auto-fix simple issues (count mismatches, missing fields)
35
- 11. Generate verification report
32
+ 8. Verify working-tree preservation: no verification step may reset, clean, restore, or delete branch state without explicit approval and recovery evidence
33
+ 9. Spec density analysis: detects agents with excessive inline implementation detail (R006 compliance)
34
+ 10. Structural linting: routing coverage (unreachable agents), orphan skill detection, circular dependency check, context:fork cap verification, R006 fork-list/frontmatter cross-validation
35
+ 11. Auto-fix simple issues (count mismatches, missing fields)
36
+ 12. Generate verification report
36
37
 
37
38
  ## Commands
38
39
 
@@ -42,6 +42,16 @@
42
42
  ],
43
43
  "description": "Pause before git push to review changes"
44
44
  },
45
+ {
46
+ "matcher": "tool == \"Bash\" && tool_input.command matches \"git (reset --hard|clean -f|clean -d|restore|checkout --|branch -D|push --force|push -f)\"",
47
+ "hooks": [
48
+ {
49
+ "type": "command",
50
+ "command": "bash .codex/hooks/scripts/destructive-git-guard.sh"
51
+ }
52
+ ],
53
+ "description": "Warn on destructive git commands and print recovery guidance without blocking"
54
+ },
45
55
  {
46
56
  "matcher": "tool == \"Write\" && tool_input.file_path matches \"\\\\.(md|txt)$\" && !(tool_input.file_path matches \"README\\\\.md|CLAUDE\\\\.md|AGENT\\\\.md|SKILL\\\\.md\")",
47
57
  "hooks": [
@@ -438,6 +448,7 @@
438
448
  "command": "bash .codex/hooks/scripts/context-budget-advisor.sh"
439
449
  }
440
450
  ],
451
+ "continueOnBlock": true,
441
452
  "description": "Context budget advisor — track tool usage patterns and advise ecomode activation"
442
453
  },
443
454
  {
@@ -448,6 +459,7 @@
448
459
  "command": "bash .codex/hooks/scripts/stuck-detector.sh"
449
460
  }
450
461
  ],
462
+ "continueOnBlock": true,
451
463
  "description": "Detect repetitive failure loops and advise recovery strategies"
452
464
  },
453
465
  {
@@ -458,6 +470,7 @@
458
470
  "command": "bash .codex/hooks/scripts/cost-cap-advisor.sh"
459
471
  }
460
472
  ],
473
+ "continueOnBlock": true,
461
474
  "description": "Advisory cost cap monitoring — warn when session cost approaches configurable limit"
462
475
  },
463
476
  {
@@ -8,13 +8,14 @@ command -v jq >/dev/null 2>&1 || exit 0
8
8
  # Context Budget Advisor Hook
9
9
  # Trigger: PostToolUse (Edit/Write/Agent/Task/Read/Glob/Grep/Bash)
10
10
  # Purpose: Monitor context usage and advise ecomode activation based on task type
11
- # Protocol: stdin JSON -> stdout pass-through, exit 0 always
11
+ # Protocol: stdin JSON -> stdout pass-through; exit 2 only for continueOnBlock signals
12
12
 
13
13
  input=$(cat)
14
14
 
15
15
  # Read context info from status file if available
16
- STATUS_FILE="/tmp/.codex-env-status-${PPID}"
16
+ COST_FILE="/tmp/.codex-cost-${PPID}"
17
17
  BUDGET_FILE="/tmp/.codex-context-budget-${PPID}"
18
+ SIGNAL_FILE="/tmp/.codex-context-budget-signal-${PPID}"
18
19
 
19
20
  # Initialize budget tracking file
20
21
  if [ ! -f "$BUDGET_FILE" ]; then
@@ -77,6 +78,43 @@ case "$task_type" in
77
78
  *) THRESHOLD=80 ;;
78
79
  esac
79
80
 
81
+ # Use statusline bridge data when available. Exiting 2 with continueOnBlock=true
82
+ # turns a high-context advisory into model-visible feedback without halting.
83
+ ctx_pct="0"
84
+ ctx_timestamp="0"
85
+ if [ -f "$COST_FILE" ]; then
86
+ IFS=$'\t' read -r _cost_usd ctx_pct ctx_timestamp _rl_5h _rl_7d _rl_5h_resets _rl_7d_resets < "$COST_FILE" 2>/dev/null || true
87
+ fi
88
+
89
+ ctx_int="${ctx_pct%%.*}"
90
+ case "$ctx_int" in
91
+ ''|*[!0-9]*) ctx_int=0 ;;
92
+ esac
93
+ case "$ctx_timestamp" in
94
+ ''|*[!0-9]*) ctx_timestamp=0 ;;
95
+ esac
96
+
97
+ now=$(date +%s)
98
+ age=$((now - ${ctx_timestamp:-0}))
99
+ signal_key="${task_type}:${THRESHOLD}"
100
+ last_signal=""
101
+ if [ -f "$SIGNAL_FILE" ]; then
102
+ last_signal=$(cat "$SIGNAL_FILE" 2>/dev/null || echo "")
103
+ fi
104
+
105
+ if [ "$age" -le 60 ] && [ "$ctx_int" -ge "$THRESHOLD" ] && [ "$last_signal" != "$signal_key" ]; then
106
+ echo "[Context Budget] ${ctx_int}% context used meets ${task_type} threshold ${THRESHOLD}%" >&2
107
+ echo "[Context Budget] Switch to ecomode, compact, or narrow the remaining task before continuing." >&2
108
+ echo "$signal_key" > "$SIGNAL_FILE"
109
+ echo "$input"
110
+ HOOK_END=$(date +%s%N 2>/dev/null || echo 0)
111
+ if [ "$HOOK_START" != "0" ] && [ "$HOOK_END" != "0" ]; then
112
+ HOOK_MS=$(( (HOOK_END - HOOK_START) / 1000000 ))
113
+ echo "[Hook Perf] $(basename "$0"): ${HOOK_MS}ms" >> "/tmp/.codex-hook-perf-${PPID}.log"
114
+ fi
115
+ exit 2
116
+ fi
117
+
80
118
  # Emit advisory at milestones (every 25 tool calls)
81
119
  if [ "$tool_count" -gt 0 ] && [ $((tool_count % 25)) -eq 0 ]; then
82
120
  echo "[Context Budget] Task: ${task_type} | Threshold: ${THRESHOLD}% | Tools used: ${tool_count}" >&2
@@ -2,7 +2,7 @@
2
2
  # cost-cap-advisor.sh — Advisory hook for session cost monitoring
3
3
  # Trigger: PostToolUse (Agent/Task)
4
4
  # Purpose: Warn when session cost approaches configurable cap
5
- # Protocol: stdin JSON -> stdout pass-through, exit 0 always (advisory only, R010)
5
+ # Protocol: stdin JSON -> stdout pass-through; exit 2 only for continueOnBlock wrap-up signals
6
6
 
7
7
  input=$(cat)
8
8
 
@@ -30,10 +30,13 @@ if ! printf '%f' "$cost_usd" >/dev/null 2>&1; then
30
30
  echo "$input"
31
31
  exit 0
32
32
  fi
33
+ if ! printf '%f' "$COST_CAP" >/dev/null 2>&1; then
34
+ echo "$input"
35
+ exit 0
36
+ fi
33
37
 
34
38
  # Calculate percentage of cap used
35
- # Use bc for float arithmetic
36
- cost_pct=$(echo "scale=0; $cost_usd * 100 / $COST_CAP" | bc 2>/dev/null || echo "0")
39
+ cost_pct=$(awk -v cost="$cost_usd" -v cap="$COST_CAP" 'BEGIN { if (cap <= 0) print 0; else printf "%d", (cost * 100 / cap) }' 2>/dev/null || echo "0")
37
40
 
38
41
  # Staleness check — skip if data is older than 60 seconds
39
42
  now=$(date +%s)
@@ -54,6 +57,8 @@ if [ "$cost_pct" -ge 100 ] && [ "$last_level" != "100" ]; then
54
57
  echo "[Cost Cap] Session cost \$${cost_usd} has reached cap \$${COST_CAP} (${cost_pct}%)" >&2
55
58
  echo "[Cost Cap] Consider wrapping up or increasing CLAUDE_COST_CAP" >&2
56
59
  echo "100" > "$ADVISORY_FILE"
60
+ echo "$input"
61
+ exit 2
57
62
  elif [ "$cost_pct" -ge 90 ] && [ "$last_level" != "90" ] && [ "$last_level" != "100" ]; then
58
63
  echo "[Cost Cap] Session cost \$${cost_usd} at 90% of cap \$${COST_CAP}" >&2
59
64
  echo "[Cost Cap] Ecomode recommended — consider /compact" >&2
@@ -0,0 +1,53 @@
1
+ #!/bin/bash
2
+ # Advisory guard for destructive git commands.
3
+ # Warns before commands that can discard worktree or branch state.
4
+ # This hook is advisory only: it prints warnings to stderr, records a
5
+ # PPID-scoped event, echoes the original hook input, and exits 0.
6
+
7
+ input=$(cat)
8
+ cmd=""
9
+
10
+ if command -v jq >/dev/null 2>&1; then
11
+ cmd=$(echo "$input" | jq -r '.tool_input.command // ""' 2>/dev/null)
12
+ elif command -v node >/dev/null 2>&1; then
13
+ cmd=$(
14
+ printf '%s' "$input" | node -e 'let s = ""; process.stdin.on("data", d => s += d); process.stdin.on("end", () => { try { const j = JSON.parse(s); process.stdout.write(j?.tool_input?.command || ""); } catch { process.exit(0); } });' 2>/dev/null
15
+ )
16
+ fi
17
+
18
+ warn() {
19
+ local pattern="$1"
20
+ local command="$2"
21
+ local violation_file="/tmp/.codex-destructive-git-violations-${PPID}"
22
+
23
+ echo "[Hook] WARNING: destructive git command detected: ${pattern}" >&2
24
+ echo "[Hook] Command: ${command}" >&2
25
+ echo "[Hook] Verify target, preserve important work, and get explicit approval before continuing." >&2
26
+ echo "[Hook] Recovery: inspect 'git status', 'git diff', and 'git reflog' before attempting repair." >&2
27
+
28
+ printf '%s\t%s\t%s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$pattern" "$command" >> "$violation_file"
29
+ }
30
+
31
+ if [ -n "$cmd" ]; then
32
+ case "$cmd" in
33
+ *"git reset --hard"*)
34
+ warn "git reset --hard" "$cmd"
35
+ ;;
36
+ *"git clean -fd"*|*"git clean -df"*|*"git clean -fxd"*|*"git clean -xdf"*)
37
+ warn "git clean -fd/-fdx" "$cmd"
38
+ ;;
39
+ *"git restore"*|*"git checkout -- ."*|*"git checkout -- *"*)
40
+ warn "git restore / git checkout --" "$cmd"
41
+ ;;
42
+ *"git branch -D"*)
43
+ warn "git branch -D" "$cmd"
44
+ echo "[Hook] Check whether the branch is merged before deleting it." >&2
45
+ ;;
46
+ *"git push --force"*|*"git push -f"*)
47
+ warn "git push --force" "$cmd"
48
+ ;;
49
+ esac
50
+ fi
51
+
52
+ echo "$input"
53
+ exit 0
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bash
2
- # SessionStart auto-update hook — interactive omcodex update check
2
+ # SessionStart auto-update hook — interactive omcustomcodex update check
3
3
  # Trigger: SessionStart (runs BEFORE session-env-check.sh)
4
4
  # Purpose: Check for oh-my-customcodex updates, prompt user, optionally update
5
5
  # Protocol: stdin JSON -> stdout pass-through, exit 0 ALWAYS
@@ -135,17 +135,17 @@ if read -r -t "$INPUT_TIMEOUT" answer </dev/tty 2>/dev/null; then
135
135
  echo " ✓ Updated to v${LATEST_VERSION}" >&2
136
136
 
137
137
  # Check if project harness should be updated too
138
- if [ -f ".omcustomrc.json" ]; then
138
+ if [ -f ".omcodexrc.json" ] || [ -f ".omcustomrc.json" ]; then
139
139
  printf " Update project harness too? [y/N] " >/dev/tty 2>/dev/null
140
140
  if read -r -t "$INPUT_TIMEOUT" harness_answer </dev/tty 2>/dev/null; then
141
141
  case "$harness_answer" in
142
142
  [yY]|[yY][eE][sS])
143
143
  echo " Updating project harness..." >&2
144
- if command -v omcustom >/dev/null 2>&1; then
145
- omcustom update --force >&2 2>&1 || echo " ⚠ Harness update failed (non-blocking)" >&2
144
+ if command -v omcustomcodex >/dev/null 2>&1; then
145
+ omcustomcodex update --force >&2 2>&1 || echo " ⚠ Harness update failed (non-blocking)" >&2
146
146
  echo " ✓ Project harness updated" >&2
147
147
  else
148
- echo " ⚠ omcustom command not found after install" >&2
148
+ echo " ⚠ omcustomcodex command not found after install" >&2
149
149
  fi
150
150
  ;;
151
151
  *)
@@ -126,8 +126,10 @@ OMCUSTOM_UPDATE_STATUS="unknown"
126
126
  INSTALLED_VERSION=""
127
127
  CACHED_LATEST=""
128
128
 
129
- # Read installed version from .omcustomrc.json
130
- if [ -f ".omcustomrc.json" ]; then
129
+ # Read installed version from the Codex config, falling back to the legacy parent config.
130
+ if [ -f ".omcodexrc.json" ]; then
131
+ INSTALLED_VERSION=$(grep -o '"version"[[:space:]]*:[[:space:]]*"[^"]*"' .omcodexrc.json 2>/dev/null | head -1 | grep -o '"[^"]*"$' | tr -d '"')
132
+ elif [ -f ".omcustomrc.json" ]; then
131
133
  INSTALLED_VERSION=$(grep -o '"version"[[:space:]]*:[[:space:]]*"[^"]*"' .omcustomrc.json 2>/dev/null | head -1 | grep -o '"[^"]*"$' | tr -d '"')
132
134
  fi
133
135
 
@@ -222,8 +224,8 @@ case "$DRIFT_STATUS" in
222
224
  esac
223
225
  echo "" >&2
224
226
  echo " [Lockfile Drift]" >&2
225
- echo " Note: file-level lockfile drift (template hash changes) is checked via 'omcodex doctor'" >&2
226
- echo " Run 'omcodex doctor' to detect modified/removed template files since install." >&2
227
+ echo " Note: file-level lockfile drift (template hash changes) is checked via 'omcustomcodex doctor'" >&2
228
+ echo " Run 'omcustomcodex doctor' to detect modified/removed template files since install." >&2
227
229
  echo "------------------------------------" >&2
228
230
 
229
231
  # SessionEnd hooks timeout (v2.1.74+)
@@ -238,12 +240,12 @@ echo " [Update Check]" >&2
238
240
  if [ -n "$INSTALLED_VERSION" ] && [ -n "$CACHED_LATEST" ]; then
239
241
  if [ "$OMCUSTOM_UPDATE_STATUS" = "available" ]; then
240
242
  echo " ⚡ oh-my-customcodex v${CACHED_LATEST} available (current: v${INSTALLED_VERSION})" >&2
241
- echo " Run 'omcodex update' to apply" >&2
243
+ echo " Run 'omcustomcodex update' to apply" >&2
242
244
  else
243
245
  echo " ✓ oh-my-customcodex is up to date (v${INSTALLED_VERSION})" >&2
244
246
  fi
245
247
  elif [ -n "$INSTALLED_VERSION" ]; then
246
- echo " ℹ oh-my-customcodex v${INSTALLED_VERSION} (run 'omcodex doctor --updates' to check for updates)" >&2
248
+ echo " ℹ oh-my-customcodex v${INSTALLED_VERSION} (run 'omcustomcodex doctor --updates' to check for updates)" >&2
247
249
  else
248
250
  echo " ℹ oh-my-customcodex not detected in this project" >&2
249
251
  fi
@@ -10,7 +10,7 @@ command -v jq >/dev/null 2>&1 || exit 0
10
10
  # Purpose: Detect repetitive failure loops and advise recovery
11
11
  # Protocol: stdin JSON -> process -> stdout pass-through
12
12
  # - exit 0: advisory (normal cases, < HARD_BLOCK_THRESHOLD repetitions)
13
- # - exit 1: hard block (extreme stuck loops, >= HARD_BLOCK_THRESHOLD repetitions)
13
+ # - exit 2: conversation block (extreme stuck loops, >= HARD_BLOCK_THRESHOLD repetitions)
14
14
 
15
15
  # Hard block threshold: consecutive identical operations before blocking
16
16
  HARD_BLOCK_THRESHOLD=${CLAUDE_STUCK_THRESHOLD:-3}
@@ -186,7 +186,7 @@ if [ "$hard_block" = true ]; then
186
186
  HOOK_MS=$(( (HOOK_END - HOOK_START) / 1000000 ))
187
187
  echo "[Hook Perf] $(basename "$0"): ${HOOK_MS}ms" >> "/tmp/.codex-hook-perf-${PPID}.log"
188
188
  fi
189
- exit 1
189
+ exit 2
190
190
  fi
191
191
 
192
192
  # Pass through
@@ -46,7 +46,7 @@ classes:
46
46
  description: "System information and utilities"
47
47
 
48
48
  GoalWorkflowSkill:
49
- skills: [goal]
49
+ skills: ["omcustomcodex:goal"]
50
50
  description: "Goal-to-execution workflow coordination"
51
51
 
52
52
  VerificationSkill:
@@ -178,14 +178,14 @@ skills:
178
178
  keywords: [review, code-review, best-practices, quality]
179
179
  rule_references: []
180
180
 
181
- goal:
181
+ "omcustomcodex:goal":
182
182
  class: GoalWorkflowSkill
183
183
  description: "Goal-to-execution workflow for disciplined Codex + OMX task completion"
184
184
  user_invocable: true
185
185
  model_invocable: true
186
186
  scope: core
187
187
  summary: "Keep a concrete objective visible through clarification, planning, execution, verification, and completion reporting"
188
- keywords: [goal, objective, planning, execution, verification, completion]
188
+ keywords: [goal, omcustomcodex-goal, objective, planning, execution, verification, completion]
189
189
  rule_references: [R020]
190
190
 
191
191
  docker-best-practices:
@@ -72,6 +72,7 @@ disableSkillShellExecution: true # Disable inline shell execution in skills (v2
72
72
  <!-- DETAIL: CC Version Compatibility History
73
73
  `isolation`, `background`, `maxTurns`, `maxTokens`, `mcpServers`, `hooks`, `permissionMode`, `disallowedTools`, `limitations` are supported in Claude Code v2.1.63+. Hook types `PostCompact`, `Elicitation`, `ElicitationResult` require v2.1.76+. `CwdChanged`, `FileChanged` hook events and `managed-settings.d/` drop-in directory require v2.1.83+. Conditional `if` field for hooks requires v2.1.85+. `PermissionDenied` hook event requires v2.1.88+. `refreshInterval` setting for status line auto-refresh interval added in v2.1.97+. Monitor tool and subprocess sandboxing (`CLAUDE_CODE_SUBPROCESS_ENV_SCRUB`, `CLAUDE_CODE_SCRIPT_CAPS`) added in v2.1.98+. Settings resilience (unrecognized hook event names no longer cause settings.json to be ignored) improved in v2.1.101+. PreCompact hook block support (exit 2 / `{"decision":"block"}`) added in v2.1.105+. Skill description listing cap raised from 250 to 1,536 characters in v2.1.105+. Plugin `monitors` manifest key for background monitors added in v2.1.105+. `ENABLE_PROMPT_CACHING_1H` and `FORCE_PROMPT_CACHING_5M` env vars for prompt cache TTL control added in v2.1.108+. Skill tool can now discover and invoke built-in slash commands (`/init`, `/review`, `/security-review`) in v2.1.108+. `/recap` session context feature and `/undo` alias for `/rewind` added in v2.1.108+. `/tui` command and `tui` setting for fullscreen rendering added in v2.1.110+. PushNotification tool for mobile push notifications (Remote Control + config required) added in v2.1.110+. `autoScrollEnabled` config for fullscreen mode added in v2.1.110+. SDK/headless `TRACEPARENT`/`TRACESTATE` distributed trace linking added in v2.1.110+. Bash tool maximum timeout enforcement added in v2.1.110+. Write tool IDE diff feedback (informs model when user edits proposed content) added in v2.1.110+. `--resume`/`--continue` now resurrects unexpired scheduled tasks in v2.1.110+. `/focus` command (separated from Ctrl+O) added in v2.1.110+. `xhigh` effort level for Opus 4.7 (between `high` and `max`; other models fall back to `high`) added in v2.1.111+. `/effort` interactive slider with arrow-key navigation (when called without arguments) added in v2.1.111+. Auto mode no longer requires `--enable-auto-mode` in v2.1.111+. PowerShell tool progressive rollout (`CLAUDE_CODE_USE_POWERSHELL_TOOL` env var) added in v2.1.111+. Read-only bash commands with glob patterns (`ls *.ts`) and `cd <project-dir> &&` prefix no longer trigger permission prompt in v2.1.111+. `/less-permission-prompts` built-in skill for permission allowlist scanning added in v2.1.111+. `/ultrareview` parallel multi-agent cloud code review added in v2.1.111+. `/skills` menu sorting by estimated token count (press `t`) added in v2.1.111+. `OTEL_LOG_RAW_API_BODIES` env var for full API request/response body logging added in v2.1.111+. Plan files named after prompt content (not random words) in v2.1.111+. Plugin error handling improvements (dependency conflict errors, stale version recovery, install recovery) in v2.1.111+.
74
74
  `sandbox.network.deniedDomains` setting for domain blocking within `allowedDomains` wildcards added in v2.1.113+. Subagent mid-stream stall detection with auto-fail after 10 minutes added in v2.1.113+. Bash `find -exec`/`-delete` no longer auto-approved under `Bash(find:*)` allow rules in v2.1.113+. Bash deny rules now match exec wrappers (`env`/`sudo`/`watch`/`ionice`/`setsid`) in v2.1.113+. Native binary spawning (per-platform optional dependency) replaces bundled JavaScript in v2.1.113+. `/loop` Esc now cancels pending wakeups in v2.1.113+.
75
+ Agent frontmatter `hooks:` fire when the agent runs as a main-thread agent via `--agent` flag in v2.1.116+. Hook JSON output `terminalSequence` field for desktop notifications, window title changes, and terminal bells without controlling terminal added in v2.1.141+. `claude agents --cwd <path>` for directory-scoped session lists added in v2.1.141+. Background agents launched via `/bg` preserve current permission mode in v2.1.141+. `CLAUDE_CODE_PLUGIN_PREFER_HTTPS` and `ANTHROPIC_WORKSPACE_ID` environment variables added in v2.1.141+ for HTTPS plugin clones and workspace-scoped federation.
75
76
  -->
76
77
 
77
78
  ## Hook Event Types