claudekit-codex-sync 0.1.0 → 0.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.
Files changed (33) hide show
  1. package/README.md +76 -59
  2. package/docs/codebase-summary.md +40 -43
  3. package/docs/codex-vs-claude-agents.md +53 -42
  4. package/docs/installation-guide.md +67 -23
  5. package/docs/project-overview-pdr.md +20 -26
  6. package/docs/project-roadmap.md +26 -32
  7. package/docs/system-architecture.md +45 -82
  8. package/package.json +4 -3
  9. package/plans/260223-1310-v02-cli-redesign-cleanup/phase-01-delete-dead-code.md +88 -0
  10. package/plans/260223-1310-v02-cli-redesign-cleanup/phase-02-cli-redesign.md +316 -0
  11. package/plans/260223-1310-v02-cli-redesign-cleanup/phase-03-symlink-venv.md +148 -0
  12. package/plans/260223-1310-v02-cli-redesign-cleanup/phase-04-wire-unused-functions.md +151 -0
  13. package/plans/260223-1310-v02-cli-redesign-cleanup/phase-05-safety-tests-docs.md +206 -0
  14. package/plans/260223-1310-v02-cli-redesign-cleanup/plan.md +18 -0
  15. package/plans/reports/planner-260223-v02-cli-redesign-cleanup-validation.md +95 -0
  16. package/plans/reports/project-manager-260223-v02-cli-redesign-cleanup-finalization.md +28 -0
  17. package/src/claudekit_codex_sync/asset_sync_dir.py +60 -9
  18. package/src/claudekit_codex_sync/asset_sync_zip.py +16 -5
  19. package/src/claudekit_codex_sync/clean_target.py +49 -0
  20. package/src/claudekit_codex_sync/cli.py +113 -81
  21. package/src/claudekit_codex_sync/constants.py +2 -13
  22. package/src/claudekit_codex_sync/dep_bootstrapper.py +71 -29
  23. package/src/claudekit_codex_sync/path_normalizer.py +2 -0
  24. package/src/claudekit_codex_sync/source_resolver.py +10 -2
  25. package/src/claudekit_codex_sync/sync_registry.py +1 -0
  26. package/templates/agents-md.md +5 -8
  27. package/tests/test_clean_target.py +55 -0
  28. package/tests/test_cli_args.py +57 -0
  29. package/reports/brainstorm-260222-2051-claudekit-codex-community-sync.md +0 -113
  30. package/scripts/bootstrap-claudekit-skill-scripts.sh +0 -150
  31. package/scripts/claudekit-sync-all.py +0 -1150
  32. package/scripts/export-claudekit-prompts.sh +0 -221
  33. package/scripts/normalize-claudekit-for-codex.sh +0 -261
@@ -41,7 +41,7 @@ def detect_claude_source() -> Path:
41
41
  for p in candidates:
42
42
  if p.exists() and (p / "skills").is_dir():
43
43
  return p
44
- raise SyncError("Claude Code not found. Use --source-dir to specify.")
44
+ raise SyncError("Claude Code not found. Use --source to specify.")
45
45
 
46
46
 
47
47
  def validate_source(source: Path) -> Dict[str, bool]:
