refacil-sdd-ai 5.1.1 → 5.2.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.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  **SDD-AI** (Specification-Driven Development with AI) packaged as a CLI.
4
4
 
5
- Installs **skills** and **sub-agents** for **Claude Code**, **Cursor**, and **OpenCode** that guide the developer through a structured AI-assisted development workflow, using **`refacil-sdd/`** as the specification store, plus a **local bus** so agents across different repos can communicate with each other.
5
+ Installs **skills** and **sub-agents** for **Claude Code**, **Cursor**, **OpenCode**, and **Codex** that guide the developer through a structured AI-assisted development workflow, using **`refacil-sdd/`** as the specification store, plus a **local bus** so agents across different repos can communicate with each other.
6
6
 
7
7
  ---
8
8
 
@@ -11,9 +11,9 @@ Installs **skills** and **sub-agents** for **Claude Code**, **Cursor**, and **Op
11
11
  ## Requirements
12
12
 
13
13
  - **Node.js >= 20.0.0**
14
- - One or more supported IDEs: **Claude Code >= 2.1.89**, **Cursor**, or **OpenCode**
14
+ - One or more supported IDEs: **Claude Code >= 2.1.89**, **Cursor**, **OpenCode**, or **Codex**
15
15
 
16
- `refacil-sdd-ai init` checks the Claude Code version and warns if it is below 2.1.89. With an older version the rest of the methodology works, but `compact-bash` will have no effect (Claude Code only — OpenCode and Cursor have their own hook delivery mechanisms).
16
+ `refacil-sdd-ai init` checks the Claude Code version and warns if it is below 2.1.89. With an older version the rest of the methodology works, but `compact-bash` will have no effect (Claude Code only — Cursor, OpenCode, and Codex have their own hook delivery mechanisms).
17
17
 
18
18
  ---
19
19
 
@@ -33,8 +33,8 @@ refacil-sdd-ai init
33
33
 
34
34
  `init` installs skills, sub-agents, and hooks into your IDE's **global user directories** (`~/.claude/`, `~/.cursor/`, `~/.config/opencode/`). Skills are available in all your repos from this point — no need to re-run `init` when you open a new repo.
35
35
 
36
- - Interactive IDE selector (Claude Code / Cursor / OpenCode) — pre-selects installed IDEs.
37
- Use `--all` to install for all three without prompting.
36
+ - Interactive IDE selector (Claude Code / Cursor / OpenCode / Codex) — pre-selects installed IDEs.
37
+ Use `--all` to install for all four without prompting.
38
38
  - Your IDE selection is saved to `~/.refacil-sdd-ai/selected-ides.json` and reused on every `update`.
39
39
  - Also prompts for global branch config (`baseBranch`, `protectedBranches`, `artifactLanguage`)
40
40
  stored in `~/.refacil-sdd-ai/config.yaml`. Skip with `--yes` or `--defaults`.
@@ -190,7 +190,7 @@ refacil-sdd-ai sdd config --json
190
190
 
191
191
  ## Available IDE Skills
192
192
 
193
- All invoked as `/refacil:<name>` in Claude Code, Cursor, or OpenCode.
193
+ All invoked as `/refacil:<name>` in Claude Code, Cursor, OpenCode, or Codex.
194
194
 
195
195
  ### SDD cycle
196
196
 
@@ -227,7 +227,7 @@ Some skills delegate their heavy work to **sub-agents** that run in isolated con
227
227
 
228
228
  **Model**: `refacil-proposer` runs with `model: opusplan` (uses Opus during plan mode for highest-stakes planning, then switches to Sonnet for execution). Other sub-agents use `model: sonnet` by default for Claude Code, others use inherit model.
229
229
 
230
- **Triple-platform**: `.claude/agents/refacil-*.md` uses `tools:` (granular allowlist). `.cursor/agents/refacil-*.md` is auto-generated: `readonly: true` for agents without `Edit`/`Write`, `readonly: false` for those that have them; always `model: inherit`. `.opencode/agents/refacil-*.md` is auto-generated via `transformFrontmatterForOpenCode()`: converts `tools:` to a `permission:` block (`edit: allow/deny`, `bash: allow/deny`, `webfetch: deny`), adds `mode: subagent`, adds `hidden: true` for internal agents, and removes `model:`. The installer transforms the frontmatter automatically for all three IDEs.
230
+ **Multi-platform**: `.claude/agents/refacil-*.md` uses `tools:` (granular allowlist). `.cursor/agents/refacil-*.md` is auto-generated: `readonly: true` for agents without `Edit`/`Write`, `readonly: false` for those that have them; always `model: inherit`. `.opencode/agents/refacil-*.md` is auto-generated via `transformFrontmatterForOpenCode()`: converts `tools:` to a `permission:` block (`edit: allow/deny`, `bash: allow/deny`, `webfetch: deny`), adds `mode: subagent`, adds `hidden: true` for internal agents, and removes `model:`. `.codex/agents/refacil-*.toml` is auto-generated via `convertAgentToToml()`: extracts `name` and `description` from the YAML frontmatter and places the Markdown body in `developer_instructions = """..."""`. The installer transforms the frontmatter automatically for all four IDEs.
231
231
 
