Skip to main content

Agent Harness

The agent harness is the runtime that transforms user messages (or webhook triggers, or cron ticks) into full, tool-using LLM interactions. It owns the tool call loop, sub-agent dispatch, trigger triage pipeline, and the hook surface around them.

Shape of a Turn

Each turn — whether the user just typed a message, a Telegram webhook fired, or a 9am cron tick — goes through the same lifecycle:

inbound → trigger triage → Agent::turn() → post-turn hooks

Inside Agent::turn:

  1. Restore session transcript (if new process)
  2. Build system prompt (first turn only)
  3. Inject memory context
  4. Enter tool call loop
  5. Dispatch tool calls
  6. Context guard / compression
  7. Stop hook check
  8. Final assistant text

Tool Call Loop

Inside Agent::turn, the tool call loop runs for up to max_tool_iterations rounds (default 10):

loop {
1. Context guard - if history too large, micro-compress / auto-compress
2. Stop hook check - budget cap, max iterations, custom kill switch
3. Provider call - send message + tool specs, stream response
4. Parse response - separate assistant text from tool calls
5. If no tool calls - return final text
6. Execute tool calls - dispatch each (next section)
7. Summarize oversize - route huge tool outputs through summarizer agent
8. Append results - push tool results into history, loop
}

Sub-agents - Orchestrator Pattern

OpenHuman is multi-agent. The agent the user chats with is the orchestrator — a high-level, strategy-level agent that decides when to answer directly, when to use a tool directly, and when to spawn a specialized sub-agent.

Built-in Prototypes

PrototypeWhen to Use
orchestratorTop-level agent
plannerMulti-step decomposition
researcherWeb / document lookup
code_executorWrite, run, debug code
criticCode review
summarizerCompress oversized tool results
archivistMemory distillation
tool_makerSelf-healing — write polyfills for missing commands

Spawn Tiers and Levels

Three levels:

  • chat - fast, UX-focused
  • reasoning - slow, deep thinking
  • worker - leaf, cannot spawn anything
LevelCan SpawnCannot Spawn
chatreasoning, workeranother chat
reasoningworkeranother reasoning, any chat
workernothinganything

Trigger Triage

When a webhook fires, a cron tick arrives, or a Composio event comes in, the system cannot just hand it to the orchestrator. The trigger triage pipeline is the gate:

TriggerEnvelope → run_triage → TriageDecision → apply_decision

├─► drop (noise)
├─► notify only
├─► spawn trigger_reactor
└─► spawn orchestrator

Hooks

Stop Hooks (During a Turn)

Stop hooks fire between iterations of the tool call loop. They are the strategic levers for budget caps, rate limits, and custom kill switches.

Post-turn Hooks

Post-turn hooks fire in the background after a turn completes. Built-in consumers:

  • Archivist - distills which facts are worth persisting
  • Learning - reflections, tool tracker, user profile updates
  • Cost log - final per-turn cost line

Interruption

When the user presses Ctrl+C or sends /stop:

  • The interrupt fence flips
  • Every running sub-agent sees the same flag and exits at its next checkpoint
  • In-flight provider streams are discarded
  • The archivist still fires with any partial context, so the conversation is not lost

Next Steps