claudekit-codex-sync 0.2.3 → 0.2.5

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
@@ -13,11 +13,11 @@ ClaudeKit uses `~/.claude/` conventions and agent markdown frontmatter. Codex us
13
13
  | **Scope select** | Sync to project `./.codex/` (default) or global `~/.codex/` (`-g`) |
14
14
  | **Fresh clean** | Optional `-f` cleanup of target dirs before sync |
15
15
  | **Source resolve** | Uses live `~/.claude/` or `--zip` export |
16
- | **Asset sync** | Copies agents `.md` → `agents/` (for TOML conversion), commands/output-styles/rules/scripts → `codex_home/` directly |
16
+ | **Asset sync** | Copies agents `.md` → `agents/` (for TOML conversion), output-styles/rules/scripts → `codex_home/` directly |
17
17
  | **Skill sync** | Copies skills into `codex_home/skills/` |
18
18
  | **Path normalize** | Rewrites `.claude` references to `.codex` |
19
+ | **Hook rules** | Generates rules/ from hook behavior (security-privacy, file-naming, code-quality) |
19
20
  | **Config enforce** | Ensures `config.toml`, feature flags, and agent registration |
20
- | **Prompt export** | Generates Codex-compatible prompt files |
21
21
  | **Dep bootstrap** | Symlink-first venv strategy, fallback install |
22
22
  | **Runtime verify** | Health-checks synced environment |
23
23
 
@@ -26,6 +26,18 @@
26
26
  - [x] Documentation refresh for new CLI contract
27
27
  - [x] Removed legacy standalone `scripts/` and stale `reports/`
28
28
 
29
+ ## v0.2.5 - Hooks→Rules + Remove Prompts
30
+
31
+ **Status:** Complete
32
+
33
+ - [x] Remove hooks sync (Codex has no hooks API)
34
+ - [x] Generate hook-equivalent rules (security-privacy, file-naming, code-quality)
35
+ - [x] Remove commands sync (deprecated concept)
36
+ - [x] Remove prompt export step (deprecated by OpenAI)
37
+ - [x] Update bridge skill for Codex-native routing
38
+ - [x] Add syntax adaptations for Claude→Codex patterns
39
+ - [x] Add test coverage for rules_generator
40
+
29
41
  ## v0.3.0 - Coverage + Reliability
30
42
 
31
43
  **Status:** Planned
@@ -8,12 +8,10 @@
8
8
  │ ~/.claude/ or zip │───▶│ ./.codex or ~/.codex │
