# 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 200–800ms 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 ```typescript 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>`. 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") 120–400 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 ```json { "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 ```typescript 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() ```typescript async function seedAiIdentity( agentPeer: Peer, content: string, source: string ): Promise { const wrapped = [ ``, `${source}`, ``, content.trim(), ``, ].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: ```typescript const namePrefix = agentName ? `You are ${agentName}.\n\n` : ""; return { systemPrompt: namePrefix + "## User Memory Context\n\n" + sections }; ``` ### CLI surface ``` honcho identity # 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 ```json { "sessionStrategy": "per-directory", "sessionPeerPrefix": false, "sessions": { "/home/user/projects/foo": "foo-project" } } ``` ### CLI surface ``` honcho sessions # list all mappings honcho map # 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 — 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