agent-ecosystem/docs/research/claude-coupling-analysis.md
iliya 71db7f153b feat(research): add comprehensive documentation on AI agent protocols and orchestration tools
- Introduced multiple new markdown files detailing the Agent Client Protocol (ACP), AI agent orchestration landscape, and various tools for managing multi-agent systems.
- Included in-depth analysis of protocol standards, governance structures, and emerging frameworks relevant to AI agent integration.
- Documented key features, architecture, and integration potential of various desktop and CLI orchestrators, enhancing understanding of the current ecosystem.
- Provided insights into best practices for integrating multi-provider agent support within the Electron framework.

This documentation aims to serve as a foundational resource for developers and stakeholders involved in AI agent orchestration and integration.
2026-03-25 14:47:52 +02:00

29 KiB

Claude Coupling Analysis

Comprehensive analysis of how tightly the Claude Agent Teams UI codebase is coupled to Claude/Claude Code/Claude Agent Teams. The goal is to understand the effort required to abstract the AI provider layer to support other agents (OpenAI Codex, Gemini CLI, etc.).

Date: 2026-03-24 Branch: dev Commit: 08be859


Summary Table

Area Coupling (1-10) Effort Key Blockers
1. Process Management 9 High Binary name, CLI flags, kill semantics
2. Protocol / Communication 10 High stream-json is Claude-proprietary
3. Message Parsing (JSONL) 9 High Schema is Claude Code's internal format
4. Team Management 10 Very High Agent Teams is a Claude Code feature
5. Session Data / Paths 9 Medium ~/.claude/ hardcoded everywhere
6. Authentication 8 Medium claude auth status, GCS binary dist
7. MCP Integration 5 Low MCP is a cross-vendor standard
8. UI Components 6 Medium Branding strings, CLAUDE.md references
9. Types / Interfaces 8 High Types mirror Claude Code JSONL schema
10. Configuration 7 Medium Path constants, env vars, config files
Pricing / Cost 7 Medium pricing.json is Claude-model-centric
Model Parsing 9 Low parseModelString() only handles claude-*

Overall Coupling Score: 8.3 / 10 — Deeply coupled to Claude Code at nearly every layer.


1. Process Management

Coupling: 9/10 | Effort: High

Specific Files

  • src/main/services/team/ClaudeBinaryResolver.ts — resolves the claude binary across platforms
  • src/main/utils/childProcess.tsspawnCli() / execCli() wrappers inject CLAUDE_HOOK_JUDGE_MODE env var
  • src/main/services/team/TeamProvisioningService.ts — spawns claude with Claude-specific flags
  • src/main/services/infrastructure/CliInstallerService.ts — downloads claude binary from GCS
  • src/main/services/schedule/ScheduledTaskExecutor.ts — spawns claude -p for scheduled tasks

What's Claude-specific

  1. Binary name: ClaudeBinaryResolver searches for claude binary across PATH, NVM, platform-specific dirs
  2. CLI flags: --input-format stream-json, --output-format stream-json, --verbose, --setting-sources, --mcp-config, --disallowedTools, --dangerously-skip-permissions, --permission-prompt-tool, --model, --effort, --worktree, --resume, --no-session-persistence, --max-turns, --permission-mode
  3. Env var: CLAUDE_HOOK_JUDGE_MODE: 'true' injected into every CLI process
  4. Env var: CLAUDE_CONFIG_DIR set in buildEnrichedEnv()
  5. Env var override: CLAUDE_CLI_PATH for custom binary location
  6. Kill semantics: killTeamProcess() uses SIGKILL specifically because Claude CLI cleanup on SIGTERM deletes team files
  7. GCS distribution: CliInstallerService downloads from https://storage.googleapis.com/claude-code-dist-.../claude-code-releases
  8. Version command: claude --version expected to output "X.Y.Z (Claude Code)"
  9. Install command: claude install for shell integration

Abstraction Approach

Create a CliProvider interface:

interface CliProvider {
  name: string;
  resolveBinaryPath(): Promise<string | null>;
  buildSpawnArgs(options: SpawnOptions): string[];
  buildEnv(binaryPath: string): NodeJS.ProcessEnv;
  parseVersionOutput(stdout: string): string;
  getKillSignal(): NodeJS.Signals;
  install(): Promise<void>;
  checkAuth(): Promise<AuthStatus>;
}

Each provider (ClaudeCliProvider, CodexCliProvider, GeminiCliProvider) implements this. ClaudeBinaryResolver becomes ClaudeCliProvider.resolveBinaryPath().


2. Protocol / Communication

Coupling: 10/10 | Effort: High

Specific Files

  • src/main/services/team/TeamProvisioningService.ts (lines 126-132, 2742-2980, 4849-5290) — stream-json parser
  • src/renderer/utils/streamJsonParser.ts — renderer-side stream-json log parsing
  • src/renderer/components/team/CliLogsRichView.tsx — renders stream-json output
  • src/shared/utils/teammateMessageParser.ts — parses <teammate-message> XML format

What's Claude-specific

  1. stream-json protocol: Claude Code's proprietary newline-delimited JSON over stdin/stdout
    • Input: {"type":"user","message":{"role":"user","content":[...]}}\n
    • Output types: user, assistant, control_request, result, system
    • result.success = turn complete, result.error = failure
    • control_request for tool approval prompts
  2. Message envelope: {"type":"user","message":{"role":"user","content":[{"type":"text","text":"..."}]}}
  3. Teammate message format: XML tags <teammate-message teammate_id="..." color="..." summary="...">content</teammate-message>
  4. Preflight ping: claude -p "Output only the single word PONG." --output-format text --model haiku --max-turns 1 --no-session-persistence
  5. Tool approval: control_request type with tool_input, tool_name, approval via stdin

Abstraction Approach

This is the hardest area. Create a CliProtocol interface:

interface CliProtocol {
  formatInputMessage(text: string): string;
  parseOutputLine(line: string): ParsedOutputMessage;
  isResultSuccess(msg: ParsedOutputMessage): boolean;
  isResultError(msg: ParsedOutputMessage): boolean;
  isToolApprovalRequest(msg: ParsedOutputMessage): ToolApprovalRequest | null;
  formatToolApprovalResponse(approved: boolean): string;
  getProtocolFlags(): string[];  // e.g. ['--input-format', 'stream-json', ...]
}

Each agent's protocol would need a distinct implementation. OpenAI Codex uses a different protocol (REST-based sandbox execution, not stdin/stdout). This would require major architectural changes.


3. Message Parsing (JSONL)

Coupling: 9/10 | Effort: High

Specific Files

  • src/main/types/jsonl.ts — raw JSONL entry types (Claude Code session file format)
  • src/main/types/messages.ts — parsed message types and type guards
  • src/main/types/domain.ts — domain types referencing ~/.claude/projects/ structure
  • src/main/types/chunks.ts — chunk building from parsed messages
  • src/main/utils/jsonl.ts — JSONL file parser
  • src/main/constants/messageTags.ts<local-command-stdout>, <local-command-caveat>, <system-reminder> tags

What's Claude-specific

  1. JSONL schema: Entry types (user, assistant, system, summary, file-history-snapshot, queue-operation) are Claude Code's internal format
  2. Content blocks: text, thinking, tool_use, tool_result, image — follows Anthropic Messages API schema
  3. thinking + signature: Extended thinking is an Anthropic-specific feature
  4. isMeta flag: Claude Code's internal convention for distinguishing real user messages from tool results
  5. isSidechain: Claude Code's flag for subagent messages
  6. stop_reason: end_turn, tool_use, max_tokens, stop_sequence — Anthropic API values
  7. XML tags in content: <local-command-stdout>, <local-command-caveat>, <system-reminder>, <command-name> are Claude Code's internal message wrapping
  8. <synthetic> model: Claude Code's marker for system-generated placeholders
  9. isCompactSummary: Claude Code's context compaction mechanism
  10. Usage metadata: cache_read_input_tokens, cache_creation_input_tokens — Anthropic cache API