9
9
  │ agents/*.md │ │ agents/*.toml (convert) │
10
10
  │ skills/* │ │ skills/* │
11
- │ commands/ │ │ commands/ │
12
11
  │ output-styles/ │ │ output-styles/ │
13
12
  │ rules/ │ │ rules/ │
14
13
  │ scripts/ │ │ scripts/ │
15
- └─────────────────────┘ │ prompts/* (generated)
16
- │ config.toml │
14
+ └─────────────────────┘ │ config.toml
17
15
  └──────────────────────────┘
18
16
  ```
19
17
 
@@ -28,7 +26,7 @@ Workspace baseline: `./AGENTS.md` is ensured in the current working directory.
28
26
 
29
27
  2. **Asset/skill sync**
30
28
  - Copy agents `.md` directly to `codex_home/agents/` (for TOML conversion)
31
- - Copy managed assets (commands, output-styles, rules, scripts) to `codex_home/` directly
29
+ - Copy managed assets (output-styles, rules, scripts) to `codex_home/` directly
32
30
  - Copy skills to `codex_home/skills/`
33
31
  - Apply registry-aware overwrite behavior (`--force`)
34
32
 
@@ -43,8 +41,8 @@ Workspace baseline: `./AGENTS.md` is ensured in the current working directory.
43
41
  - Register agents from `agents/*.toml`
44
42
  - Ensure workspace-level `AGENTS.md` baseline file exists
45
43
 
46
- 5. **Prompt export**
47
- - Generate prompt files for Codex runtime from `commands/*.md`
44
+ 5. **Hook rules generation**
45
+ - Generate rules/ from hook behavior templates (security-privacy, file-naming, code-quality)
48
46
 
49
47
  6. **Dependency bootstrap**
50
48
  - Try symlink reuse of `~/.claude/skills/.venv`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudekit-codex-sync",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "Sync ClaudeKit skills, agents, and config to Codex CLI",
5
5
  "main": "bin/ck-codex-sync.js",
6
6
  "bin": {
@@ -0,0 +1,202 @@
1
+ # Phase 1: Remove Hooks, Generate Rules
2
+
3
+ Status: pending
4
+ Priority: critical
5
+ Effort: 0.5d
6
+
7
+ ## Goal
8
+
9
+ Stop syncing hooks (dead code). Create rules that replicate hook behavior at startup.
10
+
11
+ ## Context
12
+
13
+ - 15 hooks use Claude Code's hook API (SessionStart, PreToolUse, etc.)
14
+ - Codex CLI has NO hooks support — hooks dir is dead code
15
+ - Rules (`~/.codex/rules/*.md`) load at startup = always in context = equivalent to hooks
16
+
17
+ ## Steps
18
+
19
+ ### 1.1 Remove `"hooks"` from ASSET_DIRS
20
+
21
+ **File:** [constants.py](file:///home/vinhawk/claudekit-codex-sync/src/claudekit_codex_sync/constants.py)
22
+
23
+ ```diff
24
+ -ASSET_DIRS = {"commands", "output-styles", "rules", "scripts", "hooks"}
25
+ +ASSET_DIRS = {"output-styles", "rules", "scripts"}
26
+ ```
27
+
28
+ > Also removes `"commands"` — Phase 2 handles this.
29
+
30
+ ### 1.2 Create rule templates
31
+
32
+ **File:** `templates/rule-security-privacy.md` [NEW]
33
+
34
+ ```markdown
35
+ # Security & Privacy
36
+
37
+ ## Sensitive File Access
38
+ Ask user for explicit approval before reading:
39
+ - `.env`, `.env.*` (API keys, passwords, tokens)
40
+ - `*.key`, `*.pem`, `*.p12`, `credentials.*`, `secrets.*`
41
+ - Files in `~/.ssh/`, `~/.gnupg/`, `~/.aws/`
42
+
43
+ **Flow:** State which file and why → wait for "yes" → read via cat → never output full secrets.
44
+
45
+ ## Directory Access Control
46
+ Respect `.ckignore` patterns if present in project root:
47
+ - Read `.ckignore` at session start
48
+ - Do NOT access matching directories
49
+ - Common: `node_modules/`, `dist/`, `build/`, `.git/objects/`
50
+ ```
51
+
52
+ **File:** `templates/rule-file-naming.md` [NEW]
53
+
54
+ ```markdown
55
+ # File Naming
56
+
57
+ Apply before every file creation (skip for markdown/text):
58
+ - **JS/TS/Python/shell**: kebab-case with descriptive names
59
+ - **C#/Java/Kotlin/Swift**: PascalCase
60
+ - **Go/Rust**: snake_case
61
+ - Goal: self-documenting names for LLM tools (Grep, Glob, Search)
62
+ ```
63
+
64
+ **File:** `templates/rule-code-quality.md` [NEW]
65
+
66
+ ```markdown
67
+ # Code Quality Reminders
68
+
69
+ ## Code Simplification
70
+ After significant file edits (5+), consider running code-simplifier agent.
71
+
72
+ ## Post-Planning
73
+ After creating an implementation plan, always activate the cook skill before implementation.
74
+
75
+ ## Modularization
76
+ If a code file exceeds 200 lines, consider modularizing it.
77
+ ```
78
+
79
+ ### 1.3 Create rules_generator module
80
+
81
+ **File:** `src/claudekit_codex_sync/rules_generator.py` [NEW]
82
+
83
+ ```python
84
+ """Generate hook-equivalent rules from templates."""
85
+
86
+ from __future__ import annotations
87
+
88
+ from pathlib import Path
89
+
90
+ from .utils import load_template, write_text_if_changed
91
+
92
+
93
+ RULE_TEMPLATES = {
94
+ "security-privacy.md": "rule-security-privacy.md",
95
+ "file-naming.md": "rule-file-naming.md",
96
+ "code-quality-reminders.md": "rule-code-quality.md",
97
+ }
98
+
99
+
100
+ def generate_hook_rules(*, codex_home: Path, dry_run: bool) -> int:
101
+ """Generate rules that replace ClaudeKit hook behavior."""
102
+ rules_dir = codex_home / "rules"
103
+ if not dry_run:
104
+ rules_dir.mkdir(parents=True, exist_ok=True)
105
+
106
+ generated = 0
107
+ for rule_name, template_name in RULE_TEMPLATES.items():
108
+ content = load_template(template_name)
109
+ target = rules_dir / rule_name
110
+ if write_text_if_changed(target, content, dry_run=dry_run):
111
+ generated += 1
112
+ print(f"upsert: rules/{rule_name}")
113
+
114
+ return generated
115
+ ```
116
+
117
+ ### 1.4 Fix `set-active-plan.cjs` hooks/lib dependency
118
+
119
+ > [!WARNING]
120
+ > **Discovered via Codex CLI live testing (`cxp --full-auto`)**:
121
+ > `set-active-plan.cjs` line 16: `require('../hooks/lib/ck-config-utils.cjs')`.
122
+ > Currently works because hooks ARE synced. **Will break after removing hooks.**
123
+ > Only uses 2 functions: `readSessionState` + `writeSessionState` (~20 lines total).
124
+
125
+ **File:** `scripts/set-active-plan.cjs` (source in `~/.claude/scripts/`)
126
+
127
+ Inline the 3 tiny functions to remove hooks/lib dependency:
128
+
129
+ ```diff
130
+ -const { writeSessionState, readSessionState } = require('../hooks/lib/ck-config-utils.cjs');
131
+ +// Inlined from hooks/lib/ck-config-utils.cjs (hooks removed in v0.2.5)
132
+ +function getSessionTempPath(sessionId) {
133
+ + return path.join(os.tmpdir(), `ck-session-${sessionId}.json`);
134
+ +}
135
+ +function readSessionState(sessionId) {
136
+ + if (!sessionId) return null;
137
+ + const tempPath = getSessionTempPath(sessionId);
138
+ + try {
139
+ + if (!fs.existsSync(tempPath)) return null;
140
+ + return JSON.parse(fs.readFileSync(tempPath, 'utf8'));
141
+ + } catch (e) { return null; }
142
+ +}
143
+ +function writeSessionState(sessionId, state) {
144
+ + if (!sessionId) return false;
145
+ + const tempPath = getSessionTempPath(sessionId);
146
+ + const tmpFile = tempPath + '.' + Math.random().toString(36).slice(2);
147
+ + try {
148
+ + fs.writeFileSync(tmpFile, JSON.stringify(state, null, 2));
149
+ + fs.renameSync(tmpFile, tempPath);
150
+ + return true;
151
+ + } catch (e) {
152
+ + try { fs.unlinkSync(tmpFile); } catch (_) {}
153
+ + return false;
154
+ + }
155
+ +}
156
+ ```
157
+
158
+ Also need to add `const os = require('os');` if not already present.
159
+
160
+ **Option**: Instead of modifying source, apply this patch during sync in `path_normalizer.py`
161
+ by replacing the `require('../hooks/lib/...')` line with inlined functions.
162
+
163
+ ## Codex CLI Live Test Results (cxp --full-auto)
164
+
165
+ | Script | Status | Notes |
166
+ |---|---|---|
167
+ | `ck-help.py` | ✅ OK | |
168
+ | `resolve_env.py` | ✅ OK | |
169
+ | `scan_commands.py` | ✅ OK | |
170
+ | `scan_skills.py` | ✅ OK | |
171
+ | `set-active-plan.cjs` (no args) | ⚠️ FAIL | Expected: usage error |
172
+ | `set-active-plan.cjs` (with plan) | ✅ OK | BUT depends on `../hooks/lib/` |
173
+ | `test-ck-help.py` | ✅ OK | |
174
+ | `test_ck_help.py` | ⚠️ FAIL | Pre-existing: intent detection mismatch |
175
+ | `test_ck_help_integration.py` | ⚠️ FAIL | Pre-existing: 17 pass / 2 fail |
176
+ | `validate-docs.cjs` | ✅ OK | |
177
+ | `win_compat.py` | ✅ OK | |
178
+ | `worktree.cjs` (no args) | ⚠️ FAIL | Expected: usage error |
179
+ | `worktree.test.cjs` | ⚠️ FAIL | Pre-existing test failures |
180
+
181
+ **Summary**: 8 OK / 5 FAIL. Of 5 FAILs: 2 expected (no-args usage), 2 pre-existing test bugs, 1 dependency issue (set-active-plan → hooks/lib).
182
+
183
+ ## Todo
184
+
185
+ - [ ] Remove `"hooks"` and `"commands"` from `ASSET_DIRS`
186
+ - [ ] Create `templates/rule-security-privacy.md`
187
+ - [ ] Create `templates/rule-file-naming.md`
188
+ - [ ] Create `templates/rule-code-quality.md`
189
+ - [ ] Create `src/claudekit_codex_sync/rules_generator.py`
190
+ - [ ] Fix `set-active-plan.cjs` hooks/lib dependency (inline or patch during sync)
191
+ - [ ] Compile check: `python3 -m py_compile src/claudekit_codex_sync/rules_generator.py`
192
+
193
+ ## Verification
194
+
195
+ ```bash
196
+ python3 -m py_compile src/claudekit_codex_sync/rules_generator.py
197
+ python3 -m py_compile src/claudekit_codex_sync/constants.py
198
+ ls templates/rule-*.md # should show 3 files
199
+ # After sync, verify set-active-plan.cjs no longer depends on hooks:
200
+ grep -c "hooks/lib" ~/.codex/scripts/set-active-plan.cjs # should be 0
201
+ node ~/.codex/scripts/set-active-plan.cjs plans/test 2>&1 | head -5 # should not MODULE_NOT_FOUND
202
+ ```
@@ -0,0 +1,82 @@
1
+ # Phase 2: Remove Commands & Prompts Sync
2
+
3
+ Status: pending
4
+ Priority: high
5
+ Effort: 0.5d
6
+
7
+ ## Goal
8
+
9
+ Eliminate commands/prompts duplication from pipeline. Commands already removed from `ASSET_DIRS` in Phase 1, now remove prompt generation.
10
+
11
+ ## Context
12
+
13
+ - Codex [deprecated custom prompts](https://developers.openai.com/codex/custom-prompts) in favor of skills
14
+ - `prompt_exporter.py` generates duplicates of every command → wasteful
15
+ - Bridge skill already maps legacy `/commands` → Codex skills
16
+ - Both `commands/` and `prompts/` produce identical content
17
+
18
+ ## Steps
19
+
20
+ ### 2.1 Remove prompt export from CLI
21
+
22
+ **File:** [cli.py](file:///home/vinhawk/claudekit-codex-sync/src/claudekit_codex_sync/cli.py)
23
+
24
+ Remove import and call:
25
+
26
+ ```diff
27
+ -from .prompt_exporter import export_prompts
28
+ +from .rules_generator import generate_hook_rules
29
+ ```
30
+
31
+ Remove prompt export call (~line 188):
32
+
33
+ ```diff
34
+ - prompt_stats = export_prompts(codex_home=codex_home, include_mcp=args.mcp, dry_run=args.dry_run)
35
+ - print(f"prompts: added={prompt_stats['added']} total={prompt_stats['total_generated']}")
36
+ ```
37
+
38
+ Add rules generation call after normalize step (~line 163):
39
+
40
+ ```diff
41
+ + rules_generated = generate_hook_rules(codex_home=codex_home, dry_run=args.dry_run)
42
+ + print(f"hook_rules_generated={rules_generated}")
43
+ ```
44
+
45
+ Update summary dict:
46
+
47
+ ```diff
48
+ - "prompts": prompt_stats,
49
+ + "rules_generated": rules_generated,
50
+ ```
51
+
52
+ ### 2.2 Remove prompts manifest from clean_target
53
+
54
+ **File:** [clean_target.py](file:///home/vinhawk/claudekit-codex-sync/src/claudekit_codex_sync/clean_target.py)
55
+
56
+ `".claudekit-generated-prompts.txt"` stays in cleanup list (for cleaning old installs) but `"prompts"` is already in the subdir cleanup loop — no change needed.
57
+
58
+ ### 2.3 Remove PROMPT_MANIFEST/PROMPT_REPLACEMENTS usage
59
+
60
+ **File:** [constants.py](file:///home/vinhawk/claudekit-codex-sync/src/claudekit_codex_sync/constants.py)
61
+
62
+ Keep `PROMPT_REPLACEMENTS` and `PROMPT_MANIFEST` constants (no harm, `prompt_exporter.py` still importable). But mark as deprecated with comment:
63
+
64
+ ```python
65
+ # DEPRECATED: prompt_exporter.py no longer called from CLI pipeline (v0.2.5)
66
+ PROMPT_MANIFEST = ".claudekit-generated-prompts.txt"
67
+ ```
68
+
69
+ ## Todo
70
+
71
+ - [ ] Remove `export_prompts` import from `cli.py`
72
+ - [ ] Remove prompt export call from `cli.py`
73
+ - [ ] Add `generate_hook_rules` import and call to `cli.py`
74
+ - [ ] Update summary dict in `cli.py`
75
+ - [ ] Mark `PROMPT_MANIFEST` as deprecated in `constants.py`
76
+
77
+ ## Verification
78
+
79
+ ```bash
80
+ python3 -m py_compile src/claudekit_codex_sync/cli.py
81
+ PYTHONPATH=src python3 -m claudekit_codex_sync.cli -g -n # dry-run should not error
82
+ ```
@@ -0,0 +1,59 @@
1
+ # Phase 3: Update Bridge Skill + Syntax Adaptations
2
+
3
+ Status: pending
4
+ Priority: medium
5
+ Effort: 0.25d
6
+
7
+ ## Goal
8
+
9
+ Update bridge skill description. Add syntax adaptations for remaining Claude-specific patterns.
10
+
11
+ ## Steps
12
+
13
+ ### 3.1 Update bridge skill template
14
+
15
+ **File:** [templates/bridge-skill.md](file:///home/vinhawk/claudekit-codex-sync/templates/bridge-skill.md)
16
+
17
+ ```diff
18
+ ---
19
+ name: claudekit-command-bridge
20
+ -description: Bridge legacy ClaudeKit commands to Codex-native workflows. Use when users mention /ck-help, /coding-level, /ask, /docs/*, /journal, /watzup, or ask for Claude command equivalents.
21
+ +description: Bridge legacy ClaudeKit slash commands to Codex-native skills. Activates when users mention /ck-help, /coding-level, /ask, /docs/*, /journal, /watzup, or ask for Claude command equivalents.
22
+ ---
23
+
24
+ -# ClaudeKit Command Bridge
25
+ +# ClaudeKit → Codex Bridge
26
+
27
+ -Translate ClaudeKit command intent into Codex skills/workflows.
28
+ +Translate ClaudeKit command intent into Codex-native skills.
29
+ ```
30
+
31
+ ### 3.2 Add syntax adaptations
32
+
33
+ **File:** [constants.py](file:///home/vinhawk/claudekit-codex-sync/src/claudekit_codex_sync/constants.py)
34
+
35
+ Add entries to `CLAUDE_SYNTAX_ADAPTATIONS`:
36
+
37
+ ```diff
38
+ CLAUDE_SYNTAX_ADAPTATIONS: List[Tuple[str, str]] = [
39
+ ("Task(Explore)", "the explore agent"),
40
+ ("Task(researcher)", "the researcher agent"),
41
+ ("Task(", "delegate to "),
42
+ ("$HOME/.claude/skills/*", "${CODEX_HOME:-$HOME/.codex}/skills/*"),
43
+ + ("via Task tool", "via agent delegation"),
44
+ + ("Claude Code", "Codex CLI"),
45
+ + ("claude code", "Codex CLI"),
46
+ ]
47
+ ```
48
+
49
+ ## Todo
50
+
51
+ - [ ] Update `templates/bridge-skill.md` description
52
+ - [ ] Add syntax adaptations to `constants.py`
53
+
54
+ ## Verification
55
+
56
+ ```bash
57
+ python3 -m py_compile src/claudekit_codex_sync/constants.py
58
+ grep "Codex-native skills" templates/bridge-skill.md # should match
59
+ ```
@@ -0,0 +1,135 @@
1
+ # Phase 4: Version Bump, Docs, Tests
2
+
3
+ Status: pending
4
+ Priority: medium
5
+ Effort: 0.5d
6
+
7
+ ## Goal
8
+
9
+ Bump to v0.2.5. Update docs. Add tests for `rules_generator`. Run full verification.
10
+
11
+ ## Steps
12
+
13
+ ### 4.1 Version bump
14
+
15
+ **File:** [package.json](file:///home/vinhawk/claudekit-codex-sync/package.json)
16
+
17
+ ```diff
18
+ - "version": "0.2.4",
19
+ + "version": "0.2.5",
20
+ ```
21
+
22
+ ### 4.2 Add test for rules_generator
23
+
24
+ **File:** `tests/test_rules_generator.py` [NEW]
25
+
26
+ ```python
27
+ """Tests for rules_generator module."""
28
+
29
+ from pathlib import Path
30
+
31
+ from claudekit_codex_sync.rules_generator import generate_hook_rules
32
+
33
+
34
+ def test_generates_all_rule_files(tmp_path: Path):
35
+ """Generates 3 rule files."""
36
+ count = generate_hook_rules(codex_home=tmp_path, dry_run=False)
37
+ assert count == 3
38
+ assert (tmp_path / "rules" / "security-privacy.md").exists()
39
+ assert (tmp_path / "rules" / "file-naming.md").exists()
40
+ assert (tmp_path / "rules" / "code-quality-reminders.md").exists()
41
+
42
+
43
+ def test_idempotent(tmp_path: Path):
44
+ """Second run returns 0 (no changes)."""
45
+ generate_hook_rules(codex_home=tmp_path, dry_run=False)
46
+ count = generate_hook_rules(codex_home=tmp_path, dry_run=False)
47
+ assert count == 0
48
+
49
+
50
+ def test_dry_run(tmp_path: Path):
51
+ """Dry run counts but doesn't create."""
52
+ count = generate_hook_rules(codex_home=tmp_path, dry_run=True)
53
+ assert count == 3
54
+ assert not (tmp_path / "rules").exists()
55
+ ```
56
+
57
+ ### 4.3 Update README
58
+
59
+ **File:** [README.md](file:///home/vinhawk/claudekit-codex-sync/README.md)
60
+
61
+ Update "What It Does" table:
62
+ - Remove `Prompt export` row
63
+ - Remove hooks from `Asset sync` description
64
+ - Add `Hook rules` row: "Generates rules/ from hook behavior (security-privacy, file-naming, code-quality)"
65
+
66
+ ### 4.4 Update system-architecture
67
+
68
+ **File:** [docs/system-architecture.md](file:///home/vinhawk/claudekit-codex-sync/docs/system-architecture.md)
69
+
70
+ - Remove Step 5 (Prompt export) from pipeline
71
+ - Add step: "Hook rules generation"
72
+ - Remove `hooks/` from architecture diagram
73
+ - Remove `prompts/* (generated)` from diagram
74
+
75
+ ### 4.5 Update project roadmap
76
+
77
+ **File:** [docs/project-roadmap.md](file:///home/vinhawk/claudekit-codex-sync/docs/project-roadmap.md)
78
+
79
+ Add v0.2.5 section:
80
+
81
+ ```markdown
82
+ ## v0.2.5 - Hooks→Rules + Remove Prompts
83
+
84
+ **Status:** Complete
85
+
86
+ - [x] Remove hooks sync (Codex has no hooks API)
87
+ - [x] Generate hook-equivalent rules (security-privacy, file-naming, code-quality)
88
+ - [x] Remove commands sync (deprecated concept)
89
+ - [x] Remove prompt export step (deprecated by OpenAI)
90
+ - [x] Update bridge skill for Codex-native routing
91
+ - [x] Add syntax adaptations for Claude→Codex patterns
92
+ - [x] Add test coverage for rules_generator
93
+ ```
94
+
95
+ ## Todo
96
+
97
+ - [ ] Bump version in `package.json`
98
+ - [ ] Create `tests/test_rules_generator.py`
99
+ - [ ] Update `README.md`
100
+ - [ ] Update `docs/system-architecture.md`
101
+ - [ ] Update `docs/project-roadmap.md`
102
+
103
+ ## Final Verification (all 10 steps)
104
+
105
+ ```bash
106
+ # 1. Compile check
107
+ python3 -m py_compile src/claudekit_codex_sync/*.py
108
+
109
+ # 2. Run all tests
110
+ PYTHONPATH=src python3 -m pytest tests/ -v
111
+
112
+ # 3. Dry-run sync
113
+ PYTHONPATH=src python3 -m claudekit_codex_sync.cli -g -n
114
+
115
+ # 4. Actual sync (fresh)
116
+ PYTHONPATH=src python3 -m claudekit_codex_sync.cli -g -f --force
117
+
118
+ # 5. Verify hooks NOT synced
119
+ ls ~/.codex/hooks/ 2>/dev/null && echo "FAIL" || echo "OK: no hooks"
120
+
121
+ # 6. Verify rules generated
122
+ ls ~/.codex/rules/security-privacy.md ~/.codex/rules/file-naming.md ~/.codex/rules/code-quality-reminders.md
123
+
124
+ # 7. Verify no prompts generated
125
+ [ ! -f ~/.codex/prompts/.claudekit-generated-prompts.txt ] && echo "OK" || echo "FAIL"
126
+
127
+ # 8. Verify no commands dir
128
+ ls ~/.codex/commands/ 2>/dev/null && echo "WARN: commands exist" || echo "OK"
129
+
130
+ # 9. Verify existing rules intact
131
+ ls ~/.codex/rules/development-rules.md ~/.codex/rules/primary-workflow.md
132
+
133
+ # 10. Token budget check
134
+ du -b ~/.codex/rules/*.md | awk '{sum+=$1} END {print "Rules: " sum " bytes / 32768 limit"}'
135
+ ```
@@ -0,0 +1,49 @@
1
+ # v0.2.5 — Hooks→Rules, Remove Commands/Prompts, Harden Pipeline
2
+
3
+ Remove non-functional hooks, eliminate commands/prompts bloat, generate hook-equivalent rules.
4
+
5
+ ## Problem
6
+
7
+ - 15+ hooks copied to `~/.codex/hooks/` but Codex CLI has no hooks API → dead code
8
+ - Commands duplicated as both `commands/` and `prompts/` → bloat
9
+ - Custom prompts [deprecated by OpenAI](https://developers.openai.com/codex/custom-prompts)
10
+ - Bridge skill already maps legacy commands → Codex skills
11
+
12
+ ## Phases
13
+
14
+ | # | Phase | Status | Key Changes |
15
+ |---|---|---|---|
16
+ | 1 | [Remove hooks, generate rules](phase-01-hooks-to-rules.md) | `[x]` | `constants.py`, 3 templates, `rules_generator.py` |
17
+ | 2 | [Remove commands/prompts](phase-02-remove-commands-prompts.md) | `[x]` | `cli.py`, `clean_target.py` |
18
+ | 3 | [Update bridge skill + syntax](phase-03-bridge-and-syntax.md) | `[x]` | `templates/bridge-skill.md`, `constants.py` |
19
+ | 4 | [Version bump, docs, tests](phase-04-version-docs-tests.md) | `[x]` | `package.json`, `README.md`, docs, tests |
20
+
21
+ ## Before → After
22
+
23
+ ```
24
+ ~/.codex/ ~/.codex/
25
+ hooks/ ❌ NOT WORKING rules/
26
+ 15+ .cjs files development-rules.md ← existing
27
+ commands/ ⚠️ deprecated primary-workflow.md ← existing
28
+ 18+ .md files security-privacy.md ← NEW from hooks
29
+ prompts/ ⚠️ duplicate file-naming.md ← NEW from hooks
30
+ 18+ .md files code-quality-reminders.md ← NEW from hooks
31
+ rules/ ✅ skills/ ✅ unchanged
32
+ skills/ ✅ agents/ ✅ unchanged
33
+ agents/ ✅ scripts/ ✅ unchanged
34
+ ```
35
+
36
+ ## Dependencies
37
+
38
+ Phase 1 → Phase 2 → Phase 3 → Phase 4 (strict sequential)
39
+
40
+ ## Research Sources
41
+
42
+ - [Codex Skills docs](https://developers.openai.com/codex/skills): Skills at `$HOME/.agents/skills/`
43
+ - [Custom Prompts docs](https://developers.openai.com/codex/custom-prompts): **Deprecated**, use skills
44
+ - Codex rules: `~/.codex/rules/*.md` loaded at startup, always in context
45
+ - Token budget: 37 KiB used / 65 KiB limit → ~28 KiB remaining
46
+
47
+ ## Risk
48
+
49
+ Low — removes dead code, generates static rules from templates. No logic change to working features.
@@ -0,0 +1,78 @@
1
+ # Test Report: claudekit-codex-sync v0.2.3+fix
2
+
3
+ **Date:** 2026-02-23 16:25
4
+ **Scope:** Pre-push deep verification after eliminating `claudekit/` subdirectory
5
+ **Changes tested:** `constants.py`, `clean_target.py`, `asset_sync_dir.py`, `asset_sync_zip.py`, `path_normalizer.py`, `prompt_exporter.py`
6
+
7
+ ---
8
+
9
+ ## 1. Unit Tests — 22/22 ✅
10
+
11
+ | Module | Tests | Status |
12
+ |---|---|---|
13
+ | `test_clean_target.py` | 5 | ✅ |
14
+ | `test_cli_args.py` | 6 | ✅ |
15
+ | `test_config_enforcer.py` | 4 | ✅ |
16
+ | `test_path_normalizer.py` | 7 | ✅ |
17
+
18
+ ## 2. Compile Check — 8/8 ✅
19
+
20
+ All 8 modified Python modules compile without errors.
21
+
22
+ ## 3. E2E Sync (local source, `--fresh`) — ✅
23
+
24
+ | Metric | Value |
25
+ |---|---|
26
+ | Assets added | 146 |
27
+ | Skills added | 54 (4 skipped) |
28
+ | Normalize changed | 28 |
29
+ | Agents converted & registered | 14 |
30
+ | Prompts generated | 20 |
31
+ | Verify | codex=ok, copywriting=ok |
32
+
33
+ ## 4. Filesystem Validation — 7/7 ✅
34
+
35
+ | Check | Result |
36
+ |---|---|
37
+ | `~/.codex/claudekit/` does NOT exist | ✅ |
38
+ | `~/.codex/scripts/` (17 files) | ✅ |
39
+ | `~/.codex/rules/` (5 files) | ✅ |
40
+ | `~/.codex/commands/` (22 files) | ✅ |
41
+ | `~/.codex/hooks/` (81 files) | ✅ |
42
+ | `~/.codex/output-styles/` (6 files) | ✅ |
43
+ | `~/.codex/.ck.json` + `.env.example` | ✅ |
44
+
45
+ ## 5. Reference Integrity — 5/5 ✅
46
+
47
+ Zero stale `claudekit/` filesystem paths found in:
48
+
49
+ | Location | Stale refs |
50
+ |---|---|
51
+ | Skills | 0 |
52
+ | Agent TOMLs | 0 |
53
+ | Prompts | 0 (1 GitHub URL, correctly excluded) |
54
+ | Rules | 0 |
55
+ | Commands | 0 |
56
+
57
+ ## 6. Runtime Script Execution — 5/5 ✅
58
+
59
+ | Script | Language | Exit | Notes |
60
+ |---|---|---|---|
61
+ | `set-active-plan.cjs` | Node.js | 0 | Requires `../hooks/lib/` — now synced |
62
+ | `validate-docs.cjs` | Node.js | 0 | Generated validation report |
63
+ | `worktree.cjs list` | Node.js | 0 | Listed 1 worktree |
64
+ | `ck-help.py` | Python | 0 | CK help search works |
65
+ | `fix-shebang-permissions.sh` | Bash | 0 | Expected "Error: .claude not found" (runs from codex context) |
66
+
67
+ ---
68
+
69
+ ## Bugs Found & Fixed
70
+
71
+ | Bug | Severity | Fix |
72
+ |---|---|---|
73
+ | Scripts crash with `MODULE_NOT_FOUND` for `../hooks/lib/` | **High** | Added `hooks` to `ASSET_DIRS` in `constants.py` |
74
+ | Stale `claudekit/` dir not cleaned on fresh sync | **Medium** | Added `"claudekit"` to clean list in `clean_target.py` |
75
+
76
+ ## Verdict
77
+
78
+ **✅ ALL 6 TEST CATEGORIES PASS — READY TO PUSH**
@@ -10,8 +10,8 @@ def clean_target(codex_home: Path, *, dry_run: bool) -> int:
10
10
  """Remove agents, skills (keep .venv), prompts, asset dirs before fresh sync."""
11
11
  removed = 0
12
12
 
13
- # Clean top-level asset dirs (was: "agents", "prompts", "claudekit")
14
- for subdir in ("agents", "prompts", "commands", "output-styles", "rules", "scripts", "hooks"):
13
+ # Clean top-level asset dirs + legacy claudekit/ from pre-v0.2.3
14
+ for subdir in ("agents", "prompts", "commands", "output-styles", "rules", "scripts", "hooks", "claudekit"):
15
15
  target = codex_home / subdir
16
16
  if target.exists():
17
17
  count = sum(1 for item in target.rglob("*") if item.is_file())
@@ -22,7 +22,7 @@ from .config_enforcer import (
22
22
  )
23
23
  from .dep_bootstrapper import bootstrap_deps
24
24
  from .path_normalizer import normalize_agent_tomls, normalize_files
25
- from .prompt_exporter import export_prompts
25
+ from .rules_generator import generate_hook_rules
26
26
  from .runtime_verifier import verify_runtime
27
27
  from .source_resolver import detect_claude_source, find_latest_zip, validate_source
28
28
  from .sync_registry import load_registry, save_registry
@@ -162,6 +162,9 @@ def main() -> int:
162
162
  changed = normalize_files(codex_home=codex_home, include_mcp=args.mcp, dry_run=args.dry_run)
163
163
  print(f"normalize_changed={changed}")
164
164
 
165
+ rules_generated = generate_hook_rules(codex_home=codex_home, dry_run=args.dry_run)
166
+ print(f"hook_rules_generated={rules_generated}")
167
+
165
168
  # enforce_config BEFORE register_agents — enforce_config rewrites config.toml
166
169
  baseline_changed = 0
167
170
  if ensure_agents(workspace=workspace, dry_run=args.dry_run):
@@ -185,9 +188,6 @@ def main() -> int:
185
188
  agents_registered = register_agents(codex_home=codex_home, dry_run=args.dry_run)
186
189
  print(f"agents_registered={agents_registered}")
187
190
 
188
- prompt_stats = export_prompts(codex_home=codex_home, include_mcp=args.mcp, dry_run=args.dry_run)
189
- print(f"prompts: added={prompt_stats['added']} total={prompt_stats['total_generated']}")
190
-
191
191
  bootstrap_stats = None
192
192
  if not args.no_deps:
193
193
  bootstrap_stats = bootstrap_deps(
@@ -219,7 +219,7 @@ def main() -> int:
219
219
  "normalize_changed": changed,
220
220
  "agent_toml_changed": agent_toml_changed,
221
221
  "agents_registered": agents_registered,
222
- "prompts": prompt_stats,
222
+ "rules_generated": rules_generated,
223
223
  "bootstrap": bootstrap_stats,
224
224
  "verify": verify_stats,
225
225
  }
@@ -2,9 +2,10 @@
2
2
 
3
3
  from typing import List, Set, Tuple
4
4
 
5
- ASSET_DIRS = {"commands", "output-styles", "rules", "scripts", "hooks"}
5
+ ASSET_DIRS = {"output-styles", "rules", "scripts"}
6
6
  ASSET_FILES = {".env.example", ".ck.json"}
7
7
  ASSET_MANIFEST = ".sync-manifest-assets.txt"
8
+ # DEPRECATED: prompt_exporter.py no longer called from CLI pipeline (v0.2.5)
8
9
  PROMPT_MANIFEST = ".claudekit-generated-prompts.txt"
9
10
  REGISTRY_FILE = ".claudekit-sync-registry.json"
10
11
 
@@ -67,6 +68,9 @@ CLAUDE_SYNTAX_ADAPTATIONS: List[Tuple[str, str]] = [
67
68
  ("Task(researcher)", "the researcher agent"),
68
69
  ("Task(", "delegate to "),
69
70
  ("$HOME/.claude/skills/*", "${CODEX_HOME:-$HOME/.codex}/skills/*"),
71
+ ("via Task tool", "via agent delegation"),
72
+ ("Claude Code", "Codex CLI"),
73
+ ("claude code", "Codex CLI"),
70
74
  ]
71
75
 
72
76
  # Claude model → Codex model mapping (per developers.openai.com/codex/multi-agent)
@@ -0,0 +1,31 @@
1
+ """Generate hook-equivalent rules from templates."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ from .utils import load_template, write_text_if_changed
8
+
9
+
10
+ RULE_TEMPLATES = {
11
+ "security-privacy.md": "rule-security-privacy.md",
12
+ "file-naming.md": "rule-file-naming.md",
13
+ "code-quality-reminders.md": "rule-code-quality.md",
14
+ }
15
+
16
+
17
+ def generate_hook_rules(*, codex_home: Path, dry_run: bool) -> int:
18
+ """Generate rules that replace ClaudeKit hook behavior."""
19
+ rules_dir = codex_home / "rules"
20
+ if not dry_run:
21
+ rules_dir.mkdir(parents=True, exist_ok=True)
22
+
23
+ generated = 0
24
+ for rule_name, template_name in RULE_TEMPLATES.items():
25
+ content = load_template(template_name)
26
+ target = rules_dir / rule_name
27
+ if write_text_if_changed(target, content, dry_run=dry_run):
28
+ generated += 1
29
+ print(f"upsert: rules/{rule_name}")
30
+
31
+ return generated
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  name: claudekit-command-bridge
3
- description: Bridge legacy ClaudeKit commands to Codex-native workflows. Use when users mention /ck-help, /coding-level, /ask, /docs/*, /journal, /watzup, or ask for Claude command equivalents.
3
+ description: Bridge legacy ClaudeKit slash commands to Codex-native skills. Activates when users mention /ck-help, /coding-level, /ask, /docs/*, /journal, /watzup, or ask for Claude command equivalents.
4
4
  ---
5
5
 
6
- # ClaudeKit Command Bridge
6
+ # ClaudeKit Codex Bridge
7
7
 
8
- Translate ClaudeKit command intent into Codex skills/workflows.
8
+ Translate ClaudeKit command intent into Codex-native skills.
9
9
 
10
10
  ## Quick Mapping
11
11
 
@@ -0,0 +1,10 @@
1
+ # Code Quality Reminders
2
+
3
+ ## Code Simplification
4
+ After significant file edits (5+), consider running code-simplifier agent.
5
+
6
+ ## Post-Planning
7
+ After creating an implementation plan, always activate the cook skill before implementation.
8
+
9
+ ## Modularization
10
+ If a code file exceeds 200 lines, consider modularizing it.
@@ -0,0 +1,7 @@
1
+ # File Naming
2
+
3
+ Apply before every file creation (skip for markdown/text):
4
+ - **JS/TS/Python/shell**: kebab-case with descriptive names
5
+ - **C#/Java/Kotlin/Swift**: PascalCase
6
+ - **Go/Rust**: snake_case
7
+ - Goal: self-documenting names for LLM tools (Grep, Glob, Search)
@@ -0,0 +1,15 @@
1
+ # Security & Privacy
2
+
3
+ ## Sensitive File Access
4
+ Ask user for explicit approval before reading:
5
+ - `.env`, `.env.*` (API keys, passwords, tokens)
6
+ - `*.key`, `*.pem`, `*.p12`, `credentials.*`, `secrets.*`
7
+ - Files in `~/.ssh/`, `~/.gnupg/`, `~/.aws/`
8
+
9
+ **Flow:** State which file and why → wait for "yes" → read via cat → never output full secrets.
10
+
11
+ ## Directory Access Control
12
+ Respect `.ckignore` patterns if present in project root:
13
+ - Read `.ckignore` at session start
14
+ - Do NOT access matching directories
15
+ - Common: `node_modules/`, `dist/`, `build/`, `.git/objects/`
@@ -0,0 +1,28 @@
1
+ """Tests for rules_generator module."""
2
+
3
+ from pathlib import Path
4
+
5
+ from claudekit_codex_sync.rules_generator import generate_hook_rules
6
+
7
+
8
+ def test_generates_all_rule_files(tmp_path: Path):
9
+ """Generates 3 rule files."""
10
+ count = generate_hook_rules(codex_home=tmp_path, dry_run=False)
11
+ assert count == 3
12
+ assert (tmp_path / "rules" / "security-privacy.md").exists()
13
+ assert (tmp_path / "rules" / "file-naming.md").exists()
14
+ assert (tmp_path / "rules" / "code-quality-reminders.md").exists()
15
+
16
+
17
+ def test_idempotent(tmp_path: Path):
18
+ """Second run returns 0 (no changes)."""
19
+ generate_hook_rules(codex_home=tmp_path, dry_run=False)
20
+ count = generate_hook_rules(codex_home=tmp_path, dry_run=False)
21
+ assert count == 0
22
+
23
+
24
+ def test_dry_run(tmp_path: Path):
25
+ """Dry run counts but doesn't create."""
26
+ count = generate_hook_rules(codex_home=tmp_path, dry_run=True)
27
+ assert count == 3
28
+ assert not (tmp_path / "rules").exists()