---
mode: subagent
---

<!-- SPDX-License-Identifier: MIT -->
<!-- SPDX-FileCopyrightText: 2025-2026 Marcus Quinn -->
# t1665.4: Unify Generator Scripts into generate-runtime-config.sh

## Origin

- **Created:** 2026-03-26
- **Session:** claude-code:interactive
- **Created by:** marcusquinn (human + ai-interactive)
- **Parent task:** t1665
- **Conversation context:** 4 generator scripts totalling 4,102 lines share ~80% content. Each new runtime would add another 900+ line copy.

## What

Merge the 4 existing generator scripts into a single `generate-runtime-config.sh` that uses shared content templates with per-runtime output adapters. The existing scripts become thin wrappers (or are removed) that call the unified generator.

## Why

- `generate-opencode-agents.sh` (924 lines) and `generate-claude-agents.sh` (879 lines) define the same agents with the same markdown content — only the output format differs
- `generate-opencode-commands.sh` (1,439 lines) and `generate-claude-commands.sh` (860 lines) define the same slash commands with the same markdown bodies — only the output directory and header format differ
- Adding Codex, Cursor, or Droid would require creating another 900+ line generator per runtime
- The content (agent definitions, command bodies, MCP server list) is the single source of truth — it should be defined once

## How (Approach)

### Architecture

```
generate-runtime-config.sh
├── Phase 1: Load shared content (agent definitions, command bodies, MCP list)
├── Phase 2: For each installed runtime:
│   ├── Generate agent config (using runtime-registry format info)
│   ├── Generate slash commands (write to runtime's command dir)
│   ├── Register MCP servers (using mcp-config-adapter.sh)
│   └── Deploy system prompts (using prompt-injection-adapter.sh)
└── Phase 3: Verify output integrity
```

### File: `.agents/scripts/generate-runtime-config.sh`

**Phase 1 — Shared content definitions:**

The agent definitions (name, description, model tier, tools, system prompt) are currently embedded in Python dicts inside `generate-opencode-agents.sh`. Extract these into a shared data format:

```bash
# Agent definitions — defined once, consumed by all runtimes
# Format: name|description|model_tier|prompt_file|tools
AGENT_DEFINITIONS=(
    "Build+|Code: features, bug fixes, refactors, CI, PRs|sonnet|prompts/build.txt|read,write,edit,bash,glob,grep,webfetch"
    "SEO|SEO audits, keyword research, GSC, schema markup|sonnet|prompts/build.txt|read,write,edit,bash,glob,grep,webfetch"
    # ... all agents
)

# Command definitions — defined once, consumed by all runtimes
# Format: name|description|body_file_or_inline
# Body files at: .agents/scripts/commands/*.md (already exist!)
COMMAND_DEFINITIONS=(
    "full-loop|Full development lifecycle|commands/full-loop.md"
    "pulse|Supervisor pulse|commands/pulse.md"
    # ... all commands
)

# MCP server definitions — defined once, consumed by all runtimes
# Format: universal JSON (same as mcp-config-adapter.sh input)
MCP_DEFINITIONS=(
    '{"name":"playwright","command":"playwright-mcp","args":[]}'
    '{"name":"chrome-devtools","command":"chrome-devtools-mcp","args":[]}'
    '{"name":"context7","command":"npx","args":["-y","@upstash/context7-mcp@latest"]}'
    # ... all MCPs
)
```

**Phase 2 — Per-runtime generation:**