@@ -61,11 +61,19 @@ def collect_skill_entries(zf: zipfile.ZipFile) -> Dict[str, List[Tuple[str, str]
61
61
  for name in zf.namelist():
62
62
  if name.endswith("/") or not name.startswith(".claude/skills/"):
63
63
  continue
64
- rel = name[len(".claude/skills/") :]
64
+ rel = name[len(".claude/skills/") :].replace("\\", "/")
65
+ path = Path(rel)
66
+ if path.is_absolute() or ".." in path.parts:
67
+ raise SyncError(f"Unsafe zip entry path: {name}")
65
68
  parts = rel.split("/", 1)
66
69
  if len(parts) != 2:
67
70
  continue
68
71
  skill, inner = parts
72
+ inner_path = Path(inner)
73
+ if Path(skill).is_absolute() or ".." in Path(skill).parts:
74
+ raise SyncError(f"Unsafe skill name in zip entry: {name}")
75
+ if inner_path.is_absolute() or ".." in inner_path.parts:
76
+ raise SyncError(f"Unsafe skill file path in zip entry: {name}")
69
77
  skill_files.setdefault(skill, []).append((name, inner))
70
78
  return skill_files
71
79
 
@@ -28,6 +28,7 @@ def load_registry(codex_home: Path) -> Dict[str, Any]:
28
28
  def save_registry(codex_home: Path, registry: Dict[str, Any]) -> None:
29
29
  """Save sync registry to disk."""
30
30
  registry_path = codex_home / REGISTRY_FILE
31
+ registry_path.parent.mkdir(parents=True, exist_ok=True)
31
32
  registry["lastSync"] = datetime.now(timezone.utc).isoformat()
32
33
  registry_path.write_text(json.dumps(registry, indent=2), encoding="utf-8")
33
34
 
@@ -35,11 +35,8 @@ Codex working profile for this workspace, adapted from ClaudeKit rules and workf
35
35
  - Activate relevant skills intentionally per task.
36
36
  - For legacy ClaudeKit command intents (`/ck-help`, `/coding-level`, `/ask`, `/docs/*`, `/journal`, `/watzup`), use `$claudekit-command-bridge`.
37
37
 
38
- ## Reference Material (Imported from ClaudeKit)
39
-
40
- - `~/.codex/claudekit/CLAUDE.md`
41
- - `~/.codex/claudekit/rules/development-rules.md`
42
- - `~/.codex/claudekit/rules/primary-workflow.md`
43
- - `~/.codex/claudekit/rules/orchestration-protocol.md`
44
- - `~/.codex/claudekit/rules/documentation-management.md`
45
- - `~/.codex/claudekit/rules/team-coordination-rules.md`
38
+ ## Reference Material
39
+
40
+ - `README.md`
41
+ - `docs/`
42
+ - `plans/`
@@ -0,0 +1,55 @@
1
+ """Tests for clean_target module."""
2
+
3
+ import json
4
+ from pathlib import Path
5
+
6
+ from claudekit_codex_sync.clean_target import clean_target
7
+
8
+
9
+ def test_clean_removes_agents(tmp_path: Path):
10
+ """Clean removes agents dir."""
11
+ agents = tmp_path / "agents"
12
+ agents.mkdir()
13
+ (agents / "planner.toml").write_text("model = 'test'")
14
+ (agents / "researcher.toml").write_text("model = 'test'")
15
+
16
+ removed = clean_target(tmp_path, dry_run=False)
17
+ assert not agents.exists()
18
+ assert removed >= 2
19
+
20
+
21
+ def test_clean_keeps_venv(tmp_path: Path):
22
+ """Clean keeps skills/.venv intact."""
23
+ skills = tmp_path / "skills"
24
+ skills.mkdir()
25
+ venv = skills / ".venv"
26
+ venv.mkdir()
27
+ (venv / "bin").mkdir()
28
+ (venv / "bin" / "python3").write_text("#!/usr/bin/env python3")
29
+ skill = skills / "my-skill"
30
+ skill.mkdir()
31
+ (skill / "SKILL.md").write_text("# test")
32
+
33
+ clean_target(tmp_path, dry_run=False)
34
+ assert venv.exists(), ".venv should survive cleaning"
35
+ assert not skill.exists(), "skill dirs should be removed"
36
+
37
+
38
+ def test_clean_dry_run(tmp_path: Path):
39
+ """Dry run counts but doesn't delete."""
40
+ agents = tmp_path / "agents"
41
+ agents.mkdir()
42
+ (agents / "test.toml").write_text("x = 1")
43
+
44
+ removed = clean_target(tmp_path, dry_run=True)
45
+ assert removed >= 1
46
+ assert agents.exists(), "dry-run should not delete"
47
+
48
+
49
+ def test_clean_removes_registry(tmp_path: Path):
50
+ """Clean clears sync registry."""
51
+ registry = tmp_path / ".claudekit-sync-registry.json"
52
+ registry.write_text(json.dumps({"version": 1}))
53
+
54
+ clean_target(tmp_path, dry_run=False)
55
+ assert not registry.exists()
@@ -0,0 +1,57 @@
1
+ """Tests for CLI argument parsing."""
2
+
3
+ import sys
4
+ from unittest.mock import patch
5
+
6
+ from claudekit_codex_sync.cli import parse_args
7
+
8
+
9
+ def test_default_args():
10
+ """Default: project scope, no flags."""
11
+ with patch.object(sys, "argv", ["ckc-sync"]):
12
+ args = parse_args()
13
+ assert not args.global_scope
14
+ assert not args.fresh
15
+ assert not args.force
16
+ assert not args.mcp
17
+ assert not args.no_deps
18
+ assert not args.dry_run
19
+ assert args.zip_path is None
20
+ assert args.source is None
21
+
22
+
23
+ def test_global_flag():
24
+ """'-g' enables global scope."""
25
+ with patch.object(sys, "argv", ["ckc-sync", "-g"]):
26
+ args = parse_args()
27
+ assert args.global_scope
28
+
29
+
30
+ def test_fresh_flag():
31
+ """'-f' enables fresh clean."""
32
+ with patch.object(sys, "argv", ["ckc-sync", "-f"]):
33
+ args = parse_args()
34
+ assert args.fresh
35
+
36
+
37
+ def test_combined_short_flags():
38
+ """'-g -f -n' all work together."""
39
+ with patch.object(sys, "argv", ["ckc-sync", "-g", "-f", "-n"]):
40
+ args = parse_args()
41
+ assert args.global_scope
42
+ assert args.fresh
43
+ assert args.dry_run
44
+
45
+
46
+ def test_zip_flag():
47
+ """'--zip' sets zip path and implies zip mode."""
48
+ with patch.object(sys, "argv", ["ckc-sync", "--zip", "test.zip"]):
49
+ args = parse_args()
50
+ assert str(args.zip_path) == "test.zip"
51
+
52
+
53
+ def test_mcp_flag():
54
+ """'--mcp' includes MCP skills."""
55
+ with patch.object(sys, "argv", ["ckc-sync", "--mcp"]):
56
+ args = parse_args()
57
+ assert args.mcp
@@ -1,113 +0,0 @@
1
- # Brainstorm Report: ClaudeKit -> Codex Community Toolkit
2
-
3
- ## Problem Statement
4
- You want a community-shareable toolkit that syncs ClaudeKit assets into Codex with minimal manual work, supports latest zip detection, and proves behavior is close to Claude workflows.
5
-
6
- ## Requirements
7
- - Full-auto sync entrypoint (latest zip auto-select).
8
- - Pull from both zip and local `~/.claude` where needed.
9
- - Keep current exclusions default (`mcp`, `hooks`) but support opt-in.
10
- - Add agent-role sync compatible with Codex multi-agent system.
11
- - Publish for community consumption via:
12
- - `npm`/`npx` install path.
13
- - `git clone` + local run path.
14
- - Provide evidence that behavior is close to ClaudeKit orchestration (not only file-copy parity).
15
-
16
- ## Current Reality Check
17
- - Current script (`~/.codex/scripts/claudekit-sync-all.py`) is strong for assets/skills/rules/prompts sync.
18
- - It is not yet productized as a public package.
19
- - It does not yet implement Claude-agent -> Codex-agent role transpilation + parity benchmark harness.
20
- - Behavior parity is therefore not yet provable by metrics.
21
-
22
- ## Approaches Evaluated
23
-
24
- ### Approach A: Keep Python Core + Add NPM Wrapper (Recommended for v1)
25
- Pros:
26
- - Fastest to ship.
27
- - Reuses proven sync logic now.
28
- - Lower regression risk.
29
- - Easy to support both `npx` and `python3` direct run.
30
-
31
- Cons:
32
- - Requires Python on user machine.
33
- - Wrapper layer adds runtime dependency checks.
34
-
35
- ### Approach B: Full Rewrite to TypeScript Core
36
- Pros:
37
- - Native npm experience.
38
- - Simpler JS ecosystem integration.
39
-
40
- Cons:
41
- - High rewrite cost.
42
- - High regression risk in edge behavior already solved in Python.
43
- - Slower time-to-community release.
44
-
45
- ### Approach C: Maintain Two Cores (Python + TS)
46
- Pros:
47
- - Maximum flexibility.
48
-
49
- Cons:
50
- - Highest maintenance burden.
51
- - Divergence risk.
52
- - Not YAGNI.
53
-
54
- ## Recommended Strategy
55
- - **Ship staged hybrid strategy**:
56
- 1. **v1**: Python core as source of truth + npm wrapper + git-clone workflow.
57
- 2. **v1.1**: Add agent transpiler and parity benchmark harness.
58
- 3. **v2**: Consider TS native core only if adoption justifies rewrite.
59
-
60
- This gives speed now and keeps path to long-term polish without over-engineering.
61
-
62
- ## Claude -> Codex Customization That Matters Most
63
- - Agent transpiler that converts Claude `agents/*.md` into Codex role config:
64
- - `~/.codex/config.toml` `[agents.<role>]`
65
- - `~/.codex/agents/<role>.toml`
66
- - Role strategy:
67
- - Prefix custom roles (`ck-*`) to avoid overriding built-ins accidentally.
68
- - Allow explicit override mode if user wants `default/worker/explorer` replacement.
69
- - Instruction normalization:
70
- - rewrite Claude-specific paths/tooling references to Codex equivalents.
71
- - preserve intent, not literal syntax.
72
- - Execution guardrails:
73
- - per-role `sandbox_mode`, `model_reasoning_effort`, `developer_instructions`.
74
-
75
- ## Proof Plan: “Near-Similar Behavior”
76
- Define parity suite and publish numbers:
77
- - 20-30 canonical scenarios:
78
- - planning, research, review, debug, docs update, testing loops.
79
- - A/B runs:
80
- - A: Claude original flow.
81
- - B: Codex transpiled flow.
82
- - Score dimensions:
83
- - task success rate.
84
- - required artifact completeness.
85
- - policy compliance (test/lint/docs gates).
86
- - orchestration quality (spawn/wait/close behavior).
87
- - defect quality (severity-weighted findings for review/debug cases).
88
-
89
- Target thresholds:
90
- - >=85% parity: acceptable “near-similar”.
91
- - >=90% parity: strong community-grade claim.
92
-
93
- ## Risks and Mitigations
94
- - Risk: Codex/Claude runtime semantics differ.
95
- - Mitigation: parity scoring by outcomes, not literal step parity.
96
- - Risk: multi-agent feature drift across Codex versions.
97
- - Mitigation: version compatibility matrix + CI smoke tests.
98
- - Risk: wrapper install friction.
99
- - Mitigation: clear preflight checks + actionable errors.
100
-
101
- ## Success Metrics
102
- - Install success rate >=95% on Ubuntu/macOS/WSL for default path.
103
- - End-to-end sync success rate >=98% on supported fixtures.
104
- - Parity benchmark >=85% before public “near-similar” claim.
105
- - Time to run full sync + verify under 3 minutes on standard machine.
106
-
107
- ## Next Steps
108
- - Create implementation plan with phases for:
109
- - productization,
110
- - transpiler,
111
- - benchmark harness,
112
- - npm + git distribution,
113
- - release process.
@@ -1,150 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
5
- SKILLS_DIR="${CODEX_HOME}/skills"
6
- VENV_DIR="${SKILLS_DIR}/.venv"
7
- RUN_PYTHON=true
8
- RUN_NODE=true
9
- DRY_RUN=false
10
- INCLUDE_TEST_DEPS=false
11
- INCLUDE_MCP=false
12
-
13
- usage() {
14
- cat <<'EOF'
15
- Install runtime dependencies for ClaudeKit skills synced into Codex.
16
-
17
- Usage:
18
- bootstrap-claudekit-skill-scripts.sh [options]
19
-
20
- Options:
21
- --python-only Install Python dependencies only
22
- --node-only Install Node.js dependencies only
23
- --include-test-deps Also install requirements from test folders
24
- --include-mcp Also include mcp-builder and mcp-management skills
25
- --dry-run Print actions only
26
- -h, --help Show help
27
- EOF
28
- }
29
-
30
- while [[ $# -gt 0 ]]; do
31
- case "$1" in
32
- --python-only)
33
- RUN_PYTHON=true
34
- RUN_NODE=false
35
- ;;
36
- --node-only)
37
- RUN_PYTHON=false
38
- RUN_NODE=true
39
- ;;
40
- --include-test-deps)
41
- INCLUDE_TEST_DEPS=true
42
- ;;
43
- --include-mcp)
44
- INCLUDE_MCP=true
45
- ;;
46
- --dry-run)
47
- DRY_RUN=true
48
- ;;
49
- -h|--help)
50
- usage
51
- exit 0
52
- ;;
53
- *)
54
- echo "Unknown option: $1" >&2
55
- usage >&2
56
- exit 1
57
- ;;
58
- esac
59
- shift
60
- done
61
-
62
- if [[ ! -d "$SKILLS_DIR" ]]; then
63
- echo "Skills directory not found: $SKILLS_DIR" >&2
64
- exit 1
65
- fi
66
-
67
- py_ok=0
68
- py_fail=0
69
- node_ok=0
70
- node_fail=0
71
-
72
- skip_mcp_path() {
73
- local p="$1"
74
- if [[ "$INCLUDE_MCP" == true ]]; then
75
- return 1
76
- fi
77
- [[ "$p" == *"/mcp-builder/"* || "$p" == *"/mcp-management/"* ]]
78
- }
79
-
80
- if [[ "$RUN_PYTHON" == true ]]; then
81
- if ! command -v python3 >/dev/null 2>&1; then
82
- echo "python3 not found" >&2
83
- exit 1
84
- fi
85
-
86
- if [[ "$DRY_RUN" == true ]]; then
87
- echo "[dry-run] python3 -m venv \"$VENV_DIR\""
88
- else
89
- python3 -m venv "$VENV_DIR"
90
- "$VENV_DIR/bin/python3" -m pip install --upgrade pip >/dev/null
91
- fi
92
-
93
- while IFS= read -r req; do
94
- if skip_mcp_path "$req"; then
95
- continue
96
- fi
97
- if [[ "$DRY_RUN" == true ]]; then
98
- echo "[dry-run] $VENV_DIR/bin/python3 -m pip install -r \"$req\""
99
- py_ok=$((py_ok + 1))
100
- continue
101
- fi
102
- if "$VENV_DIR/bin/python3" -m pip install -r "$req" >/dev/null; then
103
- py_ok=$((py_ok + 1))
104
- else
105
- echo "python deps failed: $req" >&2
106
- py_fail=$((py_fail + 1))
107
- fi
108
- done < <(
109
- find "$SKILLS_DIR" \
110
- \( -path '*/.system/*' -o -path '*/node_modules/*' -o -path '*/.venv/*' -o -path '*/dist/*' -o -path '*/build/*' \) -prune -o \
111
- -type f -name 'requirements*.txt' -print \
112
- | if [[ "$INCLUDE_TEST_DEPS" == true ]]; then cat; else grep -Ev '/tests?/'; fi \
113
- | sort -u
114
- )
115
- fi
116
-
117
- if [[ "$RUN_NODE" == true ]]; then
118
- if ! command -v npm >/dev/null 2>&1; then
119
- echo "npm not found" >&2
120
- exit 1
121
- fi
122
-
123
- while IFS= read -r pkg; do
124
- if skip_mcp_path "$pkg"; then
125
- continue
126
- fi
127
- dir="$(dirname "$pkg")"
128
- if [[ "$DRY_RUN" == true ]]; then
129
- echo "[dry-run] npm install --prefix \"$dir\""
130
- node_ok=$((node_ok + 1))
131
- continue
132
- fi
133
- if npm install --prefix "$dir" >/dev/null; then
134
- node_ok=$((node_ok + 1))
135
- else
136
- echo "node deps failed: $dir" >&2
137
- node_fail=$((node_fail + 1))
138
- fi
139
- done < <(
140
- find "$SKILLS_DIR" \
141
- \( -path '*/.system/*' -o -path '*/node_modules/*' -o -path '*/.venv/*' -o -path '*/dist/*' -o -path '*/build/*' \) -prune -o \
142
- -type f -name package.json -print \
143
- | sort -u
144
- )
145
- fi
146
-
147
- echo "python_ok=$py_ok python_fail=$py_fail node_ok=$node_ok node_fail=$node_fail"
148
- if [[ $py_fail -gt 0 || $node_fail -gt 0 ]]; then
149
- exit 2
150
- fi