Files
hermes-agent/docs/honcho-integration-spec.md

15 KiB
Raw Blame History

honcho-integration-spec

Comparison of Hermes Agent vs. openclaw-honcho — and a porting spec for bringing Hermes patterns into other Honcho integrations.


Overview

Two independent Honcho integrations have been built for two different agent runtimes: Hermes Agent (Python, baked into the runner) and openclaw-honcho (TypeScript plugin via hook/tool API). Both use the same Honcho peer paradigm — dual peer model, session.context(), peer.chat() — but they made different tradeoffs at every layer.

This document maps those tradeoffs and defines a porting spec: a set of Hermes-originated patterns, each stated as an integration-agnostic interface, that any Honcho integration can adopt regardless of runtime or language.

Scope Both integrations work correctly today. This spec is about the delta — patterns in Hermes that are worth propagating and patterns in openclaw-honcho that Hermes should eventually adopt. The spec is additive, not prescriptive.


Architecture comparison

Hermes: baked-in runner

Honcho is initialised directly inside AIAgent.__init__. There is no plugin boundary. Session management, context injection, async prefetch, and CLI surface are all first-class concerns of the runner. Context is injected once per session (baked into _cached_system_prompt) and never re-fetched mid-session — this maximises prefix cache hits at the LLM provider.

Turn flow:

user message
  → _honcho_prefetch()       (reads cache — no HTTP)
  → _build_system_prompt()   (first turn only, cached)
  → LLM call
  → response
  → _honcho_fire_prefetch()  (daemon threads, turn end)
       → prefetch_context() thread  ──┐
       → prefetch_dialectic() thread ─┴→ _context_cache / _dialectic_cache

openclaw-honcho: hook-based plugin

The plugin registers hooks against OpenClaw's event bus. Context is fetched synchronously inside before_prompt_build on every turn. Message capture happens in agent_end. The multi-agent hierarchy is tracked via subagent_spawned. This model is correct but every turn pays a blocking Honcho round-trip before the LLM call can begin.

Turn flow:

user message
  → before_prompt_build (BLOCKING HTTP — every turn)
       → session.context()
  → system prompt assembled
  → LLM call
  → response
  → agent_end hook
       → session.addMessages()
       → session.setMetadata()

Diff table

Dimension Hermes Agent openclaw-honcho
Context injection timing Once per session (cached). Zero HTTP on response path after turn 1. Every turn, blocking. Fresh context per turn but adds latency.
Prefetch strategy Daemon threads fire at turn end; consumed next turn from cache. None. Blocking call at prompt-build time.
Dialectic (peer.chat) Prefetched async; result injected into system prompt next turn. On-demand via honcho_recall / honcho_analyze tools.
Reasoning level Dynamic: scales with message length. Floor = config default. Cap = "high". Fixed per tool: recall=minimal, analyze=medium.
Memory modes user_memory_mode / agent_memory_mode: hybrid / honcho / local. None. Always writes to Honcho.
Write frequency async (background queue), turn, session, N turns. After every agent_end (no control).
AI peer identity observe_me=True, seed_ai_identity(), get_ai_representation(), SOUL.md → AI peer. Agent files uploaded to agent peer at setup. No ongoing self-observation.
Context scope User peer + AI peer representation, both injected. User peer (owner) representation + conversation summary. peerPerspective on context call.
Session naming per-directory / global / manual map / title-based. Derived from platform session key.
Multi-agent Single-agent only. Parent observer hierarchy via subagent_spawned.
Tool surface Single query_user_context tool (on-demand dialectic). 6 tools: session, profile, search, context (fast) + recall, analyze (LLM).
Platform metadata Not stripped. Explicitly stripped before Honcho storage.
Message dedup None. lastSavedIndex in session metadata prevents re-sending.
CLI surface in prompt Management commands injected into system prompt. Agent knows its own CLI. Not injected.
AI peer name in identity Replaces "Hermes Agent" in DEFAULT_AGENT_IDENTITY when configured. Not implemented.
QMD / local file search Not implemented. Passthrough tools when QMD backend configured.
Workspace metadata Not implemented. agentPeerMap in workspace metadata tracks agent→peer ID.

Patterns

Six patterns from Hermes are worth adopting in any Honcho integration. Each is described as an integration-agnostic interface.

Hermes contributes:

  • Async prefetch (zero-latency)
  • Dynamic reasoning level
  • Per-peer memory modes
  • AI peer identity formation
  • Session naming strategies
  • CLI surface injection