```bash
generate_for_runtime() {
    local runtime_id="$1"
    local format
    format=$(get_runtime_config_format "$runtime_id")

    echo "Generating config for $(get_runtime_display_name "$runtime_id")..."

    # 2a. Agent config
    case "$format" in
        json-opencode)      _generate_agents_opencode ;;
        cli-claude)         _generate_agents_claude ;;
        toml-codex)         _generate_agents_codex ;;
        json-mcpServers)    _generate_agents_generic "$runtime_id" ;;
        *)                  print_info "No agent config generation for $runtime_id" ;;
    esac

    # 2b. Slash commands (write .md files to runtime's command dir)
    local cmd_dir
    cmd_dir=$(get_runtime_command_dir "$runtime_id")
    if [[ -n "$cmd_dir" ]]; then
        _generate_commands "$cmd_dir" "$runtime_id"
    fi

    # 2c. MCP servers (via adapter)
    for mcp_json in "${MCP_DEFINITIONS[@]}"; do
        local mcp_name
        mcp_name=$(echo "$mcp_json" | jq -r '.name')
        register_mcp_for_runtime "$runtime_id" "$mcp_name" "$mcp_json"
    done

    # 2d. System prompts (via adapter)
    deploy_prompts_for_runtime "$runtime_id"
}

main() {
    local runtime_id
    while IFS= read -r runtime_id; do
        # Check feature flag
        if is_runtime_management_enabled "$runtime_id"; then
            generate_for_runtime "$runtime_id"
        fi
    done < <(detect_installed_runtimes)
}
```

**Phase 3 — Verification:**

```bash
# Diff test: generate output and compare with what the old scripts would produce
# This ensures no regression during migration
verify_output_parity() {
    # For OpenCode: compare opencode.json agents section
    # For Claude: compare ~/.claude/commands/ contents
    # Report any differences
}
```

### Migration strategy

1. **First**: Create `generate-runtime-config.sh` with shared content extracted from existing generators
2. **Then**: Add a `--verify-parity` flag that runs both old and new generators and diffs output
3. **Then**: Once parity is confirmed, update `setup-modules/config.sh` to call the unified generator
4. **Finally**: Mark old generators as deprecated (keep for one release cycle, then remove)

The old `update_opencode_config()` and `update_claude_config()` in `config.sh` merge into `update_runtime_configs()`:

```bash
update_runtime_configs() {
    # Generate commands (shared)
    generate-runtime-config.sh commands

    # Generate agents (shared)
    generate-runtime-config.sh agents

    # Regenerate subagent index
    subagent-index-helper.sh generate
}
```

### Key files to reference

- `.agents/scripts/generate-opencode-agents.sh` — current OpenCode agent generator (924 lines)
- `.agents/scripts/generate-claude-agents.sh` — current Claude agent generator (879 lines)
- `.agents/scripts/generate-opencode-commands.sh` — current OpenCode command generator (1,439 lines)
- `.agents/scripts/generate-claude-commands.sh` — current Claude command generator (860 lines)
- `setup-modules/config.sh:102-165` — current `update_opencode_config()` + `update_claude_config()`
- `.agents/scripts/commands/*.md` — command body files (already exist, already shared)

### Content extraction targets

From `generate-opencode-agents.sh`, extract:
- Lines 100-225: Agent auto-discovery logic (scan `.agents/*.md` for frontmatter)
- Lines 231-254: Model tier definitions and routing
- Lines 260-460: Agent config assembly (tools, permissions, prompts)
- Lines 466-475: Instructions field setting → moves to prompt-injection-adapter.sh
- Lines 490-924: Subagent generation, MCP registration, output writing → per-runtime adapters

From `generate-opencode-commands.sh`, extract:
- Command body content (the markdown inside heredocs) → shared templates
- Output directory logic → parameterized by `get_runtime_command_dir()`

## Acceptance Criteria

- [ ] `generate-runtime-config.sh` exists and generates config for all installed runtimes
- [ ] Agent definitions are defined once (not duplicated per runtime)
- [ ] Command definitions are defined once (not duplicated per runtime)
- [ ] MCP server list is defined once (not duplicated per runtime)
- [ ] `--verify-parity` flag confirms output matches old generators for OpenCode and Claude Code
  ```yaml
  verify:
    method: bash
    run: "~/.aidevops/agents/scripts/generate-runtime-config.sh --verify-parity"
  ```
- [ ] `setup-modules/config.sh` calls unified generator instead of per-runtime generators
- [ ] Old generator scripts are deprecated with pointer to unified generator
- [ ] Adding a new runtime's agent/command generation requires zero changes to content definitions
- [ ] Bash 3.2 compatible, shellcheck clean
- [ ] `aidevops update` still produces correct OpenCode and Claude Code configs (regression test)
