Harnesses

A harness is the agent runtime Athena wraps. The harness abstraction isolates Athena's workflow, plugin, and UI systems from the specifics of any one agent.

Supported Harnesses

HarnessStatusIntegration
claude-codeProductionHook-forwarding over Unix Domain Socket
openai-codexProductionJSON-RPC via app-server protocol
opencodeComing soonTBD

Architecture

Claude Code:

Claude Code → athena-hook-forwarder (stdin) → UDS NDJSON → Athena runtime

OpenAI Codex:

Codex → codex-app-server (JSON-RPC) → Athena runtime

Both produce normalized RuntimeEvent objects. Workflows, plugins, and the UI work identically regardless of harness.

Harness Capabilities

FeatureClaude CodeCodex
Session persistenceYesYes
MCP serversYesYes
WorkflowsYesYes
Isolation presetsYesYes
Ephemeral sessionsYesYes
Skills / commandsYesYes
Hook events13 event typesEvent translation layer

How Claude Code Integration Works

  1. Hook registration — Athena generates a temporary settings file registering athena-hook-forwarder for all Claude Code hook events. Tool events use a "*" matcher to receive all tool calls.
  2. Event forwarding — Claude Code calls the forwarder synchronously at each lifecycle point. The forwarder reads stdin, writes NDJSON to the UDS, and exits in single-digit milliseconds.
  3. Socket transport — Per-instance socket at <projectDir>/.claude/run/ink-<PID>.sock. Local-only, no port management.

How Codex Integration Works

  1. App-server protocol — Athena communicates with Codex via a JSON-RPC protocol through codex-app-server.
  2. Event translation — Codex events are mapped to Athena's RuntimeEvent schema with a comprehensive translation layer.
  3. Decision mappingRuntimeDecision objects are converted back to Codex-compatible JSON-RPC responses.
  4. Turn management — Codex uses a persistent thread conversation model with turn-based session management.

The RuntimeConnector Interface

Each harness implements:

type Runtime = {
  start(): void;
  stop(): void;
  getStatus(): 'stopped' | 'running';
  onEvent(handler: RuntimeEventHandler): () => void;
  onDecision(handler: RuntimeDecisionHandler): () => void;
  sendDecision(eventId: string, decision: RuntimeDecision): void;
}

Plugin and workflow authors work with normalized RuntimeEvent types — they never interact with the harness interface directly.

Configuration

{
  "harness": "claude-code"
}

Or for Codex:

{
  "harness": "openai-codex"
}

Set via config file or the setup wizard.