232
232
  **Two-pass `refacil:bug` flow**: the wrapper first invokes the sub-agent in `investigation` mode (writes nothing) → the user confirms the hypothesis and approves the fix → the wrapper validates the working branch → invokes the sub-agent in `fix` mode to implement.
233
233
 
@@ -316,14 +316,14 @@ From there, the full cycle is:
316
316
 
317
317
  ## Automatic Hooks
318
318
 
319
- Installed during `init` / `update` for each selected IDE. The same four behaviors are active in Claude Code, Cursor, and OpenCode — each through its own delivery mechanism.
319
+ Installed during `init` / `update` for each selected IDE. The same four behaviors are active in Claude Code, Cursor, OpenCode, and Codex — each through its own delivery mechanism.
320
320
 
321
- | Behavior | Claude Code | Cursor | OpenCode |
322
- |---|---|---|---|
323
- | **check-update** | `SessionStart` hook in `~/.claude/settings.json` | `SessionStart` hook in `~/.cursor/hooks.json` | `session.created` handler in the global OpenCode plugin |
324
- | **notify-update** | `UserPromptSubmit` hook | `beforeSubmitPrompt` hook | `tui.prompt.append` handler |
325
- | **compact-bash** | `PreToolUse` (Bash) hook | `PreToolUse` (Bash) hook | `tool.execute.before` handler for bash tool |
326
- | **check-review** | `PreToolUse` (Bash) hook | `PreToolUse` (Bash) hook | `tool.execute.before` handler for bash tool |
321
+ | Behavior | Claude Code | Cursor | OpenCode | Codex |
322
+ |---|---|---|---|---|
323
+ | **check-update** | `SessionStart` hook in `~/.claude/settings.json` | `SessionStart` hook in `~/.cursor/hooks.json` | `session.created` handler in the global OpenCode plugin | `sessionStart` hook in `~/.codex/config.toml` |
324
+ | **notify-update** | `UserPromptSubmit` hook | `beforeSubmitPrompt` hook | `tui.prompt.append` handler | `userPromptSubmit` hook in `~/.codex/config.toml` |
325
+ | **compact-bash** | `PreToolUse` (Bash) hook | `PreToolUse` (Bash) hook | `tool.execute.before` handler for bash tool | `preToolUse` hook (Bash matcher) in `~/.codex/config.toml` |
326
+ | **check-review** | `PreToolUse` (Bash) hook | `PreToolUse` (Bash) hook | `tool.execute.before` handler for bash tool | `preToolUse` hook (Bash matcher) in `~/.codex/config.toml` |
327
327
 
328
328
  | Behavior | What it does |
329
329
  |---|---|
@@ -334,6 +334,8 @@ Installed during `init` / `update` for each selected IDE. The same four behavior
334
334
 
335
335
  > **OpenCode plugin**: a single file installed in the global OpenCode plugins directory implements all four behaviors. It loads `lib/compact/rules.js` from the package to reuse the same rewrite rules — no duplicated logic. If the rules file is not resolvable, compact-bash is disabled gracefully with a warning to stderr; the plugin never crashes the session.
336
336
 
337
+ > **Codex hooks**: injected into `~/.codex/config.toml` under `[hooks]` with `[features] codex_hooks = true`. Each SDD-AI hook entry carries a boolean marker (`_sdd`, `_sdd_compact`, `_sdd_review`, `_sdd_notify`) for clean removal on `clean`. User-defined hooks outside these entries are preserved.
338
+
337
339
  > **Why two hooks for updates?** `SessionStart` does the silent sync when opening the session without user interaction. `notify-update` on `UserPromptSubmit` / `beforeSubmitPrompt` injects the instruction just before the agent processes the next user message, ensuring it is not ignored.
338
340
 
339
341
  ### Review gate on push
@@ -493,6 +495,11 @@ Skills, sub-agents, and hooks are installed into the user's global IDE directori
493
495
  ~/.config/opencode/agents/refacil-*.md # OpenCode sub-agents (permission block + mode:subagent)
494
496
  ~/.config/opencode/plugins/refacil-hooks.js # Plugin: session.created + tui.prompt.append + tool.execute.before
495
497
 
498
+ # Codex (if selected)
499
+ ~/.codex/skills/refacil-*/ # Codex skills (same content as Claude Code)
500
+ ~/.codex/agents/refacil-*.toml # Codex sub-agents (TOML: name + description + developer_instructions)
501
+ ~/.codex/config.toml # SDD hooks merged in under [hooks] with [features] codex_hooks = true
502
+
496
503
  # refacil-sdd-ai state