Abstraction Approach

Create a SessionParser interface that converts provider-specific session data to a normalized ParsedMessage:

interface SessionDataProvider {
  parseSessionFile(path: string): AsyncIterable<ParsedMessage>;
  isRealUserMessage(msg: ParsedMessage): boolean;
  isToolCall(block: ContentBlock): boolean;
  extractToolResult(msg: ParsedMessage): ToolResult | null;
}

The existing ParsedMessage type is actually reasonably generic (it has toolCalls, toolResults, content). The provider-specific part is the parsing FROM the raw format TO ParsedMessage. New providers would implement different parsers.


4. Team Management

Coupling: 10/10 | Effort: Very High

Specific Files

  • src/main/services/team/TeamProvisioningService.ts (~7800 lines) — the monolith
  • agent-teams-controller/ — workspace package for file-level team operations
  • src/main/services/team/*.ts (~35 files) — team data, inbox, tasks, kanban, review, cross-team
  • src/shared/types/team.ts — TeamConfig, TeamTask, SendMessageRequest, etc.
  • src/main/ipc/teams.ts — ~65 IPC handlers for team operations
  • src/shared/utils/leadDetection.ts — detects team lead by agentType values

What's Claude-specific

  1. Agent Teams is a Claude Code feature: TeamCreate, TaskCreate, TaskUpdate, TaskList, TaskGet, SendMessage, TeamDelete are Claude Code CLI tools
  2. Team file structure: ~/.claude/teams/{teamName}/config.json, inboxes/{member}.json, kanban-state.json, processes.json, members.meta.json
  3. Task file structure: ~/.claude/tasks/{teamName}/{taskId}.json
  4. Inbox protocol: File-based message passing — lead reads stdin, teammates read inbox files
  5. Lead/teammate distinction: Lead uses stream-json, teammates are independent CLI processes
  6. Tool blocking: --disallowedTools TeamDelete,TodoWrite
  7. agentType values: team-lead, lead, orchestrator, general-purpose — Claude Code internal values
  8. teammate_spawned tool results: How team member processes are detected
  9. Cross-team communication: cross_team_send, cross_team_list_targets, cross_team_get_outbox
  10. Action mode instructions: Custom protocol text injected into team prompts
  11. agent-teams-controller package: Pure JS module that reads Claude Code's team filesystem directly

Abstraction Approach

This is by far the hardest area. Agent Teams is a unique Claude Code feature with no equivalent in other CLI agents. Options:

  • Option A: Keep team management as Claude-only feature, abstract only session viewing
  • Option B: Build a generic team orchestration layer that wraps different agent CLIs. Would need to implement inbox/task/kanban semantics independently of Claude Code.
  • Option C: Make team management pluggable — each provider declares supportsTeams: boolean and provides a TeamOrchestrator implementation if supported

Option A is the most realistic short-term approach.


5. Session Data / Paths

Coupling: 9/10 | Effort: Medium

Specific Files

  • src/main/utils/pathDecoder.ts — all path construction (~/.claude/projects/, ~/.claude/todos/, ~/.claude/teams/, ~/.claude/tasks/)
  • src/main/services/discovery/ProjectScanner.ts — scans ~/.claude/projects/
  • src/main/services/infrastructure/FileWatcher.ts — watches ~/.claude/projects/, ~/.claude/todos/, ~/.claude/teams/, ~/.claude/tasks/
  • src/main/services/infrastructure/SshConnectionManager.ts — hardcodes ~/.claude/projects for remote
  • src/main/services/infrastructure/ConfigManager.ts — config at ~/.claude/claude-devtools-config.json
  • src/main/constants/worktreePatterns.ts — detects .claude/worktrees/ pattern

What's Claude-specific

  1. Base path: ~/.claude/ as root for all data
  2. Path encoding: /Users/name/project-Users-name-project (Claude Code's convention)
  3. Session files: ~/.claude/projects/{encoded-path}/{uuid}.jsonl
  4. Subagent files: ~/.claude/projects/{path}/{session_uuid}/agent_{uuid}.jsonl
  5. Todo files: ~/.claude/todos/{sessionId}.json
  6. Team files: ~/.claude/teams/{teamName}/...
  7. Task files: ~/.claude/tasks/{teamName}/{taskId}.json
  8. Config: ~/.claude/claude-devtools-config.json (our config, stored in Claude's directory)
  9. SSH remote: Hardcoded /home/{user}/.claude/projects, /Users/{user}/.claude/projects, /root/.claude/projects
  10. Worktree patterns: .claude/worktrees/ as a known source

Abstraction Approach

Path resolution is already partially abstracted via getClaudeBasePath() with override support (setClaudeBasePathOverride). Extend to:

interface DataPathProvider {
  getBasePath(): string;                           // ~/.claude/, ~/.codex/, etc.
  getProjectsPath(): string;                       // {base}/projects/
  getSessionPath(projectId: string, sessionId: string): string;
  getSubagentPath(projectId: string, sessionId: string): string;
  encodeProjectPath(absolutePath: string): string;
  decodeProjectPath(encoded: string): string;
}

Medium effort because path functions are centralized in pathDecoder.ts. The SSH remote paths would need provider-specific resolution.


6. Authentication

Coupling: 8/10 | Effort: Medium

Specific Files

  • src/main/services/infrastructure/CliInstallerService.tsclaude auth status --output-format json, claude --version
  • src/shared/types/cliInstaller.tsCliInstallationStatus.authLoggedIn, authMethod
  • src/main/utils/cliAuthDiagLog.ts — diagnostic logging for auth issues
  • src/renderer/components/dashboard/CliStatusBanner.tsx — shows login status

What's Claude-specific

  1. Auth check: claude auth status --output-format json — returns {loggedIn: boolean, authMethod: string}
  2. Auth method types: "oauth_token", "api_key" — Claude-specific
  3. Binary distribution: GCS bucket claude-code-dist-* with platform-specific binaries
  4. Install flow: Downloads binary → SHA256 verify → claude install for shell integration
  5. Version parsing: "2.1.59 (Claude Code)" format
  6. Preflight auth check: Runs claude -p "PONG" to verify auth works

Abstraction Approach

interface CliInstallerProvider {
  getLatestVersion(): Promise<string>;
  downloadBinary(platform: CliPlatform): Promise<string>;  // returns temp path
  installBinary(binaryPath: string): Promise<void>;
  checkVersion(binaryPath: string): Promise<string>;
  checkAuth(binaryPath: string): Promise<AuthStatus>;
}

7. MCP Integration

Coupling: 5/10 | Effort: Low

Specific Files

  • src/main/services/team/TeamMcpConfigBuilder.ts — builds MCP config JSON for team processes
  • src/main/services/extensions/install/McpInstallService.ts — installs MCP servers
  • src/shared/types/extensions/mcp.ts — MCP types
  • mcp-server/ — built-in MCP server for the app

What's Claude-specific

  1. Config file location: .claude.json in home dir, .mcp.json in project
  2. CLI flag: --mcp-config to pass config path to CLI
  3. Config format: Standard MCP format ({mcpServers: {name: {command, args}}})
  4. Built-in server: mcp-server/ is our own — not Claude-specific

What's NOT Claude-specific

MCP (Model Context Protocol) is becoming a cross-vendor standard. The protocol itself is vendor-neutral. The config format may vary by agent but the server implementation is portable.

Abstraction Approach

MCP is already the most abstracted area. The only coupling is the config file naming (.claude.json) and the --mcp-config flag. A provider interface would specify how to pass MCP config to the CLI.


8. UI Components

Coupling: 6/10 | Effort: Medium

Specific Files

  • src/renderer/index.html — title "Claude Agent Teams UI"
  • src/renderer/components/common/ErrorBoundary.tsx — CSS classes bg-claude-dark-bg, text-claude-dark-text
  • src/renderer/components/team/ClaudeLogsDialog.tsx, ClaudeLogsPanel.tsx, ClaudeLogsSection.tsx, ClaudeLogsFilterPopover.tsx, useClaudeLogsController.ts — "Claude Logs" feature naming
  • src/renderer/types/claudeMd.ts — CLAUDE.md tracking types
  • src/renderer/utils/claudeMdTracker.ts (70 occurrences) — CLAUDE.md context tracking
  • src/renderer/utils/contextTracker.ts (56 occurrences) — references CLAUDE.md sources
  • src/renderer/components/chat/SessionContextPanel/ — CLAUDE.md section
  • src/renderer/components/settings/sections/GeneralSection.tsx (69 occurrences) — "Claude Root" settings
  • src/renderer/components/dashboard/CliStatusBanner.tsx — "Claude CLI" status
  • src/renderer/index.css — comments mentioning "Claude Code"
  • src/shared/constants/cli.tsCLI_NOT_FOUND_MESSAGE = 'Claude CLI not found...'

What's Claude-specific

  1. Branding strings: "Claude Agent Teams UI", "Claude CLI", "Claude Logs", "Claude Root"
  2. CSS theme variables: claude-dark-bg, claude-dark-text, claude-dark-border, claude-dark-surface in ErrorBoundary
  3. CLAUDE.md feature: The entire CLAUDE.md tracking system (types, tracker, UI) is Claude Code specific
  4. "Claude Logs": 5+ components for viewing CLI logs named "ClaudeLogs*"
  5. Settings: "Local Claude Root" setting for ~/.claude override

What's NOT Claude-specific

  • Chat rendering (UserChunk, AIChunk, SystemChunk) is generic
  • Kanban board UI is generic
  • Team member list, task management UI is generic
  • Tool call visualization is generic (tool_use/tool_result pattern is shared across LLM providers)

Abstraction Approach

  1. Replace hardcoded strings with a config/branding module
  2. Rename ClaudeLogs*CliLogs* or AgentLogs*
  3. Rename claudeMdTrackerinstructionFileTracker (provider specifies filename pattern)
  4. CSS variable renaming is mechanical (claude-dark-*app-dark-*)
  5. "Claude Root" → "Agent Data Directory"

9. Types / Interfaces

Coupling: 8/10 | Effort: High

Specific Files

  • src/main/types/jsonl.tsChatHistoryEntry union follows Claude Code JSONL exactly
  • src/main/types/messages.tsParsedMessage with Claude-specific fields (isMeta, isSidechain, isCompactSummary)
  • src/main/types/domain.tsMessageType, TokenUsage with cache_read_input_tokens
  • src/shared/types/team.ts — Team types entirely Claude Agent Teams specific
  • src/shared/types/api.ts — API surface exposes Claude-specific session/team types
  • src/shared/utils/modelParser.ts — parses claude-* model strings only
  • src/shared/utils/pricing.ts — pricing data is Claude/Anthropic model centric

What's Claude-specific

  1. Content block types: thinking with signature field — Anthropic extended thinking
  2. Token usage fields: cache_read_input_tokens, cache_creation_input_tokens — Anthropic prompt caching
  3. Model string format: claude-{family}-{major}-{minor}-{date} and old claude-{major}-{family}-{date}
  4. Model families: sonnet, opus, haiku — Anthropic model names
  5. isMeta/isSidechain: Claude Code's internal conventions
  6. stop_reason values: end_turn, tool_use, max_tokens, stop_sequence
  7. Pricing data: resources/pricing.json is Anthropic-model-only (includes Bedrock/Vertex variants)

Abstraction Approach

The ParsedMessage type is actually fairly close to a generic representation. Key changes:

  • Make thinking content optional/provider-specific
  • Generalize token usage (some fields are Anthropic-specific)
  • modelParser.ts needs a provider-aware implementation
  • Pricing needs multi-provider support (or provider-supplied pricing)

10. Configuration

Coupling: 7/10 | Effort: Medium

Specific Files

  • src/main/services/infrastructure/ConfigManager.ts — stores config in ~/.claude/claude-devtools-config.json
  • src/main/utils/cliEnv.ts — sets CLAUDE_CONFIG_DIR env var
  • src/main/utils/pathDecoder.tsgetClaudeBasePath() with override support
  • src/shared/utils/cliArgsParser.tsPROTECTED_CLI_FLAGS are Claude CLI flags
  • src/main/ipc/config.ts — configuration IPC handlers
  • src/main/services/team/TeamMcpConfigBuilder.ts.claude.json user MCP config

What's Claude-specific

  1. Config dir: ~/.claude/ as base
  2. Config filename: claude-devtools-config.json
  3. Env vars: CLAUDE_CONFIG_DIR, CLAUDE_CLI_PATH, CLAUDE_HOOK_JUDGE_MODE
  4. Protected flags: --input-format, --output-format, --setting-sources, --mcp-config, --disallowedTools, --verbose
  5. Settings sources: user,project,local — Claude CLI setting hierarchy
  6. User config files: .claude.json (MCP), ~/.claude/settings.json

Abstraction Approach

Already partially abstracted (setClaudeBasePathOverride exists). Extend:

interface ProviderConfig {
  basePath: string;
  configFileName: string;
  envVars: Record<string, string>;
  protectedFlags: Set<string>;
  settingSources?: string;
}

Additional Coupling: agent-teams-controller Package

Coupling: 10/10 | Effort: High

The agent-teams-controller/ workspace package is a pure JS module that directly reads/writes Claude Code's team filesystem:

  • runtimeHelpers.js: getPaths() returns ~/.claude/teams/{name}/, ~/.claude/tasks/{name}/
  • context.js: createControllerContext({teamName, claudeDir})
  • tasks.js, kanban.js, review.js, messages.js, etc. — all operate on Claude's file structures

This package would need to be either:

  • Made provider-aware (different file layouts per provider)
  • Replaced with a generic team data layer

Estimated Overall Effort for Full Abstraction

Phase Scope Estimated Effort
Phase 1: Session viewing only Path abstraction + JSONL parser + model parser 2-3 weeks
Phase 2: UI de-branding Rename strings, CSS vars, component names 1 week
Phase 3: CLI provider interface Binary resolution + auth + install 2 weeks
Phase 4: Protocol abstraction stream-json → generic protocol layer 3-4 weeks
Phase 5: Team management abstraction Generic orchestration layer 4-8 weeks
Total Full multi-provider support 12-18 weeks

Priority Order (what to do first)

  1. Paths first (low risk, high reward) — pathDecoder.ts already has override support. Make getBasePath() provider-aware. This unblocks session viewing for other agents.

  2. Session parser second — Create SessionDataProvider interface. The existing ParsedMessage type works as the normalized target. Each provider implements a parser FROM their raw format TO ParsedMessage.

  3. Model/pricing third — Make parseModelString() and pricing lookup provider-aware. Use a registry pattern where each provider registers its models.

  4. CLI provider fourth — Abstract binary resolution, auth, install, spawning. This is where protocol differences become critical.

  5. Team management last — This is the hardest and most Claude-specific feature. Consider keeping it as a Claude-only feature initially.

What's Hardest

  1. stream-json protocol — This is Claude Code's proprietary stdin/stdout protocol. Other agents use completely different paradigms (OpenAI Codex uses sandboxed REST API, Gemini CLI may use different protocol). Abstracting this requires a fundamental architectural decision about how the app communicates with agents.

  2. Agent Teams — No other CLI agent has an equivalent feature. The entire team management subsystem (~35 service files, ~65 IPC handlers, controller package) is built around Claude Code's Agent Teams. Supporting multi-agent orchestration for other providers would essentially mean building this from scratch.

  3. JSONL session format — Claude Code's JSONL format is deeply embedded in the codebase (types, parsers, chunk builders, context trackers). While ParsedMessage serves as a reasonable intermediary, the raw parsing layer touching 10+ files would need provider-specific implementations.

What's Easiest

  1. MCP — Already vendor-neutral. Only config file naming and CLI flag need adjustment.
  2. UI branding — Mechanical string/CSS replacement.
  3. Path configuration — Override mechanism already exists.

Architecture Diagram: Provider-Agnostic Layer

┌─────────────────────────────────────────────────────────────┐
│                        Renderer (UI)                        │
│  Components (generic)  │  Store (generic)  │  Types (generic)│
└────────────────────────────┬────────────────────────────────┘
                             │ IPC
┌────────────────────────────┴────────────────────────────────┐
│                    Provider Manager                          │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐                  │
│  │ Session   │  │ CLI      │  │ Team     │                  │
│  │ Provider  │  │ Provider │  │ Provider │  ← Interfaces    │
│  └─────┬────┘  └─────┬────┘  └─────┬────┘                  │
│        │              │              │                       │
│  ┌─────┴────┐  ┌─────┴────┐  ┌─────┴────────┐             │
│  │ Claude   │  │ Claude   │  │ Claude Agent  │             │
│  │ JSONL    │  │ CLI      │  │ Teams         │  ← Impls    │
│  │ Parser   │  │ Spawner  │  │ Orchestrator  │             │
│  └──────────┘  └──────────┘  └──────────────┘             │
│  ┌──────────┐  ┌──────────┐  ┌──────────────┐             │
│  │ Codex    │  │ Codex    │  │ (not          │             │
│  │ Session  │  │ CLI      │  │  supported)   │  ← Future   │
│  │ Parser   │  │ Spawner  │  │               │             │
│  └──────────┘  └──────────┘  └──────────────┘             │
└─────────────────────────────────────────────────────────────┘
                             │
┌────────────────────────────┴────────────────────────────────┐
│                    Data Path Provider                        │
│  ~/.claude/  │  ~/.codex/  │  ~/.gemini/  │  etc.           │
└─────────────────────────────────────────────────────────────┘

Key Interfaces

CliProvider
├── resolveBinaryPath() → string | null
├── buildSpawnArgs(opts) → string[]
├── buildEnv(binary) → ProcessEnv
├── checkAuth(binary) → AuthStatus
├── getKillSignal() → Signals
└── getProtocolFlags() → string[]

CliProtocol
├── formatInputMessage(text) → string
├── parseOutputLine(line) → ParsedOutput
├── isSuccess(msg) → boolean
├── isError(msg) → boolean
└── isToolApproval(msg) → ToolApproval | null

SessionDataProvider
├── parseSessionFile(path) → AsyncIterable<ParsedMessage>
├── getSessionPaths(basePath) → string[]
├── getSubagentPaths(sessionPath) → string[]
└── encodeProjectPath(path) → string

DataPathProvider
├── getBasePath() → string
├── getProjectsPath() → string
├── getTeamsPath() → string | null
├── getSessionFilePath(project, session) → string
└── getConfigFilePath() → string

TeamOrchestrator (optional per provider)
├── supportsTeams: boolean
├── createTeam(request) → TeamCreateResponse
├── launchTeam(request) → TeamLaunchResponse
├── sendMessage(team, request) → SendMessageResult
└── stopTeam(teamName) → void

ModelInfoProvider
├── parseModelString(model) → ModelInfo | null
├── getModelFamilies() → string[]
├── getPricing(model) → Pricing | null
└── getContextWindow(model) → number

InstructionFileProvider
├── getFilename() → string  // "CLAUDE.md", ".codexrc", etc.
├── getGlobalPath() → string
├── getProjectPath(projectDir) → string
└── getSourceTypes() → string[]

Conclusion

The codebase is deeply coupled to Claude Code at approximately 8.3/10 overall. The coupling is most severe in:

  1. Team management (10/10) — Claude Agent Teams is a unique feature with no equivalent
  2. Protocol (10/10) — stream-json is proprietary
  3. Session data (9/10) — JSONL format, path encoding, file structure
  4. Process management (9/10) — Claude binary, flags, kill semantics

The most pragmatic path to multi-provider support would be a phased approach starting with session viewing (paths + JSONL parser abstraction), which delivers value with ~3 weeks effort, before tackling the much harder protocol and team management layers.

Full abstraction to support other agents with team management would require 12-18 weeks of focused effort, with the protocol and team management layers being the primary engineering challenges.