openclaw-honcho contributes back (Hermes should adopt):

  • lastSavedIndex dedup
  • Platform metadata stripping
  • Multi-agent observer hierarchy
  • peerPerspective on context()
  • Tiered tool surface (fast/LLM)
  • Workspace agentPeerMap

Spec: async prefetch

Problem

Calling session.context() and peer.chat() synchronously before each LLM call adds 200800ms of Honcho round-trip latency to every turn.

Pattern

Fire both calls as non-blocking background work at the end of each turn. Store results in a per-session cache keyed by session ID. At the start of the next turn, pop from cache — the HTTP is already done. First turn is cold (empty cache); all subsequent turns are zero-latency on the response path.

Interface contract

interface AsyncPrefetch {
  // Fire context + dialectic fetches at turn end. Non-blocking.
  firePrefetch(sessionId: string, userMessage: string): void;

  // Pop cached results at turn start. Returns empty if cache is cold.
  popContextResult(sessionId: string): ContextResult | null;
  popDialecticResult(sessionId: string): string | null;
}

type ContextResult = {
  representation: string;
  card: string[];
  aiRepresentation?: string;  // AI peer context if enabled
  summary?: string;           // conversation summary if fetched
};

Implementation notes

  • Python: threading.Thread(daemon=True). Write to dict[session_id, result] — GIL makes this safe for simple writes.
  • TypeScript: Promise stored in Map<string, Promise<ContextResult>>. Await at pop time. If not resolved yet, return null — do not block.
  • The pop is destructive: clears the cache entry after reading so stale data never accumulates.
  • Prefetch should also fire on first turn (even though it won't be consumed until turn 2).

openclaw-honcho adoption

Move session.context() from before_prompt_build to a post-agent_end background task. Store result in state.contextCache. In before_prompt_build, read from cache instead of calling Honcho. If cache is empty (turn 1), inject nothing — the prompt is still valid without Honcho context on the first turn.


Spec: dynamic reasoning level

Problem

Honcho's dialectic endpoint supports reasoning levels from minimal to max. A fixed level per tool wastes budget on simple queries and under-serves complex ones.

Pattern

Select the reasoning level dynamically based on the user's message. Use the configured default as a floor. Bump by message length. Cap auto-selection at high — never select max automatically.

Logic

< 120 chars  → default (typically "low")
120400 chars → one level above default (cap at "high")
> 400 chars  → two levels above default (cap at "high")

Config key

Add dialecticReasoningLevel (string, default "low"). This sets the floor. The dynamic bump always applies on top.

openclaw-honcho adoption

Apply in honcho_recall and honcho_analyze: replace fixed reasoningLevel with the dynamic selector. honcho_recall uses floor "minimal", honcho_analyze uses floor "medium" — both still bump with message length.


Spec: per-peer memory modes

Problem

Users want independent control over whether user context and agent context are written locally, to Honcho, or both.

Modes

Mode Effect
hybrid Write to both local files and Honcho (default)
honcho Honcho only — disable corresponding local file writes
local Local files only — skip Honcho sync for this peer

Config schema

{
  "memoryMode": "hybrid",
  "userMemoryMode": "honcho",
  "agentMemoryMode": "hybrid"
}

Resolution order: per-peer field wins → shorthand memoryMode → default "hybrid".

Effect on Honcho sync

  • userMemoryMode=local: skip adding user peer messages to Honcho
  • agentMemoryMode=local: skip adding assistant peer messages to Honcho
  • Both local: skip session.addMessages() entirely
  • userMemoryMode=honcho: disable local USER.md writes
  • agentMemoryMode=honcho: disable local MEMORY.md / SOUL.md writes

Spec: AI peer identity formation

Problem

Honcho builds the user's representation organically by observing what the user says. The same mechanism exists for the AI peer — but only if observe_me=True is set for the agent peer. Without it, the agent peer accumulates nothing.

Additionally, existing persona files (SOUL.md, IDENTITY.md) should seed the AI peer's Honcho representation at first activation.

Part A: observe_me=True for agent peer

await session.addPeers([
  [ownerPeer.id, { observeMe: true,  observeOthers: false }],
  [agentPeer.id, { observeMe: true,  observeOthers: true  }], // was false
]);

One-line change. Foundational. Without it, the AI peer representation stays empty regardless of what the agent says.

Part B: seedAiIdentity()

async function seedAiIdentity(
  agentPeer: Peer,
  content: string,
  source: string
): Promise<boolean> {
  const wrapped = [
    `<ai_identity_seed>`,
    `<source>${source}</source>`,
    ``,
    content.trim(),
    `</ai_identity_seed>`,
  ].join("\n");

  await agentPeer.addMessage("assistant", wrapped);
  return true;
}

Part C: migrate agent files at setup

During honcho setup, upload agent-self files (SOUL.md, IDENTITY.md, AGENTS.md) to the agent peer via seedAiIdentity() instead of session.uploadFile(). This routes content through Honcho's observation pipeline.

Part D: AI peer name in identity

When the agent has a configured name, prepend it to the injected system prompt:

const namePrefix = agentName ? `You are ${agentName}.\n\n` : "";
return { systemPrompt: namePrefix + "## User Memory Context\n\n" + sections };

CLI surface

honcho identity <file>    # seed from file
honcho identity --show    # show current AI peer representation

Spec: session naming strategies

Problem

A single global session means every project shares the same Honcho context. Per-directory sessions provide isolation without requiring users to name sessions manually.

Strategies

Strategy Session key When to use
per-directory basename of CWD Default. Each project gets its own session.
global fixed string "global" Single cross-project session.
manual map user-configured per path sessions config map overrides directory basename.
title-based sanitized session title When agent supports named sessions set mid-conversation.

Config schema

{
  "sessionStrategy": "per-directory",
  "sessionPeerPrefix": false,
  "sessions": {
    "/home/user/projects/foo": "foo-project"
  }
}

CLI surface

honcho sessions              # list all mappings
honcho map <name>            # map cwd to session name
honcho map                   # no-arg = list mappings

Resolution order: manual map → session title → directory basename → platform key.


Spec: CLI surface injection

Problem

When a user asks "how do I change my memory settings?" the agent either hallucinates or says it doesn't know. The agent should know its own management interface.

Pattern

When Honcho is active, append a compact command reference to the system prompt. Keep it under 300 chars.

# Honcho memory integration
Active. Session: {sessionKey}. Mode: {mode}.
Management commands:
  honcho status                    — show config + connection
  honcho mode [hybrid|honcho|local] — show or set memory mode
  honcho sessions                  — list session mappings
  honcho map <name>                — map directory to session
  honcho identity [file] [--show]  — seed or show AI identity
  honcho setup                     — full interactive wizard

openclaw-honcho checklist

Ordered by impact:

  • Async prefetch — move session.context() out of before_prompt_build into post-agent_end background Promise
  • observe_me=True for agent peer — one-line change in session.addPeers()
  • Dynamic reasoning level — add helper; apply in honcho_recall and honcho_analyze; add dialecticReasoningLevel to config
  • Per-peer memory modes — add userMemoryMode / agentMemoryMode to config; gate Honcho sync and local writes
  • seedAiIdentity() — add helper; use during setup migration for SOUL.md / IDENTITY.md
  • Session naming strategies — add sessionStrategy, sessions map, sessionPeerPrefix
  • CLI surface injection — append command reference to before_prompt_build return value
  • honcho identity subcommand — seed from file or --show current representation
  • AI peer name injection — if aiPeer name configured, prepend to injected system prompt
  • honcho mode / sessions / map — CLI parity with Hermes

Already done in openclaw-honcho (do not re-implement): lastSavedIndex dedup, platform metadata stripping, multi-agent parent observer, peerPerspective on context(), tiered tool surface, workspace agentPeerMap, QMD passthrough, self-hosted Honcho.


nanobot-honcho checklist

Greenfield integration. Start from openclaw-honcho's architecture and apply all Hermes patterns from day one.

Phase 1 — core correctness

  • Dual peer model (owner + agent peer), both with observe_me=True
  • Message capture at turn end with lastSavedIndex dedup
  • Platform metadata stripping before Honcho storage
  • Async prefetch from day one — do not implement blocking context injection
  • Legacy file migration at first activation (USER.md → owner peer, SOUL.md → seedAiIdentity())

Phase 2 — configuration

  • Config schema: apiKey, workspaceId, baseUrl, memoryMode, userMemoryMode, agentMemoryMode, dialecticReasoningLevel, sessionStrategy, sessions
  • Per-peer memory mode gating
  • Dynamic reasoning level
  • Session naming strategies

Phase 3 — tools and CLI

  • Tool surface: honcho_profile, honcho_recall, honcho_analyze, honcho_search, honcho_context
  • CLI: setup, status, sessions, map, mode, identity
  • CLI surface injection into system prompt
  • AI peer name wired into agent identity