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
| Harness | Status | Integration |
|---|---|---|
claude-code | Production | Hook-forwarding over Unix Domain Socket |
openai-codex | Production | JSON-RPC via app-server protocol |
opencode | Coming soon | TBD |
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
| Feature | Claude Code | Codex |
|---|---|---|
| Session persistence | Yes | Yes |
| MCP servers | Yes | Yes |
| Workflows | Yes | Yes |
| Isolation presets | Yes | Yes |
| Ephemeral sessions | Yes | Yes |
| Skills / commands | Yes | Yes |
| Hook events | 13 event types | Event translation layer |
How Claude Code Integration Works
- Hook registration — Athena generates a temporary settings file registering
athena-hook-forwarderfor all Claude Code hook events. Tool events use a"*"matcher to receive all tool calls. - 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.
- Socket transport — Per-instance socket at
<projectDir>/.claude/run/ink-<PID>.sock. Local-only, no port management.
How Codex Integration Works
- App-server protocol — Athena communicates with Codex via a JSON-RPC protocol through
codex-app-server. - Event translation — Codex events are mapped to Athena's
RuntimeEventschema with a comprehensive translation layer. - Decision mapping —
RuntimeDecisionobjects are converted back to Codex-compatible JSON-RPC responses. - 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.