Skip to content

Spec: Support OpenAI Codex as an alternative to Claude Code #150

@dhilgaertner

Description

@dhilgaertner

Summary

Investigate and plan what it would take to make Crow agent-agnostic — allowing users to choose OpenAI Codex (or other AI coding agents) as an alternative to Claude Code. This requires a full audit of every Claude Code touchpoint in the codebase and a design for an abstraction layer that supports multiple agents.

Important: Wizard-Style Questions

When working this ticket, present any questions or decisions as a wizard — step-by-step prompts asking me to choose between options, one decision at a time. Don't dump all questions at once.

Why

Crow currently assumes Claude Code as the only AI coding agent. Users may prefer or need to use other tools (Codex, Aider, Cursor agent, etc.). Making the agent pluggable increases Crow's value and reach.

Scope of Investigation

Below is a complete inventory of every Claude Code integration point that needs to be studied and abstracted.

1. Binary Resolution & Launch (3 touchpoints)

File Location What It Does
SessionService.swift lines 551-562 findClaudeBinary() — searches hardcoded paths (~/.local/bin/claude, /usr/local/bin/claude, /opt/homebrew/bin/claude)
AppDelegate.swift lines 780-799 resolveClaudeInCommand() — replaces bare "claude" tokens in terminal commands with full path
SessionService.swift lines 98-99 launchClaude(terminalID:) — sends claude --continue\n to terminal after shell readiness

Questions to answer: How does Codex launch? Is it a CLI binary like Claude? What are its CLI flags? Does it support --continue equivalent?

2. Hook System (17 event types, 3 touchpoints)

File Location What It Does
HookConfigGenerator.swift lines 7-13 Defines 17 hook events: SessionStart, SessionEnd, Stop, StopFailure, Notification, PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest, PermissionDenied, UserPromptSubmit, TaskCreated, TaskCompleted, SubagentStart, SubagentStop, PreCompact, PostCompact
HookConfigGenerator.swift lines 28-90 generateHooks() / writeHookConfig() — writes hook entries to .claude/settings.local.json that invoke crow hook-event
HookConfigGenerator.swift lines 93-120 removeHookConfig() — cleans up hook entries on session deletion

Questions to answer: Does Codex support lifecycle hooks? What events does it emit? Can we get equivalent state signals (working, waiting, idle)?

3. Hook Event State Machine (1 large touchpoint)

File Location What It Does
AppDelegate.swift lines 572-749 hook-event RPC handler — receives events from crow hook-event CLI calls, updates SessionHookState with Claude-specific state transitions (idle → working → waiting → done)

Questions to answer: Can we map Codex lifecycle events to the same state machine? Or do we need a per-agent state mapping?

4. Settings & Skills Scaffolding (3 touchpoints)

File Location What It Does
Scaffolder.swift lines 114-143 bundledSettings() — generates .claude/settings.json with pre-approved permissions for Bash, Read, Write, Edit, etc.
Scaffolder.swift lines 93-111 bundledSkill() — deploys skills/crow-workspace/SKILL.md to .claude/skills/
Scaffolder.swift lines 69-90 bundledCLAUDEMD() — generates/updates CLAUDE.md context file

Questions to answer: Does Codex have an equivalent to .claude/ config directory? Skills? Settings? Context files like CLAUDE.md?

5. Prompt Generation & Templates (2 touchpoints)

File Location What It Does
ClaudeLauncher.swift lines 9-51 generatePrompt() — builds /plan prefixed prompt with workspace context table, ticket info, gh/glab commands
ClaudeLauncher.swift lines 54-62 launchCommand() — writes prompt to temp file, returns cd {path} && claude "$(cat {promptPath})"\n

Questions to answer: How does Codex accept initial prompts? File-based? Stdin? CLI arg? Does it support plan mode?

6. Terminal Readiness & Auto-Launch (3 touchpoints)

File Location What It Does
SessionDetailView.swift lines 350-389 ReadinessAwareTerminal — triggers onLaunchClaude callback when shell reaches .shellReady
AppState.swift line 83 onLaunchClaude: ((UUID) -> Void)? closure
Enums.swift lines 37-45 TerminalReadiness enum (uninitialized → surfaceCreated → shellReady → claudeLaunched) and ClaudeState enum (idle, working, waiting, done)

Questions to answer: Should the readiness enum be renamed to be agent-agnostic? Is the launch flow the same for Codex?

7. UI & Branding References (2 touchpoints)

File Location What It Does
SessionListView.swift lines 217-414 claudeStateBadge — shows Claude state with icon and color in sidebar
SessionDetailView.swift lines 370-380 Loading overlay text while terminal initializes

Questions to answer: Should the UI show which agent is active? Agent-specific icons/colors?

8. Manager Session Integration (1 touchpoint)

File Location What It Does
AppDelegate.swift lines 139-149 onWorkOnIssue — sends /crow-workspace {issueURL}\n to Manager terminal (assumes Claude Code is running)

Questions to answer: The Manager session itself runs Claude Code. Should this also be swappable? Or is the Manager always Claude Code?

9. Notification System (1 touchpoint)

File Location What It Does
NotificationManager.swift lines 51-98 handleEvent() — processes hook events for system notifications and sounds

Questions to answer: Notification events are currently keyed to Claude Code hook names. Need agent-agnostic event mapping.

10. Documentation & Context Files (4 touchpoints)

File Description
CLAUDE.md Manager tab context document (139 lines)
README.md Architecture docs reference Claude Code throughout
skills/crow-workspace/SKILL.md Full workspace setup skill (423 lines)
Resources/*.template Bundled templates for CLAUDE.md and SKILL.md

11. Configuration & Models (2 touchpoints)

File Description
settings.json Pre-approved permissions template (Claude Code specific format)
WorkspaceConfig.swift References CLAUDE.md in keyword sources

Architectural Decisions to Make

  1. Abstraction layer — Should we introduce an AgentProtocol / AgentProvider abstraction? Or use config-driven switching?
  2. Per-session vs global — Can different sessions use different agents? Or is it a global app setting?
  3. Hook compatibility — If Codex doesn't support hooks, do we poll terminal output instead? Or require hooks?
  4. Skill system — Do we need agent-specific skill files, or one universal format?
  5. Manager session — Is the Manager tab always Claude Code? Or also swappable?
  6. Feature parity — What Claude Code features does Codex lack? What's the minimum viable integration?

Suggested Approach

  1. Research Codex CLI capabilities, flags, config format, and lifecycle events
  2. Design an AgentProvider protocol with methods: findBinary(), launchCommand(), generatePrompt(), hookConfig(), settingsConfig()
  3. Implement ClaudeCodeProvider (extracting current behavior) and CodexProvider
  4. Add agent selection to workspace config or session creation
  5. Update UI to be agent-aware
  6. Update documentation and templates

Files That Will Need Changes

~20 files across the codebase:

  • SessionService.swift, AppDelegate.swift, HookConfigGenerator.swift, Scaffolder.swift, ClaudeLauncher.swift
  • SessionDetailView.swift, SessionListView.swift, AppState.swift, Enums.swift
  • NotificationManager.swift, CrowCLI.swift, WorkspaceConfig.swift
  • CLAUDE.md, README.md, SKILL.md, settings.json, template files

Priority: 3/10
Effort: Large (multi-day)

Metadata

Metadata

Assignees

Labels

refactorCode refactoring and cleanup

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions