feat: add Codex agent conversion and install support (#362)

Adds Codex as a conversion/install target: each agent → `~/.codex/agents/<slug>.toml` with the three required Codex fields (name, description, developer_instructions).

Validated: all 184 agents generate valid, parseable TOML (incl. 21k-char agents with embedded code blocks) via the PR's TOML basic-string escaper. Matches OpenAI's documented custom-agent schema.

Thanks @yunuskilicdev.
This commit is contained in:
Yunus Kılıç
2026-06-04 01:59:48 +02:00
committed by GitHub
parent ab414934e3
commit 620a061a90
7 changed files with 190 additions and 8 deletions
+43 -4
View File
@@ -19,6 +19,7 @@
# openclaw — OpenClaw workspaces (integrations/openclaw/<agent>/SOUL.md)
# qwen — Qwen Code SubAgent files (~/.qwen/agents/*.md)
# kimi — Kimi Code CLI agent files (~/.config/kimi/agents/)
# codex — Codex custom agent TOML files (~/.codex/agents/*.toml)
# all — All tools (default)
#
# Output is written to integrations/<tool>/ relative to the repo root.
@@ -104,6 +105,21 @@ slugify() {
echo "$1" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//'
}
# Escape a value for a TOML basic string, including control characters that
# cannot appear raw in TOML source.
toml_escape_string() {
printf '%s' "$1" | perl -0pe '
s/\\/\\\\/g;
s/"/\\"/g;
s/\n/\\n/g;
s/\r/\\r/g;
s/\t/\\t/g;
s/\f/\\f/g;
s/\x08/\\b/g;
s/([\x00-\x07\x0B\x0E-\x1F\x7F])/sprintf("\\u%04X", ord($1))/ge;
'
}
# --- Per-tool converters ---
convert_antigravity() {
@@ -132,6 +148,28 @@ ${body}
HEREDOC
}
convert_codex() {
local file="$1"
local name description slug outfile body
name="$(get_field "name" "$file")"
description="$(get_field "description" "$file")"
slug="$(slugify "$name")"
body="$(get_body "$file")"
outfile="$OUT_DIR/codex/agents/${slug}.toml"
mkdir -p "$(dirname "$outfile")"
# Codex custom agent format: one TOML file per agent with minimal required
# fields only. Use a TOML basic string so control characters in the source
# body are encoded safely instead of producing invalid TOML.
cat > "$outfile" <<HEREDOC
name = "$(toml_escape_string "$name")"
description = "$(toml_escape_string "$description")"
developer_instructions = "$(toml_escape_string "$body")"
HEREDOC
}
convert_gemini_cli() {
local file="$1"
local name description slug outdir outfile body
@@ -500,6 +538,7 @@ run_conversions() {
case "$tool" in
antigravity) convert_antigravity "$file" ;;
codex) convert_codex "$file" ;;
gemini-cli) convert_gemini_cli "$file" ;;
opencode) convert_opencode "$file" ;;
cursor) convert_cursor "$file" ;;
@@ -536,7 +575,7 @@ main() {
esac
done
local valid_tools=("antigravity" "gemini-cli" "opencode" "cursor" "aider" "windsurf" "openclaw" "qwen" "kimi" "all")
local valid_tools=("antigravity" "gemini-cli" "opencode" "cursor" "aider" "windsurf" "openclaw" "qwen" "kimi" "codex" "all")
local valid=false
for t in "${valid_tools[@]}"; do [[ "$t" == "$tool" ]] && valid=true && break; done
if ! $valid; then
@@ -555,7 +594,7 @@ main() {
local tools_to_run=()
if [[ "$tool" == "all" ]]; then
tools_to_run=("antigravity" "gemini-cli" "opencode" "cursor" "aider" "windsurf" "openclaw" "qwen" "kimi")
tools_to_run=("antigravity" "gemini-cli" "opencode" "cursor" "aider" "windsurf" "openclaw" "qwen" "kimi" "codex")
else
tools_to_run=("$tool")
fi
@@ -566,7 +605,7 @@ main() {
if $use_parallel && [[ "$tool" == "all" ]]; then
# Tools that write to separate dirs can run in parallel; buffer output so each tool's output stays together
local parallel_tools=(antigravity gemini-cli opencode cursor openclaw qwen)
local parallel_tools=(antigravity gemini-cli opencode cursor openclaw qwen codex)
local parallel_out_dir
parallel_out_dir="$(mktemp -d)"
info "Converting: ${#parallel_tools[@]}/${n_tools} tools in parallel (output buffered per tool)..."
@@ -578,7 +617,7 @@ main() {
[[ -f "$parallel_out_dir/$t" ]] && cat "$parallel_out_dir/$t"
done
rm -rf "$parallel_out_dir"
local idx=7
local idx=8
for t in aider windsurf; do
progress_bar "$idx" "$n_tools"
printf "\n"
+20 -1
View File
@@ -20,6 +20,7 @@
# windsurf -- Copy .windsurfrules to current directory
# openclaw -- Copy workspaces to ~/.openclaw/agency-agents/
# qwen -- Copy SubAgents to ~/.qwen/agents/ (user-wide) or .qwen/agents/ (project)
# codex -- Copy custom agent TOML files to ~/.codex/agents/
# all -- Install for all detected tools (default)
#
# Flags:
@@ -101,7 +102,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
INTEGRATIONS="$REPO_ROOT/integrations"
ALL_TOOLS=(claude-code copilot antigravity gemini-cli opencode openclaw cursor aider windsurf qwen kimi)
ALL_TOOLS=(claude-code copilot antigravity gemini-cli opencode openclaw cursor aider windsurf qwen kimi codex)
# Standard agent category directories (keep sorted, sync with convert.sh / lint-agents.sh)
AGENT_DIRS=(
@@ -149,6 +150,7 @@ detect_openclaw() { command -v openclaw >/dev/null 2>&1 || [[ -d "${HOME}/.o
detect_windsurf() { command -v windsurf >/dev/null 2>&1 || [[ -d "${HOME}/.codeium" ]]; }
detect_qwen() { command -v qwen >/dev/null 2>&1 || [[ -d "${HOME}/.qwen" ]]; }
detect_kimi() { command -v kimi >/dev/null 2>&1; }
detect_codex() { command -v codex >/dev/null 2>&1 || [[ -d "${HOME}/.codex" ]]; }
is_detected() {
case "$1" in
@@ -163,6 +165,7 @@ is_detected() {
windsurf) detect_windsurf ;;
qwen) detect_qwen ;;
kimi) detect_kimi ;;
codex) detect_codex ;;
*) return 1 ;;
esac
}
@@ -181,6 +184,7 @@ tool_label() {
windsurf) printf "%-14s %s" "Windsurf" "(.windsurfrules)" ;;
qwen) printf "%-14s %s" "Qwen Code" "(~/.qwen/agents)" ;;
kimi) printf "%-14s %s" "Kimi Code" "(~/.config/kimi/agents)" ;;
codex) printf "%-14s %s" "Codex" "(~/.codex/agents)" ;;
esac
}
@@ -518,6 +522,20 @@ install_kimi() {
ok "Usage: kimi --agent-file ~/.config/kimi/agents/<agent-name>/agent.yaml"
}
install_codex() {
local src="$INTEGRATIONS/codex/agents"
local dest="${HOME}/.codex/agents"
local count=0
[[ -d "$src" ]] || { err "integrations/codex missing. Run convert.sh first."; return 1; }
mkdir -p "$dest"
local f
while IFS= read -r -d '' f; do
cp "$f" "$dest/"
(( count++ )) || true
done < <(find "$src" -maxdepth 1 -name "*.toml" -print0)
ok "Codex: $count agents -> $dest"
}
install_tool() {
case "$1" in
claude-code) install_claude_code ;;
@@ -531,6 +549,7 @@ install_tool() {
windsurf) install_windsurf ;;
qwen) install_qwen ;;
kimi) install_kimi ;;
codex) install_codex ;;
esac
}