mirror of
https://github.com/itme-brain/agent-team.git
synced 2026-05-08 11:40:12 -04:00
- opus → gpt-5.4, sonnet → gpt-5.3-codex, haiku → gpt-5.1-codex-mini - effort max → extra high (was xhigh) - config.toml default model → gpt-5.3-codex - README model mapping table updated
295 lines
9.9 KiB
Bash
Executable file
295 lines
9.9 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# generate.sh — generates both Claude and Codex output directories from
|
|
# shared agent source files. Agent source files (agents/*.md) are the
|
|
# single source of truth; this script derives tool-specific equivalents.
|
|
#
|
|
# Template variables in agent bodies are expanded per-target:
|
|
# ${PLANS_DIR} — where plans live (.claude/plans vs plans)
|
|
# ${WEB_SEARCH} — how web search is referenced
|
|
# ${SEARCH_TOOLS} — how codebase search tools are referenced
|
|
#
|
|
# Idempotent: safe to run multiple times.
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
|
AGENTS_SRC="$SCRIPT_DIR/agents"
|
|
RULES_DIR="$SCRIPT_DIR/rules"
|
|
CLAUDE_MD="$SCRIPT_DIR/CLAUDE.md"
|
|
SETTINGS_JSON="$SCRIPT_DIR/settings.json"
|
|
|
|
CLAUDE_DIR="$SCRIPT_DIR/claude"
|
|
CLAUDE_AGENTS_DIR="$CLAUDE_DIR/agents"
|
|
|
|
CODEX_DIR="$SCRIPT_DIR/codex"
|
|
CODEX_AGENTS_DIR="$CODEX_DIR/agents"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Template variable values per target (KEY=VALUE pairs)
|
|
# ---------------------------------------------------------------------------
|
|
CLAUDE_VARS=(
|
|
"PLANS_DIR=.claude/plans"
|
|
"WEB_SEARCH=via WebFetch/WebSearch"
|
|
"SEARCH_TOOLS=Use Grep/Glob/Read"
|
|
)
|
|
|
|
CODEX_VARS=(
|
|
"PLANS_DIR=plans"
|
|
"WEB_SEARCH=via web search"
|
|
"SEARCH_TOOLS=Search the codebase"
|
|
)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# extract_body — extracts everything after the second --- (YAML frontmatter)
|
|
# ---------------------------------------------------------------------------
|
|
extract_body() {
|
|
local file="$1"
|
|
awk 'BEGIN{fm=0} /^---$/{if(fm==0){fm=1;next} if(fm==1){fm=2;next}} fm==2{print}' "$file"
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# extract_frontmatter_block — extracts the raw frontmatter including delimiters
|
|
# ---------------------------------------------------------------------------
|
|
extract_frontmatter_block() {
|
|
local file="$1"
|
|
awk 'BEGIN{fm=0} /^---$/{if(fm==0){fm=1;print;next} if(fm==1){print;exit}} fm==1{print}' "$file"
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# expand_body — runs envsubst on body text, substituting only our 3 variables
|
|
# $1 = body text
|
|
# $2.. = KEY=VALUE pairs to export
|
|
# ---------------------------------------------------------------------------
|
|
expand_body() {
|
|
local body="$1"
|
|
shift
|
|
# Export only the specified variables
|
|
for pair in "$@"; do
|
|
export "${pair%%=*}=${pair#*=}"
|
|
done
|
|
echo "$body" | envsubst '${PLANS_DIR} ${WEB_SEARCH} ${SEARCH_TOOLS}'
|
|
# Clean up exported variables
|
|
for pair in "$@"; do
|
|
unset "${pair%%=*}"
|
|
done
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# map_model — maps Claude model name to Codex model name
|
|
# ---------------------------------------------------------------------------
|
|
map_model() {
|
|
local model="$1"
|
|
case "$model" in
|
|
opus) echo "gpt-5.4" ;;
|
|
sonnet) echo "gpt-5.3-codex" ;;
|
|
haiku) echo "gpt-5.1-codex-mini" ;;
|
|
*) echo "gpt-5.3-codex" ;;
|
|
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 "extra high" ;;
|
|
*) 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_claude — produces claude/ output directory
|
|
# ---------------------------------------------------------------------------
|
|
generate_claude() {
|
|
echo "=== Generating Claude output ==="
|
|
|
|
# Clean and recreate output directories
|
|
rm -rf "$CLAUDE_DIR"
|
|
mkdir -p "$CLAUDE_AGENTS_DIR"
|
|
|
|
# Copy CLAUDE.md
|
|
cp "$CLAUDE_MD" "$CLAUDE_DIR/CLAUDE.md"
|
|
echo "Copied: $CLAUDE_DIR/CLAUDE.md"
|
|
|
|
# Copy settings.json
|
|
cp "$SETTINGS_JSON" "$CLAUDE_DIR/settings.json"
|
|
echo "Copied: $CLAUDE_DIR/settings.json"
|
|
|
|
# Create relative symlinks for rules and skills
|
|
ln -s ../rules "$CLAUDE_DIR/rules"
|
|
echo "Symlinked: $CLAUDE_DIR/rules -> ../rules"
|
|
|
|
ln -s ../skills "$CLAUDE_DIR/skills"
|
|
echo "Symlinked: $CLAUDE_DIR/skills -> ../skills"
|
|
|
|
# Generate agent .md files with expanded template variables
|
|
for agent_file in "$AGENTS_SRC"/*.md; do
|
|
[ -f "$agent_file" ] || continue
|
|
|
|
local agent_basename
|
|
agent_basename="$(basename "$agent_file")"
|
|
local dst_file="$CLAUDE_AGENTS_DIR/$agent_basename"
|
|
|
|
# Extract frontmatter and body separately
|
|
local frontmatter body expanded_body
|
|
frontmatter="$(extract_frontmatter_block "$agent_file")"
|
|
body="$(extract_body "$agent_file")"
|
|
expanded_body="$(expand_body "$body" "${CLAUDE_VARS[@]}")"
|
|
|
|
# Reassemble: frontmatter + expanded body
|
|
{
|
|
echo "$frontmatter"
|
|
echo "$expanded_body"
|
|
} > "$dst_file"
|
|
|
|
echo "Generated: $dst_file"
|
|
done
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# generate_codex — produces codex/ output directory
|
|
# ---------------------------------------------------------------------------
|
|
generate_codex() {
|
|
echo ""
|
|
echo "=== Generating Codex output ==="
|
|
|
|
# Clean and recreate output directories
|
|
rm -rf "$CODEX_DIR"
|
|
mkdir -p "$CODEX_AGENTS_DIR"
|
|
|
|
# Generate agent .toml files
|
|
echo "Generating Codex agent definitions..."
|
|
for agent_file in "$AGENTS_SRC"/*.md; do
|
|
[ -f "$agent_file" ] || continue
|
|
|
|
local agent_basename
|
|
agent_basename="$(basename "$agent_file" .md)"
|
|
local dst_file="$CODEX_AGENTS_DIR/${agent_basename}.toml"
|
|
|
|
# Extract YAML frontmatter using yq
|
|
local frontmatter
|
|
frontmatter="$(yq --front-matter=extract '.' "$agent_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 and expand body with Codex variable values
|
|
local body expanded_body
|
|
body="$(extract_body "$agent_file")"
|
|
expanded_body="$(expand_body "$body" "${CODEX_VARS[@]}")"
|
|
|
|
# Build developer_instructions: append disallowedTools note if present
|
|
local developer_instructions
|
|
developer_instructions="$expanded_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"
|
|
done
|
|
|
|
# Generate AGENTS.md — concatenate rules/*.md with tool-agnostic header
|
|
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 "$RULES_DIR"/*.md; 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..."
|
|
|
|
local default_mode
|
|
default_mode="$(yq -r '.permissions.defaultMode // "acceptEdits"' "$SETTINGS_JSON")"
|
|
|
|
# Map Claude defaultMode to Codex sandbox_mode
|
|
local config_sandbox
|
|
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 = "gpt-5.3-codex"
|
|
model_reasoning_effort = "medium"
|
|
sandbox_mode = "${config_sandbox}"
|
|
approval_policy = "on-request"
|
|
TOML
|
|
echo "Generated: $CODEX_DIR/config.toml"
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Main
|
|
# ---------------------------------------------------------------------------
|
|
generate_claude
|
|
generate_codex
|
|
|
|
echo ""
|
|
echo "Done."
|