mirror of
https://github.com/itme-brain/agent-team.git
synced 2026-05-08 13:50:12 -04:00
feat: add Codex CLI compatibility layer
- flake.nix: devShell with yq-go for config generation - generate-codex.sh: generates Codex agent TOML, AGENTS.md, and config.toml from Claude source files (idempotent, yq-powered) - install.sh: optional Codex symlinks when ~/.codex exists (skills shared via ~/.agents/skills/, agents/config/AGENTS.md to ~/.codex/) - .gitignore: exclude generated codex/ directory - README.md: document Codex compatibility setup and model mapping
This commit is contained in:
parent
8d08f9650c
commit
d812c7f49a
6 changed files with 287 additions and 0 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -8,3 +8,6 @@ settings.local.json
|
||||||
# OS noise
|
# OS noise
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
|
||||||
|
# Generated Codex CLI config (derived from Claude source files via generate-codex.sh)
|
||||||
|
codex/
|
||||||
|
|
|
||||||
29
README.md
29
README.md
|
|
@ -59,6 +59,35 @@ For simple tasks, agents can be invoked directly:
|
||||||
/agent worker Fix the broken pagination in the user list endpoint
|
/agent worker Fix the broken pagination in the user list endpoint
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Codex CLI compatibility
|
||||||
|
|
||||||
|
This project also generates configuration for [OpenAI Codex CLI](https://github.com/openai/codex). Claude Code config is the source of truth; Codex config is derived from it.
|
||||||
|
|
||||||
|
### Setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix develop # enter devShell with yq
|
||||||
|
./generate-codex.sh # generate Codex config from Claude source files
|
||||||
|
./install.sh # installs both Claude and Codex (if ~/.codex exists)
|
||||||
|
```
|
||||||
|
|
||||||
|
### What gets generated
|
||||||
|
|
||||||
|
| Source | Generated | Codex location |
|
||||||
|
|---|---|---|
|
||||||
|
| `agents/*.md` | `codex/agents/*.toml` | `~/.codex/agents/` |
|
||||||
|
| `CLAUDE.md` + `rules/*.md` | `codex/AGENTS.md` | `~/.codex/AGENTS.md` |
|
||||||
|
| `settings.json` | `codex/config.toml` | `~/.codex/config.toml` |
|
||||||
|
| `skills/` | (shared as-is) | `~/.agents/skills/` |
|
||||||
|
|
||||||
|
### Model mapping
|
||||||
|
|
||||||
|
| Claude Code | Codex CLI |
|
||||||
|
|---|---|
|
||||||
|
| `opus` | `o3` |
|
||||||
|
| `sonnet` | `o4-mini` |
|
||||||
|
| `haiku` | `o4-mini` |
|
||||||
|
|
||||||
## Project-specific config
|
## Project-specific config
|
||||||
|
|
||||||
Each project repo can extend the team with local config in `.claude/`:
|
Each project repo can extend the team with local config in `.claude/`:
|
||||||
|
|
|
||||||
27
flake.lock
generated
Normal file
27
flake.lock
generated
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1775095191,
|
||||||
|
"narHash": "sha256-CsqRiYbgQyv01LS0NlC7shwzhDhjNDQSrhBX8VuD3nM=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "106eb93cbb9d4e4726bf6bc367a3114f7ed6b32f",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
14
flake.nix
Normal file
14
flake.nix
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||||
|
outputs = { nixpkgs, ... }:
|
||||||
|
let
|
||||||
|
systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
|
||||||
|
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f nixpkgs.legacyPackages.${system});
|
||||||
|
in {
|
||||||
|
devShells = forAllSystems (pkgs: {
|
||||||
|
default = pkgs.mkShell {
|
||||||
|
packages = [ pkgs.yq-go ];
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
184
generate-codex.sh
Executable file
184
generate-codex.sh
Executable file
|
|
@ -0,0 +1,184 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# generate-codex.sh — generates Codex CLI config from Claude source files.
|
||||||
|
# Claude source files are the source of truth; this script derives Codex equivalents.
|
||||||
|
# Idempotent: safe to run multiple times.
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
CODEX_DIR="$SCRIPT_DIR/codex"
|
||||||
|
CODEX_AGENTS_DIR="$CODEX_DIR/agents"
|
||||||
|
AGENTS_SRC="$SCRIPT_DIR/agents"
|
||||||
|
RULES_DIR="$SCRIPT_DIR/rules"
|
||||||
|
CLAUDE_MD="$SCRIPT_DIR/CLAUDE.md"
|
||||||
|
SETTINGS_JSON="$SCRIPT_DIR/settings.json"
|
||||||
|
|
||||||
|
# Create output directories
|
||||||
|
mkdir -p "$CODEX_DIR"
|
||||||
|
mkdir -p "$CODEX_AGENTS_DIR"
|
||||||
|
|
||||||
|
# Clean existing generated agent TOMLs
|
||||||
|
rm -f "$CODEX_AGENTS_DIR"/*.toml
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# map_model — maps Claude model name to Codex model name
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
map_model() {
|
||||||
|
local model="$1"
|
||||||
|
case "$model" in
|
||||||
|
opus) echo "o3" ;;
|
||||||
|
sonnet) echo "o4-mini" ;;
|
||||||
|
haiku) echo "o4-mini" ;;
|
||||||
|
*) echo "o4-mini" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# map_effort — maps Claude effort level to Codex model_reasoning_effort
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
map_effort() {
|
||||||
|
local effort="$1"
|
||||||
|
case "$effort" in
|
||||||
|
low) echo "low" ;;
|
||||||
|
medium) echo "medium" ;;
|
||||||
|
high) echo "high" ;;
|
||||||
|
max) echo "xhigh" ;;
|
||||||
|
*) echo "medium" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# map_sandbox_mode — determines Codex sandbox_mode from agent frontmatter
|
||||||
|
# $1 = permissionMode value (plan / acceptEdits / "")
|
||||||
|
# $2 = tools list (comma-separated)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
map_sandbox_mode() {
|
||||||
|
local permission_mode="$1"
|
||||||
|
local tools="$2"
|
||||||
|
|
||||||
|
# plan mode is read-only
|
||||||
|
if [ "$permission_mode" = "plan" ]; then
|
||||||
|
echo "read-only"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# acceptEdits with Write or Edit tool → workspace-write
|
||||||
|
if [ "$permission_mode" = "acceptEdits" ]; then
|
||||||
|
if echo "$tools" | grep -qE '\b(Write|Edit)\b'; then
|
||||||
|
echo "workspace-write"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Default: read-only
|
||||||
|
echo "read-only"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# generate_agent_toml — converts a single agent .md file to Codex .toml
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
generate_agent_toml() {
|
||||||
|
local src_file="$1"
|
||||||
|
local agent_basename
|
||||||
|
agent_basename="$(basename "$src_file" .md)"
|
||||||
|
local dst_file="$CODEX_AGENTS_DIR/${agent_basename}.toml"
|
||||||
|
|
||||||
|
# Extract YAML frontmatter using yq
|
||||||
|
local frontmatter
|
||||||
|
frontmatter="$(yq --front-matter=extract '.' "$src_file")"
|
||||||
|
|
||||||
|
# Extract individual fields from frontmatter
|
||||||
|
local name description model effort permission_mode tools disallowed_tools
|
||||||
|
name="$(echo "$frontmatter" | yq '.name // ""')"
|
||||||
|
description="$(echo "$frontmatter" | yq '.description // ""')"
|
||||||
|
model="$(echo "$frontmatter" | yq '.model // ""')"
|
||||||
|
effort="$(echo "$frontmatter" | yq '.effort // ""')"
|
||||||
|
permission_mode="$(echo "$frontmatter" | yq '.permissionMode // ""')"
|
||||||
|
tools="$(echo "$frontmatter" | yq '.tools // ""')"
|
||||||
|
disallowed_tools="$(echo "$frontmatter" | yq '.disallowedTools // ""')"
|
||||||
|
|
||||||
|
# Map to Codex equivalents
|
||||||
|
local codex_model codex_effort codex_sandbox
|
||||||
|
codex_model="$(map_model "$model")"
|
||||||
|
codex_effort="$(map_effort "${effort:-medium}")"
|
||||||
|
codex_sandbox="$(map_sandbox_mode "$permission_mode" "$tools")"
|
||||||
|
|
||||||
|
# Extract markdown body (everything after the closing frontmatter ---)
|
||||||
|
# The frontmatter block starts at line 1 with --- and ends at the second ---
|
||||||
|
local body
|
||||||
|
body="$(awk 'BEGIN{fm=0} /^---$/{if(fm==0){fm=1;next} if(fm==1){fm=2;next}} fm==2{print}' "$src_file")"
|
||||||
|
|
||||||
|
# Build developer_instructions: append disallowedTools note if present
|
||||||
|
local developer_instructions
|
||||||
|
developer_instructions="$body"
|
||||||
|
if [ -n "$disallowed_tools" ] && [ "$disallowed_tools" != "null" ]; then
|
||||||
|
developer_instructions="${developer_instructions}
|
||||||
|
|
||||||
|
You do NOT have access to these tools: ${disallowed_tools}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Write TOML output
|
||||||
|
cat > "$dst_file" <<TOML
|
||||||
|
name = "${name}"
|
||||||
|
description = "${description}"
|
||||||
|
model = "${codex_model}"
|
||||||
|
model_reasoning_effort = "${codex_effort}"
|
||||||
|
sandbox_mode = "${codex_sandbox}"
|
||||||
|
developer_instructions = """
|
||||||
|
${developer_instructions}
|
||||||
|
"""
|
||||||
|
TOML
|
||||||
|
|
||||||
|
echo "Generated: $dst_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Generate agents
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
echo "Generating Codex agent definitions..."
|
||||||
|
for agent_file in "$AGENTS_SRC"/*.md; do
|
||||||
|
[ -f "$agent_file" ] || continue
|
||||||
|
generate_agent_toml "$agent_file"
|
||||||
|
done
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Generate AGENTS.md — concatenate CLAUDE.md and rules/*.md (sorted)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
echo ""
|
||||||
|
echo "Generating codex/AGENTS.md..."
|
||||||
|
{
|
||||||
|
echo "# Agent Team Instructions"
|
||||||
|
echo ""
|
||||||
|
echo "Agent-team specific protocols live in skills (orchestrate, conventions, worker-protocol, qa-checklist, message-schema, project)."
|
||||||
|
for rules_file in $(ls "$RULES_DIR"/*.md | sort); do
|
||||||
|
echo ""
|
||||||
|
cat "$rules_file"
|
||||||
|
done
|
||||||
|
} > "$CODEX_DIR/AGENTS.md"
|
||||||
|
echo "Generated: $CODEX_DIR/AGENTS.md"
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Generate config.toml — derive sandbox_mode from settings.json defaultMode
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
echo ""
|
||||||
|
echo "Generating codex/config.toml..."
|
||||||
|
|
||||||
|
default_mode="$(yq -r '.permissions.defaultMode // "acceptEdits"' "$SETTINGS_JSON")"
|
||||||
|
|
||||||
|
# Map Claude defaultMode to Codex sandbox_mode
|
||||||
|
case "$default_mode" in
|
||||||
|
plan) config_sandbox="read-only" ;;
|
||||||
|
acceptEdits) config_sandbox="workspace-write" ;;
|
||||||
|
*) config_sandbox="workspace-write" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
cat > "$CODEX_DIR/config.toml" <<TOML
|
||||||
|
model = "o4-mini"
|
||||||
|
model_reasoning_effort = "medium"
|
||||||
|
sandbox_mode = "${config_sandbox}"
|
||||||
|
approval_policy = "on-request"
|
||||||
|
TOML
|
||||||
|
echo "Generated: $CODEX_DIR/config.toml"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Done. Run ./install.sh to link generated files into ~/.codex/"
|
||||||
30
install.sh
30
install.sh
|
|
@ -122,5 +122,35 @@ create_symlink "$RULES_SRC" "$RULES_DST" "rules"
|
||||||
create_file_symlink "$CLAUDE_MD_SRC" "$CLAUDE_MD_DST" "CLAUDE.md"
|
create_file_symlink "$CLAUDE_MD_SRC" "$CLAUDE_MD_DST" "CLAUDE.md"
|
||||||
create_file_symlink "$SETTINGS_SRC" "$SETTINGS_DST" "settings.json"
|
create_file_symlink "$SETTINGS_SRC" "$SETTINGS_DST" "settings.json"
|
||||||
|
|
||||||
|
# Codex CLI integration (optional — only if ~/.codex exists)
|
||||||
|
CODEX_DIR="$HOME/.codex"
|
||||||
|
CODEX_AGENTS_DIR="$HOME/.agents"
|
||||||
|
|
||||||
|
if [ -d "$CODEX_DIR" ]; then
|
||||||
|
echo ""
|
||||||
|
echo "Codex CLI detected at $CODEX_DIR"
|
||||||
|
|
||||||
|
# Skills shared via ~/.agents/skills/ (Codex discovery path)
|
||||||
|
mkdir -p "$CODEX_AGENTS_DIR"
|
||||||
|
create_symlink "$SKILLS_SRC" "$CODEX_AGENTS_DIR/skills" "codex skills"
|
||||||
|
|
||||||
|
# Generated agents
|
||||||
|
if [ -d "$SCRIPT_DIR/codex/agents" ]; then
|
||||||
|
create_symlink "$SCRIPT_DIR/codex/agents" "$CODEX_DIR/agents" "codex agents"
|
||||||
|
else
|
||||||
|
echo "Run ./generate-codex.sh first to generate Codex agent definitions"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Generated AGENTS.md (symlink to project root for Codex discovery)
|
||||||
|
if [ -f "$SCRIPT_DIR/codex/AGENTS.md" ]; then
|
||||||
|
create_file_symlink "$SCRIPT_DIR/codex/AGENTS.md" "$CODEX_DIR/AGENTS.md" "codex AGENTS.md"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Generated config.toml
|
||||||
|
if [ -f "$SCRIPT_DIR/codex/config.toml" ]; then
|
||||||
|
create_file_symlink "$SCRIPT_DIR/codex/config.toml" "$CODEX_DIR/config.toml" "codex config.toml"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Done. Open Claude Code and load the orchestrate skill to begin."
|
echo "Done. Open Claude Code and load the orchestrate skill to begin."
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue