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:
- Restore session transcript (if new process)
- Build system prompt (first turn only)
- Inject memory context
- Enter tool call loop
- Dispatch tool calls
- Context guard / compression
- Stop hook check
- 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
| Prototype | When to Use |
|---|---|
orchestrator | Top-level agent |
planner | Multi-step decomposition |
researcher | Web / document lookup |
code_executor | Write, run, debug code |
critic | Code review |
summarizer | Compress oversized tool results |
archivist | Memory distillation |
tool_maker | Self-healing — write polyfills for missing commands |
Spawn Tiers and Levels
Three levels:
chat- fast, UX-focusedreasoning- slow, deep thinkingworker- leaf, cannot spawn anything
| Level | Can Spawn | Cannot Spawn |
|---|---|---|
chat | reasoning, worker | another chat |
reasoning | worker | another reasoning, any chat |
worker | nothing | anything |
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
- Architecture Overview - Where it fits in the bigger picture
- Memory Tree - Where memory loaders read and post-turn hooks write
- Model Routing - How
model: "hint:reasoning"resolves to concrete provider+model