diff --git a/setup_codex.py b/setup_codex.py index 6be864f..3bdcaca 100644 --- a/setup_codex.py +++ b/setup_codex.py @@ -13,7 +13,7 @@ import subprocess from pathlib import Path -from utils import adapt_instructions_file, ensure_https, get_gateway_host, get_npm_version +from utils import adapt_instructions_file, ensure_https, get_gateway_host, get_npm_version, mirror_claude_skills # Set HOME if not properly set if not os.environ.get("HOME") or os.environ["HOME"] == "/": @@ -93,6 +93,9 @@ codex_dir = home / ".codex" codex_dir.mkdir(exist_ok=True) +# Mirror Claude skills into ~/.codex/skills so Codex sees the same skill content +mirror_claude_skills(codex_dir / "skills", "Codex") + # Copy bundled Databricks model catalog into ~/.codex so it can be referenced # by relative path in config.toml (codex resolves relatives against CODEX_HOME). catalog_src = Path(__file__).parent / ".codex" / "databricks-models.json" diff --git a/setup_hermes.py b/setup_hermes.py index 07bb030..5291b34 100644 --- a/setup_hermes.py +++ b/setup_hermes.py @@ -25,7 +25,7 @@ import subprocess from pathlib import Path -from utils import adapt_instructions_file, ensure_https, get_gateway_host +from utils import adapt_instructions_file, ensure_https, get_gateway_host, mirror_claude_skills # Opt-out: allow operators to disable Hermes bundling without removing the file. if os.environ.get("ENABLE_HERMES", "true").strip().lower() in ("false", "0", "no"): @@ -58,6 +58,9 @@ local_bin.mkdir(parents=True, exist_ok=True) hermes_home.mkdir(parents=True, exist_ok=True) +# Mirror Claude skills into ~/.hermes/skills so Hermes sees the same skill content +mirror_claude_skills(hermes_home / "skills", "Hermes") + def _run(cmd, **kwargs): """Run a subprocess command and return (rc, stdout, stderr).""" diff --git a/setup_opencode.py b/setup_opencode.py index 071252a..729d242 100644 --- a/setup_opencode.py +++ b/setup_opencode.py @@ -11,7 +11,7 @@ import subprocess from pathlib import Path -from utils import ensure_https, get_gateway_host, get_npm_version +from utils import ensure_https, get_gateway_host, get_npm_version, mirror_claude_skills # content-filter proxy local proxy — sanitizes empty content blocks before reaching Databricks # (see https://github.com/sst/opencode/issues/5028) @@ -278,6 +278,9 @@ opencode_data_dir = home / ".local" / "share" / "opencode" opencode_data_dir.mkdir(parents=True, exist_ok=True) +# Mirror Claude skills into ~/.local/share/opencode/skills so OpenCode sees them +mirror_claude_skills(opencode_data_dir / "skills", "OpenCode") + if gateway_host: auth_data = { "databricks": { diff --git a/utils.py b/utils.py index 94237bf..af26ab9 100644 --- a/utils.py +++ b/utils.py @@ -4,10 +4,29 @@ import os import re +import shutil import subprocess from pathlib import Path +def mirror_claude_skills(target_dir: Path, agent_name: str) -> None: + """Mirror ~/.claude/skills into ``target_dir`` so non-Claude agents see them. + + Replaces ``target_dir`` if it already exists (idempotent across restarts). + Resolves the Claude skills directory via ``HOME``, falling back to a no-op + if nothing is there (the same shape `setup_gemini.py` uses for Gemini). + """ + home = Path(os.environ.get("HOME", "/app/python/source_code")) + claude_skills_dir = home / ".claude" / "skills" + if not claude_skills_dir.exists(): + print(f"No Claude skills at {claude_skills_dir}, skipping {agent_name} mirror") + return + if target_dir.exists(): + shutil.rmtree(target_dir) + shutil.copytree(claude_skills_dir, target_dir) + print(f"Skills mirrored: {claude_skills_dir} -> {target_dir}") + + def get_npm_version(package_name): """Resolve the latest stable version of an npm package.