497
504
  ~/.refacil-sdd-ai/
498
505
  selected-ides.json # IDE selection saved on init, reused by update
@@ -532,6 +539,7 @@ refacil-sdd/ # SDD artifacts store
532
539
  - [Claude Code](https://claude.ai/code) — Anthropic CLI
533
540
  - [Cursor](https://cursor.sh) — AI IDE
534
541
  - [OpenCode](https://opencode.ai) — open-source AI development agent
542
+ - [Codex](https://github.com/openai/codex) — OpenAI CLI agent
535
543
 
536
544
  ## License
537
545
 
@@ -11,7 +11,7 @@ You are a debugging agent operating in two modes. In investigation mode you rece
11
11
 
12
12
  Reject weak hypotheses. If the evidence does not support a root cause, say so. Do not propose a fix until the cause is clear.
13
13
 
14
- **Prerequisites**: `agents` profile from `refacil-prereqs/SKILL.md` + rules from `METHODOLOGY-CONTRACT.md`.
14
+ **Prerequisites**: `agents` profile from `refacil-prereqs/SKILL.md` + rules from **`METHODOLOGY-CONTRACT.md` (§3, §3.1 — verification defaults to scoped in fix mode)**.
15
15
 
16
16
  ## Guardrail: direct invocation detection
17
17
 
@@ -29,6 +29,7 @@ If you prefer to continue here, provide:
29
29
  - mode: investigation (only analyze and propose hypotheses) or fix (implement with already-confirmed hypothesis)
30
30
  - description: <full bug description>
31
31
  - hypothesis: <confirmed root cause> (only for mode=fix)
32
+ - testScope: scoped \| full (only for mode=fix; default scoped)
32
33
  ```
33
34
 
34
35
  **Do not proceed with reads or implementation until the scope is clear.**
@@ -124,7 +125,7 @@ Proposed fix for hypothesis #1:
124
125
 
125
126
  ## Fix mode
126
127
 
127
- The main agent passes you: `mode: fix` + `description` + `hypothesis` (root cause confirmed by the user).
128
+ The main agent passes you: `mode: fix` + `description` + `hypothesis` (root cause confirmed by the user) + optional **`testScope`** (`scoped` \| `full`, default **`scoped`**).
128
129
 
129
130
  ### Step 1: Implement the fix
130
131
 
@@ -139,7 +140,7 @@ Detect the project's testing stack and framework: read `METHODOLOGY-CONTRACT.md
139
140
  Generate tests that:
140
141
  1. **Reproduce the bug**: a test that fails WITHOUT the fix (verifies the test is valid).
141
142
  2. **Verify the fix**: the same test passes WITH the fix.
142
- 3. **Verify no regression**: normal flow tests still pass.
143
+ 3. **Guardrails**: extend with normal/control-path assertions when they fit the bug surface (Step 4 **scoped** run targets those files/packages — **not** the entire repo suite).
143
144
 
144
145
  Each test must cover:
145
146
  - `should [correct behavior] when [condition that previously failed]`
@@ -164,9 +165,14 @@ Create `refacil-sdd/changes/<fix-name>/summary.md`:
164
165
 
165
166
  This file is mandatory for traceability and allows the `check-review` hook to detect the active change. The `.review-passed` will be created by `/refacil:review` upon approval.
166
167
 
167
- ### Step 4: Run all tests
168
+ ### Step 4: Verify tests (`METHODOLOGY-CONTRACT.md` §3.1)
168
169
 
169
- Resolve and run the test command according to `METHODOLOGY-CONTRACT.md §3`. All tests must pass.
170
+ 1. Read **`testScope`** from wrapper (default **`scoped`** if omitted).
171
+ 2. **`testScope: full`**: Resolve baseline from **`METHODOLOGY-CONTRACT.md §3`**, run **once unparsed** — **all tests** emitted by that command must pass.
172
+ 3. **`testScope: scoped`** (default): Collect **`verificationTargets`** — every production/test file **you edited or added** during fix mode (**including** regression tests created this session).
173
+ - Build **`scopedCommand`** by narrowing baseline §3 to cover only those roots (directories, `-p`/`-pl`, `--`/path suffixes — follow stack docs + **`AGENTS.md` / `.agents/testing.md`** when present — see §3.1 **Scoped command patterns**).
174
+ - Run **`scopedCommand`**; everything it selects must pass. **Do not** upgrade to repo-wide invocation while `scoped` unless §3.1 says narrowing is unreliable — then run baseline **once**, prepend report line **WARN: scoped narrowing unavailable → full-suite fallback (heavy)**.
175
+ 4. **`testsResult.command`** in JSON must quote the **literal** executed shell string (`scopedCommand` or baseline).
170
176
 
171
177
  ### Report + JSON block (fix)
172
178
 
@@ -208,4 +214,5 @@ Resolve and run the test command according to `METHODOLOGY-CONTRACT.md §3`. All
208
214
  - In mode=investigation: follow diagnose loop discipline (reproduce, minimize, hypothesize, validate evidence) before proposing a fix.
209
215
  - In mode=fix: the fix must be MINIMAL. Never over-refactor.
210
216
  - Regression tests are MANDATORY in mode=fix.
217
+ - **Scoped verification**: default **`testScope: scoped`** from wrapper — narrowed command in Step 4, not wholesale “run entire repo suite” unless `full`.
211
218
  - Use **concise** output mode by default.
@@ -11,7 +11,7 @@ You are an implementation agent. You receive a structured briefing (objective, s
11
11
 
12
12
  If the briefing is ambiguous or a task cannot be completed safely, report it — do not silently skip or guess.
13
13
 
14
- **Prerequisites**: rules from `refacil-prereqs/METHODOLOGY-CONTRACT.md`.
14
+ **Prerequisites**: rules from `refacil-prereqs/METHODOLOGY-CONTRACT.md` (**§3**, **§3.1** — default verification is **scoped**).
15
15
 
16
16
  ## Guardrail: direct invocation detection
17
17
 
@@ -72,7 +72,9 @@ Read from the prompt the `BRIEFING:` sections passed by the wrapper:
72
72
  - `scope.modify` — existing files to modify
73
73
  - `scope.doNotTouch` — files out of scope
74
74
  - `tasks` — numbered task list
75
- - `testCommand` — verification command
75
+ - `testScope` — `scoped` \| `full` (default **`scoped`** if absent — treat missing as scoped)
76
+ - `testCommand` — **exact shell command** to execute for verification (narrowed when `scoped`)
77
+ - `verificationWarning` — optional hint from wrapper (often explains fallback-to-baseline)
76
78
  - `architectureContext` — already-extracted architecture context
77
79
  - `specsNote` — if there are specs, where they are and whether there are possible contradictions
78
80
 
@@ -82,7 +84,7 @@ If the briefing is **not present** (direct invocation without briefing):
82
84
  3. Read `refacil-sdd/changes/<changeName>/tasks.md` (tasks)
83
85
  4. Read `AGENTS.md` (architecture)
84
86
  5. Read the change specs
85
- 6. Read `METHODOLOGY-CONTRACT.md §3` (test command)
87
+ 6. Read `METHODOLOGY-CONTRACT.md` §3 and §3.1 (narrow **before** invoking the runner unless you explicitly widen)
86
88
 
87
89
  ### Step 2: Read existing interfaces (scope.modify only)
88
90
 
@@ -103,7 +105,12 @@ If a task requires touching a file outside the scope: note it in `issues` as pot
103
105
 
104
106
  ### Step 4: Verify
105
107
 
106
- Run the `testCommand` from the briefing (or from `METHODOLOGY-CONTRACT.md §3` if not in the briefing).
108
+ Follow **`METHODOLOGY-CONTRACT.md §3.1`**:
109
+
110
+ 1. Run **exactly** the **`testCommand`** supplied in the briefing.
111
+ 2. If **`testCommand` is missing**, resolve baseline from **`METHODOLOGY-CONTRACT.md §3`** and **narrow** it yourself using `scope.create` ∪ `scope.modify` plus the §3.1 **Scoped command patterns**. If narrowing is unsafe, run the baseline **once**, add **`issues`** entry severity **MEDIUM** explaining full-suite fallback, and cite `verificationWarning` pattern if analogous.
112
+ 3. **Do not** broaden the briefing’s `testCommand` into a fuller suite when `testScope` is **`scoped`** (or omitted). Repo-wide regression belongs in CI or an explicit **`/refacil:test … full`**.
113
+ 4. If `verificationWarning` is present in the briefing, mirror a short note in **`issues`** (severity **LOW**) so the wrapper/user sees CPU/RAM risk was intentional.
107
114
 
108
115
  ### Step 5: Report + JSON block
109
116
 
package/bin/cli.js CHANGED
@@ -1,14 +1,13 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  'use strict';
4
4
 
5
5
  const fs = require('fs');
6
6
  const path = require('path');
7
7
  const os = require('os');
8
- const {
9
- syncCompactGuidance,
10
- removeCompactGuidance,
11
- } = require('../lib/compact-guidance');
8
+ const { removeCompactGuidance } = require('../lib/compact-guidance');
9
+ const { removeTestingPolicyBlock } = require('../lib/testing-policy-sync');
10
+ const { syncRepoSessionMarkers } = require('../lib/session-repo-sync');
12
11
  const compactBash = require('../lib/compact/bash');
13
12
  const {
14
13
  installSkills,
@@ -17,6 +16,7 @@ const {
17
16
  removeSkills,
18
17
  removeGlobalSkills,
19
18
  removeOpenCodeArtifacts,
19
+ removeCodexArtifacts,
20
20
  removeOpenspecLegacyAssets,
21
21
  removeProjectLevelArtifacts,
22
22
  createClaudeMd,
@@ -30,7 +30,7 @@ const {
30
30
  checkClaudeCodeVersion,
31
31
  } = require('../lib/installer');
32
32
  const { installHooks, uninstallHooks, cleanLegacySettingsHooks, installOpenCodePlugin, uninstallOpenCodePlugin, removeProjectLevelHooks } = require('../lib/hooks');
33
- const { globalClaudeDir, globalCursorDir, globalOpenCodeDir, readSelectedIDEs, writeSelectedIDEs } = require('../lib/global-paths');
33
+ const { globalClaudeDir, globalCursorDir, globalOpenCodeDir, globalCodexDir, readSelectedIDEs, writeSelectedIDEs } = require('../lib/global-paths');
34
34
  const { detectInstalledIDEs } = require('../lib/ide-detection');
35
35
  const { handleCompact } = require('../lib/commands/compact');
36
36
  const { handleBus } = require('../lib/commands/bus');
@@ -131,7 +131,8 @@ function repoIsInitialized() {
131
131
  if (
132
132
  fs.existsSync(path.join(globalClaudeDir(home), 'skills')) ||
133
133
  fs.existsSync(path.join(globalCursorDir(home), 'skills')) ||
134
- fs.existsSync(path.join(globalOpenCodeDir(home), 'skills'))
134
+ fs.existsSync(path.join(globalOpenCodeDir(home), 'skills')) ||
135
+ fs.existsSync(path.join(globalCodexDir(home), 'skills'))
135
136
  ) {
136
137
  return true;
137
138
  }
@@ -204,9 +205,9 @@ function readlineMultiSelect(options) {
204
205
  */
205
206
  async function selectIDEs() {
206
207
  const allFlag = process.argv.includes('--all');
207
- const allIDEs = ['.claude', '.cursor', '.opencode'];
208
+ const allIDEs = ['.claude', '.cursor', '.opencode', '.codex'];
208
209
 
209
- // --all or non-TTY: install all three
210
+ // --all or non-TTY: install all four
210
211
  if (allFlag || !process.stdout.isTTY) {
211
212
  return allIDEs;
212
213
  }
@@ -226,11 +227,15 @@ async function selectIDEs() {
226
227
  const openCodeSelected = hasSaved
227
228
  ? savedSelection.includes('.opencode')
228
229
  : detectedIds.includes('opencode') || fs.existsSync(path.join(projectRoot, '.opencode'));
230
+ const codexSelected = hasSaved
231
+ ? savedSelection.includes('.codex')
232
+ : detectedIds.includes('codex');
229
233
 
230
234
  const options = [
231
235
  { label: 'Claude Code (~/.claude/)', value: '.claude', selected: claudeSelected },
232
236
  { label: 'Cursor (~/.cursor/)', value: '.cursor', selected: cursorSelected },
233
237
  { label: 'OpenCode (global config dir)', value: '.opencode', selected: openCodeSelected },
238
+ { label: 'Codex (~/.codex/)', value: '.codex', selected: codexSelected },
234
239
  ];
235
240
 
236
241
  // Try @clack/prompts first, fall back to inline readline
@@ -337,7 +342,8 @@ function checkUpdate() {
337
342
  const globalActive =
338
343
  fs.existsSync(path.join(globalClaudeDir(home), 'skills')) ||
339
344
  fs.existsSync(path.join(globalCursorDir(home), 'skills')) ||
340
- fs.existsSync(path.join(globalOpenCodeDir(home), 'skills'));
345
+ fs.existsSync(path.join(globalOpenCodeDir(home), 'skills')) ||
346
+ fs.existsSync(path.join(globalCodexDir(home), 'skills'));
341
347
 
342
348
  if (globalActive) {
343
349
  const cleaned = removeProjectLevelArtifacts(projectRoot);
@@ -354,9 +360,23 @@ function checkUpdate() {
354
360
  let localVersion = getPackageVersion(packageRoot);
355
361
 
356
362
  try {
357
- syncCompactGuidance(projectRoot, packageRoot);
363
+ const syncOut = syncRepoSessionMarkers(projectRoot, packageRoot);
364
+ if (!syncOut.ok) {
365
+ process.stderr.write(`[refacil-sdd-ai] session repo sync: ${syncOut.reason}\n`);
366
+ } else {
367
+ if (syncOut.compact.status === 'error') {
368
+ process.stderr.write(`[refacil-sdd-ai] Could not sync compact-guidance: ${syncOut.compact.message}\n`);
369
+ }
370
+ if (syncOut.testing.status === 'error') {
371
+ process.stderr.write(`[refacil-sdd-ai] Could not sync testing-policy block: ${syncOut.testing.message}\n`);
372
+ } else if (
373
+ ['created-file', 'appended', 'replaced', 'written-empty'].includes(syncOut.testing.status)
374
+ ) {
375
+ process.stdout.write(`[refacil-sdd-ai] testing-policy: ${syncOut.testing.status} (.agents/testing.md)\n`);
376
+ }
377
+ }
358
378
  } catch (err) {
359
- process.stderr.write(`[refacil-sdd-ai] Could not sync compact-guidance: ${err.message}\n`);
379
+ process.stderr.write(`[refacil-sdd-ai] session repo sync: ${err.message}\n`);
360
380
  }
361
381
 
362
382
  cleanLegacySettingsHooks(projectRoot);
@@ -616,6 +636,7 @@ async function init() {
616
636
  const installClaude = selectedIDEs.includes('.claude');
617
637
  const installCursor = selectedIDEs.includes('.cursor');
618
638
  const installOpenCode = selectedIDEs.includes('.opencode');
639
+ const installCodex = selectedIDEs.includes('.codex');
619
640
  const homeDir = os.homedir();
620
641
 
621
642
  // Migration step: remove project-level artifacts (now global) — silent, non-destructive
@@ -630,6 +651,7 @@ async function init() {
630
651
  const ideList = selectedIDEs.map((d) => {
631
652
  if (d === '.claude') return `~/.claude/skills/`;
632
653
  if (d === '.cursor') return `~/.cursor/skills/`;
654
+ if (d === '.codex') return `~/.codex/skills/`;
633
655
  return `(opencode-global)/skills/`;
634
656
  }).join(', ');
635
657
  console.log(` ${count} skills installed in ${ideList}`);
@@ -639,6 +661,7 @@ async function init() {
639
661
  const agentList = selectedIDEs.map((d) => {
640
662
  if (d === '.claude') return `~/.claude/agents/`;
641
663
  if (d === '.cursor') return `~/.cursor/agents/`;
664
+ if (d === '.codex') return `~/.codex/agents/`;
642
665
  return `(opencode-global)/agents/`;
643
666
  }).join(', ');
644
667
  console.log(` ${agentsCount} sub-agents installed in ${agentList}`);
@@ -666,6 +689,12 @@ async function init() {
666
689
  }
667
690
  }
668
691
 
692
+ if (installCodex) {
693
+ if (installHooks('.codex', homeDir)) {
694
+ console.log(' Hook check-update added to ~/.codex/config.toml');
695
+ }
696
+ }
697
+
669
698
  try {
670
699
  const IDE_TO_IGNORE = { '.claude': '.claudeignore', '.cursor': '.cursorignore', '.opencode': '.opencodeignore' };
671
700
  const ignoreResult = syncIgnoreFiles(projectRoot, selectedIDEs);
@@ -683,14 +712,29 @@ async function init() {
683
712
  }
684
713
 
685
714
  try {
686
- const result = syncCompactGuidance(projectRoot, packageRoot);
687
- if (result.status === 'appended') {
688
- console.log(' compact-guidance block added to AGENTS.md');
689
- } else if (result.status === 'replaced') {
690
- console.log(' compact-guidance block updated in AGENTS.md');
715
+ const syncOut = syncRepoSessionMarkers(projectRoot, packageRoot);
716
+ if (!syncOut.ok) {
717
+ console.error(` Warning: session repo sync: ${syncOut.reason}`);
718
+ } else {
719
+ if (syncOut.compact.status === 'error') {
720
+ console.error(` Warning: could not sync compact-guidance: ${syncOut.compact.message}`);
721
+ } else if (syncOut.compact.status === 'appended') {
722
+ console.log(' compact-guidance block added to AGENTS.md');
723
+ } else if (syncOut.compact.status === 'replaced') {
724
+ console.log(' compact-guidance block updated in AGENTS.md');
725
+ }
726
+ if (syncOut.testing.status === 'error') {
727
+ console.error(` Warning: could not sync testing-policy: ${syncOut.testing.message}`);
728
+ } else if (syncOut.testing.status === 'created-file') {
729
+ console.log(' testing-policy: created .agents/testing.md');
730
+ } else if (syncOut.testing.status === 'appended' || syncOut.testing.status === 'written-empty') {
731
+ console.log(' testing-policy block added to .agents/testing.md');
732
+ } else if (syncOut.testing.status === 'replaced') {
733
+ console.log(' testing-policy block updated in .agents/testing.md');
734
+ }
691
735
  }
692
736
  } catch (err) {
693
- console.error(` Warning: could not sync compact-guidance: ${err.message}`);
737
+ console.error(` Warning: session repo sync: ${err.message}`);
694
738
  }
695
739
 
696
740
  console.log('\n Next steps:\n');
@@ -721,10 +765,13 @@ function update() {
721
765
  const hasOpenCodeDir = detectedIds.includes('opencode') ||
722
766
  fs.existsSync(path.join(globalOpenCodeDir(homeDir), 'skills')) ||
723
767
  fs.existsSync(path.join(projectRoot, '.opencode'));
768
+ const hasCodexFallback = detectedIds.includes('codex') ||
769
+ fs.existsSync(path.join(globalCodexDir(homeDir), 'skills'));
724
770
  selectedIDEs = [
725
771
  hasClaudeDir && '.claude',
726
772
  hasCursorDir && '.cursor',
727
773
  hasOpenCodeDir && '.opencode',
774
+ hasCodexFallback && '.codex',
728
775
  ].filter(Boolean);
729
776
  // Persist for future runs so detection only happens once
730
777
  if (selectedIDEs.length > 0) writeSelectedIDEs(selectedIDEs);
@@ -733,6 +780,7 @@ function update() {
733
780
  const hasClaudeDir = selectedIDEs.includes('.claude');
734
781
  const hasCursorDir = selectedIDEs.includes('.cursor');
735
782
  const hasOpenCodeDir = selectedIDEs.includes('.opencode');
783
+ const hasCodexDir = selectedIDEs.includes('.codex');
736
784
  const detectedIDEs = selectedIDEs;
737
785
 
738
786
  // Migration step: remove project-level artifacts — silent, non-destructive
@@ -745,6 +793,7 @@ function update() {
745
793
  const installedDirs = detectedIDEs.map((d) => {
746
794
  if (d === '.claude') return '~/.claude/skills/';
747
795
  if (d === '.cursor') return '~/.cursor/skills/';
796
+ if (d === '.codex') return '~/.codex/skills/';
748
797
  return '(opencode-global)/skills/';
749
798
  });
750
799
  console.log(` ${count} skills updated in ${installedDirs.join(', ') || '(none detected)'}`);
@@ -755,6 +804,7 @@ function update() {
755
804
  hasClaudeDir && '~/.claude/agents/',
756
805
  hasCursorDir && '~/.cursor/agents/',
757
806
  hasOpenCodeDir && '(opencode-global)/agents/',
807
+ hasCodexDir && '~/.codex/agents/',
758
808
  ].filter(Boolean);
759
809
  console.log(` ${agentsCount} sub-agents updated in ${agentDirs.join(', ')}`);
760
810
  }
@@ -789,6 +839,12 @@ function update() {
789
839
  }
790
840
  }
791
841
 
842
+ if (hasCodexDir) {
843
+ if (installHooks('.codex', homeDir)) {
844
+ console.log(' Hook check-update updated in ~/.codex/config.toml');
845
+ }
846
+ }
847
+
792
848
  try {
793
849
  const IDE_TO_IGNORE = { '.claude': '.claudeignore', '.cursor': '.cursorignore', '.opencode': '.opencodeignore' };
794
850
  const ignoreResult = syncIgnoreFiles(projectRoot, detectedIDEs);
@@ -806,14 +862,29 @@ function update() {
806
862
  }
807
863
 
808
864
  try {
809
- const result = syncCompactGuidance(projectRoot, packageRoot);
810
- if (result.status === 'appended') {
811
- console.log(' compact-guidance block added to AGENTS.md');
812
- } else if (result.status === 'replaced') {
813
- console.log(' compact-guidance block updated in AGENTS.md');
865
+ const syncOut = syncRepoSessionMarkers(projectRoot, packageRoot);
866
+ if (!syncOut.ok) {
867
+ console.error(` Warning: session repo sync: ${syncOut.reason}`);
868
+ } else {
869
+ if (syncOut.compact.status === 'error') {
870
+ console.error(` Warning: could not sync compact-guidance: ${syncOut.compact.message}`);
871
+ } else if (syncOut.compact.status === 'appended') {
872
+ console.log(' compact-guidance block added to AGENTS.md');
873
+ } else if (syncOut.compact.status === 'replaced') {
874
+ console.log(' compact-guidance block updated in AGENTS.md');
875
+ }
876
+ if (syncOut.testing.status === 'error') {
877
+ console.error(` Warning: could not sync testing-policy: ${syncOut.testing.message}`);
878
+ } else if (syncOut.testing.status === 'created-file') {
879
+ console.log(' testing-policy: created .agents/testing.md');
880
+ } else if (syncOut.testing.status === 'appended' || syncOut.testing.status === 'written-empty') {
881
+ console.log(' testing-policy block added to .agents/testing.md');
882
+ } else if (syncOut.testing.status === 'replaced') {
883
+ console.log(' testing-policy block updated in .agents/testing.md');
884
+ }
814
885
  }
815
886
  } catch (err) {
816
- console.error(` Warning: could not sync compact-guidance: ${err.message}`);
887
+ console.error(` Warning: session repo sync: ${err.message}`);
817
888
  }
818
889
 
819
890
  console.log('\n RESTART your IDE session to apply the changes.\n');
@@ -853,6 +924,17 @@ function clean() {
853
924
  console.error(` Warning: could not remove OpenCode plugin: ${err.message}`);
854
925
  }
855
926
 
927
+ // Remove Codex global artifacts (skills + agents) and hooks
928
+ try {
929
+ removeCodexArtifacts(homeDir);
930
+ console.log(' Codex skills and agents removed from ~/.codex/');
931
+ } catch (err) {
932
+ console.error(` Warning: could not remove Codex artifacts: ${err.message}`);
933
+ }
934
+ if (uninstallHooks('.codex', homeDir)) {
935
+ console.log(' SDD-AI hooks removed from ~/.codex/config.toml');
936
+ }
937
+
856
938
  // Clean project-level OpenCode artifacts if .opencode/ directory is present
857
939
  if (fs.existsSync(path.join(projectRoot, '.opencode'))) {
858
940
  try {
@@ -872,6 +954,15 @@ function clean() {
872
954
  console.error(` Warning: could not clean compact-guidance: ${err.message}`);
873
955
  }
874
956
 
957
+ try {
958
+ const tp = removeTestingPolicyBlock(projectRoot);
959
+ if (tp.status === 'removed') {
960
+ console.log(' testing-policy block removed from .agents/testing.md');
961
+ }
962
+ } catch (err) {
963
+ console.error(` Warning: could not clean testing-policy: ${err.message}`);
964
+ }
965
+
875
966
  console.log(' AGENTS.md, CLAUDE.md and .cursorrules were not removed.');
876
967
  console.log('\n Note: if you have openspec/ in the repo, migrate first with: refacil-sdd-ai sdd status');
877
968
  console.log(' (the openspec/ → refacil-sdd/ migration is automatic on any sdd subcommand)');
@@ -883,19 +974,20 @@ function help() {
883
974
  const claudePath = globalClaudeDir(home);
884
975
  const cursorPath = globalCursorDir(home);
885
976
  const opencodePath = globalOpenCodeDir(home);
977
+ const codexPath = globalCodexDir(home);
886
978
 
887
979
  console.log(`
888
980
  refacil-sdd-ai — SDD-AI Methodology
889
981
 
890
982
  Commands:
891
- init Install skills globally for Claude Code, Cursor and/or OpenCode (interactive IDE selector).
892
- Use --all to install for all three IDEs without prompting.
983
+ init Install skills globally for Claude Code, Cursor, OpenCode and/or Codex (interactive IDE selector).
984
+ Use --all to install for all four IDEs without prompting.
893
985
  Use --yes or --defaults to skip interactive branch config prompts.
894
986
  Creates CLAUDE.md, .cursorrules and .opencode/opencode.json as appropriate.
895
987
  Migrates any project-level artifacts to global dirs automatically.
896
988
  update Re-copy skills for all detected IDEs to global user dirs
897
989
  migration-pending Same validation as hooks/notify-update: list migrations (exit 1 if any; --json)
898
- check-update Sync skills and compact-guidance at session start (SessionStart hook)
990
+ check-update Sync skills, compact-guidance (AGENTS.md), and testing-policy block (.agents/testing.md) at session start
899
991
  notify-update Notify methodology migration only if applicable (UserPromptSubmit hook)
900
992
  check-review Verify that review has been completed (used by PreToolUse hook)
901
993
  compact-bash Rewrite bare Bash commands to reduce tokens (used by PreToolUse hook)
@@ -940,7 +1032,7 @@ function help() {
940
1032
  Full flow:
941
1033
  1. npm install -g refacil-sdd-ai
942
1034
  2. refacil-sdd-ai init
943
- 3. RESTART your IDE session (Claude Code, Cursor, or OpenCode)
1035
+ 3. RESTART your IDE session (Claude Code, Cursor, OpenCode, or Codex)
944
1036
  4. Run: /refacil:setup (generates AGENTS.md for your project)
945
1037
 
946
1038
  Global installation paths (this machine):
@@ -950,6 +1042,8 @@ function help() {
950
1042
  ${cursorPath}/hooks.json (hooks)
951
1043
  - OpenCode: ${opencodePath}/skills/, ${opencodePath}/agents/
952
1044
  ${opencodePath}/plugins/refacil-hooks.js
1045
+ - Codex: ${codexPath}/skills/, ${codexPath}/agents/
1046
+ ${codexPath}/config.toml (hooks)
953
1047
 
954
1048
  Requirements:
955
1049
  - Node.js >= 20.0.0