From 85239a69b262c944de3c35900b91c88ba9b84f1a Mon Sep 17 00:00:00 2001
From: ajspig <46900795+ajspig@users.noreply.github.com>
Date: Wed, 27 May 2026 15:25:55 -0400
Subject: [PATCH] Updating Design Patterns (#717)
* docs: draft of design-patterns
* fix: minor language changes
* docs: adding unified memory guide
* docs: simplifying design patterns
* docs: minor edits
* docs: language clarification
* docs: simplification of intro
---
docs/docs.json | 1 +
.../core-concepts/design-patterns.mdx | 357 ++----------------
docs/v3/guides/overview.mdx | 9 +
.../guides/recipes/unified-memory-setup.mdx | 186 +++++++++
4 files changed, 237 insertions(+), 316 deletions(-)
create mode 100644 docs/v3/guides/recipes/unified-memory-setup.mdx
diff --git a/docs/docs.json b/docs/docs.json
index 5ccb4166..64b56d86 100644
--- a/docs/docs.json
+++ b/docs/docs.json
@@ -110,6 +110,7 @@
{
"group": "Tutorials",
"pages": [
+ "v3/guides/recipes/unified-memory-setup",
"v3/guides/discord",
"v3/guides/granola",
"v3/guides/telegram",
diff --git a/docs/v3/documentation/core-concepts/design-patterns.mdx b/docs/v3/documentation/core-concepts/design-patterns.mdx
index 0e35114e..06582d80 100644
--- a/docs/v3/documentation/core-concepts/design-patterns.mdx
+++ b/docs/v3/documentation/core-concepts/design-patterns.mdx
@@ -5,364 +5,92 @@ icon: "cubes"
---
-If you're using a coding agent (Claude Code, OpenCode, Cursor, etc.), the **`/honcho-integration` skill** walks you through these decisions interactively. It explores your codebase, interviews you about peers and sessions, and generates the integration code. The patterns below are the same ones the skill uses.
+This page covers **how to structure** workspaces, peers, and sessions for real applications. For the conceptual model behind them, start with [Architecture](/v3/documentation/core-concepts/architecture).
+
+Ready to add Honcho to your codebase? The **`/honcho-integration` skill** applies these patterns for you — it explores your code, asks how your peers and sessions should map to your app, and wires in the Honcho SDK. Run it in any coding agent that supports skills (Claude Code, Cursor, and others).
## Quick Reference
+**Workspaces isolate, peers persist, and sessions scope the active context.**
+
| Decision | Recommendation |
|----------|---------------|
-| How many workspaces? | One per application. Separate per-agent if you need hard data isolation. |
-| Who should be a peer? | Any entity you want Honcho to reason about — users, agents, NPCs, students, customers. |
-| How should I scope sessions? | Flexible -- per-conversation, per-channel, per-scene, etc. See [Session Design](#session-design) below. |
-| Should I set `observe_me: false`? | Yes, for any peer you don't need Honcho to build a representation of — typically assistants or bots with deterministic behavior. |
-| Do I need `observe_others`? | Only when different peers need distinct views of the same participant (e.g., games, multi-agent). Most apps can leave it at the default (false). |
+| How many workspaces? | One workspace per application, tool, tenant, or collaboration boundary. Split workspaces only when you need hard isolation between products, customers, environments, or agents. |
+| When should agents share a workspace? | When agents collaborate over the same product, project, team, user, customer, or game state. Separate them when they should not see or influence each other's memory. |
+| Who should be a peer? | Any persistent participant whose messages should be attributed or reasoned about: users, agents, assistants, NPCs, students, or customers. Use one peer for the same entity across sessions and platforms. |
+| How should I scope sessions? | Scope sessions to the active interaction: per-conversation, per-channel, per-task run, per-project, per-import, or other bounded context. Reuse a session when local context should keep accumulating. |
+| How does cross-session reasoning work? | Session memory stays local to one session. Peer representations accumulate across every session where the peer is included, and `session.context()` becomes cross-session when you include a peer target. |
+| Should I set `observe_me: false`? | Yes, for deterministic peers Honcho does not need to model, like bots or tool agents. Still save their messages so other peers have session context. Keep it enabled for users and evolving agents. |
+| Do I need `observe_others`? | Only when a peer needs its own perspective on another participant, such as in games, multi-agent systems, or parent/subagent workflows. |
## Workspace Design
-Workspaces are the top-level container. Everything inside a workspace (peers, sessions, messages, and all reasoning) is fully isolated from other workspaces.
+A workspace is a hard isolation boundary. **Default to one workspace per application,** and split only at a real privacy, compliance, or product boundary (e.g. per-tenant SaaS, or a tool that needs intentionally isolated memory). Agents that collaborate over the same product, user, or game state belong in the *same* workspace so each can retrieve what the others produced.
-**One workspace per application** is the most common pattern. Use separate workspaces when you need hard isolation:
-
-| Pattern | When to use |
-|---------|-------------|
-| Single workspace | Most applications. One product, one environment. |
-| Per-tenant | Multi-tenant SaaS where each customer's data must be completely isolated. |
+Honcho plugins default to one workspace *per host* (`hermes`, `claude_code`, `cursor`, `opencode`). To unify memory across them, point each at the same workspace — see [Unified Memory Setup](/v3/guides/recipes/unified-memory-setup).
-If you are using the SDK, it will create a workspace called `default` if no name is specified for `workspace_id`
+The SDK creates a workspace called `default` when no `workspace_id` is specified.
---
## Peer Design
-A peer is any entity that participates in a session. Observation settings control which ones Honcho reasons about.
+Give each real-world entity **one** stable peer ID and reuse it everywhere — splitting one entity across `user-web`, `user-discord`, and `user-slack` builds three separate representations. Prefix IDs by source for multi-channel apps (`discord_491827364`), and if a peer goes by multiple names, store the aliases in its peer card with `set_card()` / `setCard()`.
-**What makes a good peer?**
-
-- It participates in sessions (a user, an agent, a character, an NPC)
-- It persists across sessions
-- It changes over time (preferences shift, knowledge grows), or it produces messages you want Honcho to see
-
-**Naming conventions**
-
-Give peers stable, unique identifiers scoped to your application:
-
-
-```python Python
-# Prefix with the source platform for multi-channel apps
-peer = honcho.peer("discord_491827364")
-peer = honcho.peer("slack_U04ABCDEF")
-
-# Use your own user IDs for backend integrations
-peer = honcho.peer("user_abc123")
-
-# Use descriptive names for agents/assistants
-peer = honcho.peer("assistant")
-peer = honcho.peer("dungeon-master")
-```
-
-```typescript TypeScript
-// Prefix with the source platform for multi-channel apps
-const peer = await honcho.peer("discord_491827364");
-const peer = await honcho.peer("slack_U04ABCDEF");
-
-// Use your own user IDs for backend integrations
-const peer = await honcho.peer("user_abc123");
-
-// Use descriptive names for agents/assistants
-const peer = await honcho.peer("assistant");
-const peer = await honcho.peer("dungeon-master");
-```
-
-
-If your Peer represents an entity that may go by multiple different names, such as nicknames indicate that in the Peer Card:
-
-
-```python Python
-peer = honcho.peer("user_abc123")
-peer.set_card([
- "Name: Alice. Also known as 'Ali' and 'A'.",
- "College student, prefers casual tone.",
-])
-```
-
-```typescript TypeScript
-const peer = await honcho.peer("user_abc123");
-await peer.setCard([
- "Name: Alice. Also known as 'Ali' and 'A'.",
- "College student, prefers casual tone.",
-]);
-```
-
-
-**When to disable reasoning**
-
-Not every peer needs a representation. Set `observe_me: false` on peers that behave deterministically.
-
-
-```python Python
-from honcho.api_types import PeerConfig
-
-# The assistant doesn't need a representation
-assistant = honcho.peer("assistant", configuration=PeerConfig(observe_me=False))
-
-# The user does--this is who you want to understand
-user = honcho.peer("user-123", configuration=PeerConfig(observe_me=True))
-```
-
-```typescript TypeScript
-const assistant = await honcho.peer("assistant", { configuration: { observeMe: false } });
-const user = await honcho.peer("user-123", { configuration: { observeMe: true } });
-```
-
+
+For unified context across Honcho plugins, set the same user peer ID (`peerName`) everywhere — that shared ID is what connects memory across Claude Code, Cursor, OpenCode, and your own app. See [Unified Memory Setup](/v3/guides/recipes/unified-memory-setup).
+
---
## Session Design
-Sessions define the temporal boundaries of an interaction. How you scope sessions directly affects how summaries are generated and how context is retrieved.
+Sessions define the temporal boundaries of an interaction. How you scope them affects how summaries are generated, how context is retrieved, and when reasoning fires.
**Common session patterns**
| Pattern | Session scoped to | Example |
|---------|-------------------|---------|
-| Per-conversation | Each new chat thread | ChatGPT-style UI where each thread is a session |
+| Per-conversation | Each new chat thread | ChatGPT or Claude Code style UI where each thread is a session |
| Per-channel | A persistent channel or room | Discord channel, Slack thread |
| Per-interaction | A bounded task or encounter | A support ticket, a game encounter |
+| Per-project | A persistent work area | Coding agent memory for one repository |
| Per-import | A batch of external data | Importing emails or documents for a single peer |
-**When to create new sessions vs reuse**
+Create a **new** session when context resets (new conversation, new day, new topic); **reuse** one when context should keep accumulating (ongoing channel, persistent thread).
-- **New session** when the context resets (new conversation, new day, new topic)
-- **Reuse session** when context should accumulate (ongoing channel, persistent thread)
+
+**Don't scope sessions too thin.** Honcho only reasons over a peer once it accumulates ~1,000 tokens *within a single session* ([token batching](/v3/documentation/core-concepts/reasoning#token-batching)). Many tiny sessions each stall below that threshold, so low-volume or trickle inputs should append to one ongoing session rather than fragment across many (nothing is lost — it just waits).
+
+
+**How cross-session reasoning works**
+
+- **Session memory** is local to an interaction — summaries and recent-message context describe only what happened there.
+- **Peer memory** (representations) accumulates reasoning across every session the peer is part of.
+
+So you can start a session fresh or pull in a peer's long-term memory. [`session.context()`](/v3/documentation/features/get-context) returns the current session's summary and recent messages; add a [peer target](/v3/documentation/features/get-context#peer-representation-in-context) to fold in that peer's cross-session history.
---
-## Application Patterns
-
-### AI Companions
-
-An assistant that remembers the user across sessions and platforms. The [Honcho plugin for OpenClaw](/v3/guides/integrations/openclaw) is a production example--one assistant with memory across WhatsApp, Telegram, Discord, and Slack.
-
-
-```python Python
-from honcho import Honcho
-from honcho.api_types import PeerConfig, SessionPeerConfig
-
-honcho = Honcho(workspace_id="my-companion-app")
-
-owner = honcho.peer("owner")
-agent = honcho.peer("agent-main", configuration=PeerConfig(observe_me=False))
-
-# Session key = thread + platform → separate histories, shared user memory
-session = honcho.session("general-discord")
-session.add_peers([
- (owner, SessionPeerConfig(observe_me=True, observe_others=False)),
- (agent, SessionPeerConfig(observe_me=True, observe_others=True)),
-])
-
-session.add_messages([
- owner.message("I've been stressed about the move to Portland next month"),
- agent.message("Moving is a big deal. What's weighing on you the most?"),
- owner.message("Honestly just leaving my friend group behind"),
-])
-
-# Query from any session or platform
-response = owner.chat("What's going on in this user's life right now?")
-```
-
-```typescript TypeScript
-const honcho = new Honcho({ workspaceId: "my-companion-app" });
-
-const owner = await honcho.peer("owner");
-const agent = await honcho.peer("agent-main", { configuration: { observeMe: false } });
-
-const session = await honcho.session("general-discord");
-await session.addPeers([
- ["owner", { observeMe: true, observeOthers: false }],
- ["agent-main", { observeMe: true, observeOthers: true }],
-]);
-
-await session.addMessages([
- owner.message("I've been stressed about the move to Portland next month"),
- agent.message("Moving is a big deal. What's weighing on you the most?"),
- owner.message("Honestly just leaving my friend group behind"),
-]);
-
-const response = await owner.chat("What's going on in this user's life right now?");
-```
-
-
-**Key decisions (from the [OpenClaw plugin](/v3/guides/integrations/openclaw)):**
-- **Session key = thread + platform** — `general-discord` and `general-telegram` are separate sessions but share a single owner representation, so Honcho learns from every channel
-- **Dynamic agent peers** — each agent gets its own peer (`agent-{id}`), resolved via a workspace-level map. Renaming an agent recovers the peer by metadata lookup
-- **Subagent hierarchy** — when a primary agent spawns a subagent, the parent joins the child's session as a silent observer (`observe_me: false, observe_others: true`), giving Honcho visibility into the full agent tree
-- **Asymmetric observation** — both owner and agent are observed, but with different scopes: owner has `observe_others: false` (default view), while the agent has `observe_others: true` so it can build its own representation of the owner. Subagents get lighter context (peer card only, no session summary)
-
-See the [OpenClaw integration guide](/v3/guides/integrations/openclaw) for the full plugin setup.
-
----
-
-### Coding Agents
-
-Coding agents survive terminal restarts, editor switches, and project hops. The [Honcho plugin for Claude Code](/v3/guides/integrations/claude-code) is a production example of this pattern.
-
-
-```python Python
-from honcho import Honcho
-from honcho.api_types import PeerConfig
-
-honcho = Honcho(workspace_id="claude_code")
-
-# Developer is observed; agent is not
-developer = honcho.peer("user")
-agent = honcho.peer("claude", configuration=PeerConfig(observe_me=False))
-
-# Session per project directory -- stable across restarts
-session = honcho.session("user-honcho-repo")
-session.add_peers([developer, agent])
-
-session.add_messages([
- developer.message("refactor the auth module to use dependency injection"),
- agent.message("I'll extract the auth dependencies into a provider pattern..."),
- developer.message("actually let's keep it simpler, just pass the config directly"),
-])
-
-# In a future session, query what Honcho learned
-context = developer.chat("What are this developer's preferences for code architecture?")
-# Honcho knows: prefers simplicity, reverses decisions when simpler approach exists
-```
-
-```typescript TypeScript
-const honcho = new Honcho({ workspaceId: "claude_code" });
-
-const developer = await honcho.peer("user");
-const agent = await honcho.peer("claude", { configuration: { observeMe: false } });
-
-const session = await honcho.session("user-honcho-repo");
-await session.addPeers([developer, agent]);
-
-await session.addMessages([
- developer.message("refactor the auth module to use dependency injection"),
- agent.message("I'll extract the auth dependencies into a provider pattern..."),
- developer.message("actually let's keep it simpler, just pass the config directly"),
-]);
-
-const context = await developer.chat("What are this developer's preferences for code architecture?");
-```
-
-
-**Key decisions (from the Claude Code plugin):**
-- **One workspace per tool** -- Claude Code and Cursor each get their own workspace, with optional cross-linking for read access
-- **Asymmetric peers** -- developer is observed (memory formation), agent is not observed but still stores messages so Honcho sees both sides
-- **Session-per-directory** by default -- each project accumulates its own memory. Prefix with peer name (`user-honcho-repo`) so multiple developers on the same workspace don't collide. Alternative strategies: `git-branch` (session switches on branch change) or `chat-instance` (clean slate each time)
-- **Filter what you store** -- user messages go in real-time; agent messages are filtered to skip trivial tool output and keep substantive explanations
-- **Import external data** with single-peer sessions to ingest READMEs, architecture docs, or commit history into a developer's representation
-
-See the [Claude Code integration guide](/v3/guides/integrations/claude-code) for the full plugin setup.
-
----
-
-### Games
-
-Games introduce multi-peer scenarios where **information asymmetry matters**. An NPC should only know what it has witnessed, not the full game state.
-
-
-```python Python
-from honcho import Honcho
-from honcho.api_types import SessionPeerConfig
-
-honcho = Honcho(workspace_id="my-rpg")
-
-# Every character is a peer
-player = honcho.peer("player-one")
-merchant = honcho.peer("merchant-grim")
-thief = honcho.peer("thief-shadow")
-
-# Scene 1: Player talks to the merchant
-tavern = honcho.session("tavern-scene")
-tavern.add_peers([player, merchant])
-
-# Enable the merchant to build its own representation of the player
-tavern.set_peer_configuration(merchant, SessionPeerConfig(observe_others=True))
-
-tavern.add_messages([
- player.message("I'm looking for a rare gemstone. Money is no object."),
- merchant.message("I may know of one... but it won't come cheap."),
-])
-
-# Scene 2: Player talks to the thief (merchant isn't here)
-alley = honcho.session("dark-alley")
-alley.add_peers([player, thief])
-alley.set_peer_configuration(thief, SessionPeerConfig(observe_others=True))
-
-alley.add_messages([
- player.message("I need that gemstone stolen from the merchant. Quietly."),
- thief.message("Consider it done. Half up front."),
-])
-
-# The merchant's view of the player: wealthy buyer seeking a gemstone
-merchant_view = merchant.chat("What do I know about this player?", target="player-one")
-
-# The thief's view: someone willing to steal from the merchant
-thief_view = thief.chat("What do I know about this player?", target="player-one")
-
-# Honcho's global view: knows both sides of the story
-full_view = player.chat("What is this player up to?")
-```
-
-```typescript TypeScript
-const honcho = new Honcho({ workspaceId: "my-rpg" });
-
-const player = await honcho.peer("player-one");
-const merchant = await honcho.peer("merchant-grim");
-const thief = await honcho.peer("thief-shadow");
-
-const tavern = await honcho.session("tavern-scene");
-await tavern.addPeers([player, merchant]);
-await tavern.setPeerConfiguration(merchant, { observeOthers: true });
-
-await tavern.addMessages([
- player.message("I'm looking for a rare gemstone. Money is no object."),
- merchant.message("I may know of one... but it won't come cheap."),
-]);
-
-const alley = await honcho.session("dark-alley");
-await alley.addPeers([player, thief]);
-await alley.setPeerConfiguration(thief, { observeOthers: true });
-
-await alley.addMessages([
- player.message("I need that gemstone stolen from the merchant. Quietly."),
- thief.message("Consider it done. Half up front."),
-]);
-
-const merchantView = await merchant.chat("What do I know about this player?", { target: "player-one" });
-const thiefView = await thief.chat("What do I know about this player?", { target: "player-one" });
-const fullView = await player.chat("What is this player up to?");
-```
-
-
-**Key decisions:**
-- Every character (player, NPC) is a peer
-- `observe_others: true` lets NPCs build their own representations of the player based only on what they've witnessed
-- Session-per-scene or session-per-encounter so context scopes to specific interactions
-- Use `target` when querying to get a specific NPC's perspective rather than Honcho's omniscient view
-- See [Representation Scopes](/v3/documentation/features/advanced/representation-scopes) for the full details
-
----
## Common Mistakes
+- **Splitting one identity across peer IDs** -- If the same user is `alice`, `alice-discord`, and `alice-cursor`, Honcho builds separate representations. Use one stable peer ID when you want unified memory.
+- **Too many tiny sessions** -- Summaries and recent messages are session-scoped, and reasoning only fires past ~1,000 tokens per session. Splitting a continuous conversation across many sessions fragments local context and can stall reasoning. Reuse a session when context should flow continuously.
+- **Separating agents that should collaborate** -- If agents need shared product, customer, or team context, put them in the same workspace. Separate workspaces are hard isolation boundaries.
- **Leaving `observe_me` on for assistants** -- Wastes reasoning compute on a peer you control. Deterministic behavior doesn't need to be modeled.
-- **Not storing messages** -- Honcho reasons about messages asynchronously. If you don't call `add_messages()`, there's nothing to reason about — no messages means no memory. See [Storing Data](/v3/documentation/features/storing-data) for details.
-- **Creating a new workspace per user** -- Use peers within a single workspace instead. Workspaces are for isolation between applications, not between users.
-- **Too many tiny sessions** -- Summaries and `session.context()` are scoped to a single session. If you split a continuous conversation across many sessions, context is fragmented and each session is too short to summarize. Reuse a session when context should flow continuously.
+- **Turning on `observe_others` everywhere** -- Directional representations are powerful, but they add complexity. Use them when peers need distinct perspectives, not just because a session has multiple peers.
+- **Forgetting `peer_target` on session context** -- `session.context()` defaults to the active session's summary and recent messages, which are session-scoped. It becomes cross-session only through adding a peer_target which includes the peer representation.
- **Blocking on processing** -- Messages are processed asynchronously in the background. Don't poll or wait for reasoning to complete before continuing your application flow.
## Next Steps
+
+ Wire these patterns into one shared workspace across four integrations
+
Retrieve formatted context from sessions for your LLM
@@ -372,7 +100,4 @@ const fullView = await player.chat("What is this player up to?");
Fine-tune what gets reasoned about and how
-
- Directional representations for multi-peer scenarios
-
diff --git a/docs/v3/guides/overview.mdx b/docs/v3/guides/overview.mdx
index 4411629d..4be16f39 100644
--- a/docs/v3/guides/overview.mdx
+++ b/docs/v3/guides/overview.mdx
@@ -7,6 +7,15 @@ icon: 'puzzle-piece'
Honcho plugs into whatever you're already building. Add memory to an AI assistant, connect an external data source, wire Honcho into your agent framework, or migrate from another provider.
+## Recipes
+Compose the core primitives across multiple integrations:
+
+
+
+ One shared workspace across a chat companion, coding agent, autonomous agent, and ingestion job
+
+
+
## AI Assistants
Add persistent memory to AI assistants and agents:
diff --git a/docs/v3/guides/recipes/unified-memory-setup.mdx b/docs/v3/guides/recipes/unified-memory-setup.mdx
new file mode 100644
index 00000000..1d547db2
--- /dev/null
+++ b/docs/v3/guides/recipes/unified-memory-setup.mdx
@@ -0,0 +1,186 @@
+---
+title: "Unified Memory Setup"
+sidebarTitle: "Unified Memory"
+icon: "diagram-project"
+description: "Wire one shared Honcho workspace across a chat companion, a coding agent, an autonomous agent, and a scheduled ingestion job"
+---
+
+This is a how-to, not an intro. It assumes you know what workspaces, peers, and
+sessions are. If you don't, start with [Core Concepts](/v3/documentation/core-concepts/).
+
+
+This guide wires four integration points into a single Honcho setup: a
+chat companion (Discord/Slack), a coding agent (Claude Code), an autonomous agent
+(Hermes), and a cron job that ingests external data. They share **one workspace** and
+**one peer** for the user, so everything Honcho learns about your user in one place is
+available everywhere else. Each section below notes the per-host setup.
+
+---
+
+## 1. Chat companion (Discord / Slack)
+
+**One session per conversation surface, one peer per participant.** The channel, thread,
+or DM is the session; everyone who speaks in it gets their own peer:
+
+- Channel → `discord-channel-{channel_id}`
+- Thread → `discord-thread-{thread_id}`
+- DM → `discord-dm-{user_id}`
+
+Derive each peer ID from the immutable platform ID (`discord-{user_id}`), not the
+display name (which can change). Keep the display name in peer metadata instead. A shared
+channel then naturally holds several human peers in one session, with the bot joining
+as its own peer (everyone observed on defaults):
+
+```python
+session = honcho.session(f"discord-channel-{channel_id}")
+session.add_peers([user, assistant]) # plus any other humans in the channel
+```
+
+Slack mirrors this with `slack_{user_id}` peers and `slack-{channel}` sessions. For a
+full bot walkthrough — message ingestion, watchlists, and storing turns — see the
+[Discord guide](/v3/guides/discord).
+
+---
+
+## 2. Coding agent (Claude Code)
+
+**Scope sessions per project directory, prefixed with the user** — `{USER_PEER_ID}-{repo_name}`
+— so multiple developers sharing the workspace don't collide on a session ID. Switch
+to a `git-branch` scope only when each branch is genuinely a separate line of work.
+
+The Claude Code plugin reads its workspace and peers from `.honcho/config.json`. Point
+each host at the same `workspace` and use the same top-level `peerName`, so every host
+attributes you to one peer:
+
+```json .honcho/config.json
+{
+ "peerName": "your-user-id",
+ "hosts": {
+ "claude_code": { "workspace": "my-product", "aiPeer": "claude" },
+ "opencode": { "workspace": "my-product", "aiPeer": "opencode" }
+ }
+}
+```
+
+
+This is a minimal, illustrative snippet — the real config file carries more fields
+(session maps, recall mode, observation strategy, etc.). See the [integration](/v3/guides/overview/)
+guides for the full schema and per-host options.
+
+
+Add the user peer and the `claude` agent peer (no special observation config needed),
+then store turns — stripping `tool_use` blocks from the assistant message so only
+substantive explanation lands in the session.
+
+Because this uses the **same user peer** as the companion, a preference the user
+states while coding ("keep it simple, pass config directly") is queryable from the
+Discord bot via `user.chat(...)`, and vice versa — both write to the same peer
+representation.
+
+
+**A shared workspace is not the default.** The Honcho plugins — Claude Code, OpenCode,
+Hermes, Cursor — each default to a *per-host* workspace (`Claude_Code`, `hermes`, …),
+keeping memory isolated per tool. The unification above only happens when you set the
+same workspace **and** the same user peer across all of them; otherwise each builds its
+own separate representation.
+
+
+---
+
+## 3. Autonomous agent (Hermes)
+
+The Hermes Honcho plugin is configured through `honcho.json`, set its `workspace`
+and `aiPeer` there. See the [Hermes guide](/v3/guides/integrations/hermes) for the full config schema.
+
+- **Sessions** follow a `session_strategy` (default `per-directory`, like the coding
+ agent above; `per-repo` or `per-session` for a fresh Honcho session each run). The
+ user peer defaults to `user-{channel}-{chat_id}` unless you pin a `peerName`.
+- **Observation** defaults to `directional` — both the user and the `hermes` agent
+ peer are observed, consistent with the defaults above, so Hermes builds a
+ representation of itself as well as the user.
+- Hermes exposes Honcho as agent **tools** (`honcho_reasoning` for synthesized
+ answers, plus lighter `honcho_search` and `honcho_context` lookups) and decides when
+ to call them mid-task. Unlike other sources, you write no retrieval code —
+ the agent pulls cross-session context on its own.
+
+---
+
+## 4. Scheduled data ingestion (cron)
+
+A scheduled job feeds external data (emails, meeting notes, CRM records) into Honcho.
+Attribute the messages to the peer the data is *about* — not to an agent — and group
+them into a session. **How you scope that session is the main decision here**, because
+it controls when Honcho reasons over the data (more on that below).
+
+```python
+from datetime import datetime, timezone
+
+session = honcho.session(f"email-import-{datetime.now(timezone.utc):%Y-%m-%d}")
+session.add_peers([user])
+
+messages = [
+ user.message(
+ f"Subject: {e['subject']}\nFrom: {e['from']}\n\n{e['body']}",
+ metadata={"source": "gmail", "thread_id": e["thread_id"]},
+ created_at=e["timestamp"], # the event's time, NOT import time
+ )
+ for e in emails
+]
+# add_messages accepts at most 100 messages per call — split into requests of 100
+for i in range(0, len(messages), 100):
+ session.add_messages(messages[i:i + 100])
+```
+
+Honcho only reasons over a peer once it accumulates ~1,000 tokens *within a single session*
+([token batching](/v3/documentation/core-concepts/reasoning#token-batching)). Scope
+the session to the volume you ingest:
+
+- **High-volume runs** (a day of emails, a CRM export) clear the threshold easily — a
+ per-run session like `email-import-{date}` is fine.
+- **Low-volume or trickle imports** (a few short records at a time) should append to
+ one **ongoing per-source session** (e.g. `email-import-gmail`), so content
+ accumulates across runs instead of fragmenting into thin sessions that each stall
+ below the threshold (nothing is lost — it just waits).
+
+The [Gmail](/v3/guides/gmail) and [Granola](/v3/guides/granola) guides are related
+import examples.
+
+
+If a cron run also posts as a deterministic agent (a bot or tool agent whose behavior
+you fully control), set `observe_me=False` on that peer so Honcho doesn't spend
+reasoning modeling it. Its messages still land in the session for context.
+
+```python
+agent = honcho.peer("cron_agent", configuration=PeerConfig(observe_me=False))
+```
+
+
+---
+
+## What you end up with
+
+From any integration, the same call — `user.chat("What is this user working on, and
+what do they care about?")` — draws on all four sources at once: Discord chats, coding
+decisions, Hermes task runs, and imported emails. They blend because:
+
+- **One workspace and one user peer**, so the representation accumulates in one place
+ instead of fragmenting into `user-discord`, `user-cursor`, etc.
+- **Sessions scoped to the live interaction** (channel, repo, task run, import batch),
+ so local context stays coherent while the user peer carries the long view.
+
+## Next Steps
+
+
+
+ The reasoning behind every decision in this guide.
+
+
+ Pull session + cross-session context into your LLM calls.
+
+
+ An interactive import using the per-import session and created_at patterns.
+
+
+ Production multi-platform companion with parent/subagent tracking.
+
+