---
mode: subagent
---

<!-- SPDX-License-Identifier: MIT -->
<!-- SPDX-FileCopyrightText: 2025-2026 Marcus Quinn -->
# t1665.5: Migrate Accidentally-Coupled Scripts to Use Runtime Registry

## Origin

- **Created:** 2026-03-26
- **Session:** claude-code:interactive
- **Created by:** marcusquinn (human + ai-interactive)
- **Parent task:** t1665
- **Conversation context:** Audit identified ~45 files with accidental runtime coupling — hardcoded `command -v opencode`, config paths, process patterns. These should use the runtime registry instead.

## What

Migrate all accidentally-coupled scripts to use `runtime-registry.sh` functions instead of hardcoded runtime references. After this, adding a new runtime to the registry automatically makes it visible to session counting, process detection, config validation, dispatch, and all other framework operations.

## Why

- 45 files currently hardcode runtime-specific values that should come from the registry
- Without migration, the registry exists but nothing uses it — the coupling remains
- Each new runtime would still require updating these 45 files manually
- This is the "last mile" that makes the abstraction actually useful

## How (Approach)

### Migration categories (ordered by impact)

#### Category 1: Runtime detection (6+ scripts)

**Pattern to replace:**
```bash
# OLD
if command -v opencode &>/dev/null; then
    backends+=("opencode")
fi
if command -v claude &>/dev/null; then
    backends+=("claude")
fi
```

**Replacement:**
```bash
# NEW
source "$(dirname "${BASH_SOURCE[0]}")/runtime-registry.sh"
while IFS= read -r rt; do
    backends+=("$rt")
done < <(detect_installed_runtimes)
```

**Files:**
- `.agents/scripts/shared-constants.sh:1382-1392` — `detect_available_backends()`
- `.agents/scripts/runner-helper.sh:133-169` — `_detect_backend()`
- `.agents/scripts/contest-helper.sh:50-91`
- `.agents/scripts/email-signature-parser-helper.sh`
- `.agents/scripts/remote-dispatch-helper.sh:341-375`
- `.agents/scripts/voice-helper.sh`
- `.agents/scripts/worktree-sessions.sh`

#### Category 2: Process detection patterns (5+ scripts)

**Pattern to replace:**
```bash
# OLD
/(\.(opencode|claude)|opencode-ai|claude-ai)/ && !/awk/
```

**Replacement:**
```bash
# NEW — build pattern from registry
_build_process_pattern() {
    local pattern=""
    local rt
    for rt in "${RUNTIME_IDS[@]}"; do
        local p
        p=$(get_runtime_process_pattern "$rt")
        [[ -z "$p" ]] && continue
        [[ -n "$pattern" ]] && pattern+="|"
        pattern+="$p"
    done
    echo "$pattern"
}
```

**Files:**
- `.agents/scripts/session-count-helper.sh:116-338` — merge `_count_opencode_sessions()` + `_count_claude_sessions()` into `_count_runtime_sessions()`
- `.agents/scripts/pulse-wrapper.sh:1345-1835` — process tree detection, session counting
- `.agents/scripts/process-guard-helper.sh`
- `.agents/scripts/memory-pressure-monitor.sh`
- `.agents/scripts/dispatch-dedup-helper.sh:144`
- `.agents/scripts/pulse-session-helper.sh:87,383,634`

#### Category 3: Config path lookups (10+ scripts)

**Pattern to replace:**
```bash
# OLD
local opencode_config="$HOME/.config/opencode/opencode.json"
```

**Replacement:**
```bash
# NEW
local config_path
config_path=$(get_runtime_config_path "opencode")
```

**Files:**
- `setup.sh:387-395` — `find_opencode_config()` → `get_runtime_config_path("opencode")`
- `setup-modules/mcp-setup.sh:201-233` — `update_mcp_paths_in_opencode()` → `update_mcp_paths_for_runtime()`
- `setup-modules/migrations.sh:627-836` — `clean_deprecated_mcps()`, `validate_opencode_config()`
- `.agents/scripts/mcp-index-helper.sh:30-565` — reads only opencode.json
- `.agents/scripts/mcp-diagnose.sh:71` — hardcoded config path
- `.agents/scripts/worker-sandbox-helper.sh:152-168` — per-runtime config copy
- `.agents/scripts/secret-hygiene-helper.sh:461` — per-runtime config scanning
- `.agents/scripts/tool-version-check.sh:73-116` — hardcoded tool entries
- `.agents/scripts/contributor-activity-helper.sh:580-583` — session DB lookup

#### Category 4: Dispatch and orchestration (5+ scripts)

**Pattern to replace:**
```bash
# OLD
if [[ "$backend" == "opencode" ]]; then
    opencode run --model "$model" --prompt "$prompt" ...
elif [[ "$backend" == "claude" ]]; then
    claude -p "$prompt" --model "$model" ...
fi
```

**Replacement:**
```bash
# NEW — dispatch adapter (may stay in headless-runtime-helper.sh)
# The dispatch command format is inherently runtime-specific,
# but the selection logic should use the registry
local backend
backend=$(select_dispatch_backend)  # Uses registry + preference
_dispatch_for_runtime "$backend" "$model" "$prompt"
```

**Files:**
- `.agents/scripts/runner-helper.sh:496-536` — `_build_dispatch_cmd()`
- `.agents/scripts/headless-runtime-helper.sh:898-937` — `_invoke_opencode()`
- `.agents/scripts/remote-dispatch-helper.sh:524-597` — remote dispatch
- `.agents/scripts/pulse-wrapper.sh:213,1957-2126` — watchdog loop
- `setup-modules/schedulers.sh:153-257` — pulse plist generation
- `setup-modules/post-setup.sh:142-160` — onboarding dispatch

#### Category 5: Feature flags and config management (3+ files)

**Pattern to replace:**
```bash
# OLD in aidevops.defaults.jsonc
"manage_opencode_config": true,
"manage_claude_config": true,
```

**Replacement:**
```jsonc
// NEW — per-runtime management flags
"managed_runtimes": {
    "opencode": true,
    "claude": true,
    "codex": true,
    "cursor": false
}
```

Or keep the existing pattern but make it registry-driven:
```bash
is_runtime_management_enabled() {
    local runtime_id="$1"
    is_feature_enabled "manage_${runtime_id}_config" 2>/dev/null
}
```

**Files:**
- `.agents/configs/aidevops.defaults.jsonc` — feature flag definitions
- `setup-modules/config.sh:102-165` — feature flag checks
- `setup.sh:769-777` — feature-gated config updates

#### Category 6: Documentation and AGENTS.md (3+ files)

**Files:**
- `.agents/AGENTS.md` — "Supported runtimes" list, session DB paths, dispatch examples
- `AGENTS.md` (root) — config path references
- `.agents/prompts/build.txt` — session transcript paths

These are documentation updates — replace hardcoded runtime lists with "see runtime registry" or keep a curated list that's manually maintained (documentation doesn't need to be auto-generated).

### Migration order

1. **Category 1** first (runtime detection) — highest leverage, used by everything else
2. **Category 2** (process detection) — enables accurate session counting for all runtimes
3. **Category 3** (config paths) — enables config operations for all runtimes
4. **Category 4** (dispatch) — enables headless dispatch to all runtimes
5. **Category 5** (feature flags) — enables per-runtime management control
6. **Category 6** (docs) — cosmetic, lowest priority

### What NOT to migrate

These files are inherently runtime-specific and should stay as-is:
- `.agents/plugins/opencode-aidevops/` — OpenCode plugin API
- `.agents/hooks/git_safety_guard.py` — Claude Code hook API
- `.agents/scripts/extract-opencode-prompts.sh` — binary introspection
- `.agents/scripts/opencode-prompt-drift-check.sh` — upstream tracking
- `.agents/scripts/oauth-pool-helper.sh` Cursor functions — IDE auth extraction
- `setup-modules/tool-install.sh` per-runtime `setup_*_cli()` functions

## Acceptance Criteria

- [ ] `shared-constants.sh` `detect_available_backends()` delegates to `detect_installed_runtimes()`
- [ ] `session-count-helper.sh` counts sessions for all registered runtimes (not just opencode + claude)
- [ ] `runner-helper.sh` `_detect_backend()` uses registry
- [ ] `mcp-index-helper.sh` reads MCP config from all runtimes with config files (not just opencode.json)
- [ ] `mcp-diagnose.sh` diagnoses MCP issues across all runtimes
- [ ] `worker-sandbox-helper.sh` copies configs for all installed runtimes into sandbox
- [ ] `secret-hygiene-helper.sh` scans all runtime config files for leaked secrets
- [ ] No remaining `command -v opencode` or `command -v claude` outside of inherently runtime-specific files
  ```yaml
  verify:
    method: bash
    run: "rg -l 'command -v opencode|command -v claude' ~/.aidevops/agents/scripts/*.sh | rg -v 'extract-opencode|opencode-prompt-drift|opencode-test|opencode-sandbox|opencode-github-setup|oauth-pool|install-hooks' | wc -l | xargs test 0 -eq"
  ```
- [ ] All modified scripts pass shellcheck
- [ ] `aidevops update` still works correctly (regression test)
