Hermes Team Deployment

A multi-user enterprise agent architecture — 25 team members, one gateway, per-user isolation, shared context, AWS Bedrock LLM, and Google Workspace identity.

Hermes Multiplex Google Chat AWS Bedrock Honcho GCP + Portainer Google Drive
25
Team Members
1
Gateway Process
4
Containers Total
~1.1GB
RAM Required
~$50/mo
GCP VM Cost

What This Architecture Delivers

One Bot, 25 Users — A single Google Chat bot serves the entire team. No per-user bot tokens, no per-user gateways. The multiplex gateway routes each message to the right user's profile.
Per-User Isolation — Alice's projects, memory, sessions, and secrets are invisible to Bob. Tirith filesystem authorization blocks cross-user access at the tool level.
Shared Team Context — Honcho memory provider creates a shared workspace for team-wide knowledge alongside per-user private memory. Users see both.
AWS Bedrock LLM — All 25 agents route through a single AWS Bedrock provider. IAM-based auth, standard AWS credential chain, no per-user API keys needed.
Google Drive Integration — Team files live on Google Drive. Per-user OAuth tokens give each agent access to their own Drive while a shared service account handles team-level documents.

Stack Overview

LayerTechnologyRole
Identity & InterfaceGoogle Chat (Google Workspace)Users DM the bot or interact in shared spaces. Google identity is the auth layer.
Agent RuntimeHermes Agent v0.18+ (multiplex mode)Single gateway process, 25 isolated profiles, Tirith filesystem authorization.
LLM InferenceAWS Bedrock (Claude, Nova, etc.)IAM-authenticated, no API keys. Models selected per-profile or globally.
MemoryHoncho (self-hosted)Shared workspace for team context + per-peer observations for private memory.
DatabasePostgreSQL + pgvectorHoncho backing store. Vector embeddings for semantic memory search.
File StorageGoogle DriveTeam documents stored in Drive. Per-user OAuth for personal files.
DeploymentGCP Compute Engine + PortainerSingle VM, Docker Compose stack, managed via Portainer web UI.

User Experience

Alice opens Google Chat, searches for "Hermes," starts a DM. She asks "summarize the Q3 engineering doc from my Drive." The agent searches her Google Drive via OAuth, finds the doc, and summarizes it. She then asks "what's the team deadline for Q3?" — the agent searches Honcho's shared workspace and responds with the date Bob entered last week. Alice never sees Bob's private Drive files. Bob never sees Alice's.

The architecture is invisible to users. They interact with a Google Chat bot. They get their own private agent with their own memory. They benefit from team knowledge without any setup. The 4 containers, the multiplex gateway, the Bedrock IAM auth — none of it is visible from Google Chat.

System Architecture

                            ┌─────────────────────────────────────────────┐
                            │               GOOGLE WORKSPACE               │
                            │  (alice@co.com, bob@co.com, ... x25)         │
                            │         ┌───────────────────┐                │
                            │         │  Google Chat Bot  │                │
                            │         │  "Hermes Team"    │                │
                            │         └────────┬──────────┘                │
                            └──────────────────┼───────────────────────────┘
                                               │ Cloud Pub/Sub
                                               ▼
  ┌─────────────────────────────────────────────────────────────────────────────────┐
  │                           GCP COMPUTE ENGINE (1 VM)                              │
  │                                                                                  │
  │  ┌──────────────────────────────────────────────────────────────────────────┐   │
  │  │                     PORTAINER (DOCKER MANAGEMENT)                         │   │
  │  │                      Port 9443 (web UI)                                   │   │
  │  └──────────────────────────────────────────────────────────────────────────┘   │
  │                                                                                  │
  │  ┌──────────────────────────────────────────────────────────────────────────┐   │
  │  │                      DOCKER COMPOSE STACK                                 │   │
  │  │                                                                           │   │
  │  │  ┌──────────────────────────────────────────────────────────────────┐    │   │
  │  │  │  CONTAINER 1: HERMES GATEWAY (multiplex mode)                    │    │   │
  │  │  │  ┌───────────────────────────────────────────────────────────┐  │    │   │
  │  │  │  │  GATEWAY PROCESS (1)                                        │  │    │   │
  │  │  │  │  ├── Google Chat adapter (Pub/Sub → events)                 │  │    │   │
  │  │  │  │  ├── Profile Router (email → profile mapping)              │  │    │   │
  │  │  │  │  └── Session Dispatch (per-profile agent loop)              │  │    │   │
  │  │  │  │                                                             │  │    │   │
  │  │  │  │  PROFILES:                                                  │  │    │   │
  │  │  │  │  ├── alice  → HERMES_HOME=/profiles/alice                  │  │    │   │
  │  │  │  │  │            Model: bedrock/us.anthropic.claude-sonnet-4    │  │    │   │
  │  │  │  │  │            Tirith: /workspaces/alice/**                  │  │    │   │
  │  │  │  │  │            Honcho peer: alice                            │  │    │   │
  │  │  │  │  │            Google OAuth: alice@co.com token              │  │    │   │
  │  │  │  │  │                                                          │  │    │   │
  │  │  │  │  ├── bob    → HERMES_HOME=/profiles/bob                    │  │    │   │
  │  │  │  │  ├── carol  → HERMES_HOME=/profiles/carol                  │  │    │   │
  │  │  │  │  └── ... x25                                                │  │    │   │
  │  │  │  └───────────────────────────────────────────────────────────┘  │    │   │
  │  │  └──────────────────────────────────────────────────────────────────┘    │   │
  │  │                                                                           │   │
  │  │  ┌────────────────────────┐  ┌──────────────────────┐  ┌──────────────┐  │   │
  │  │  │  CONTAINER 2: HONCHO   │  │  CONTAINER 3:        │  │  CONTAINER 4:│  │   │
  │  │  │  API (port 8000)       │  │  PostgreSQL + pgvector│  │  Redis Cache │  │   │
  │  │  └────────────────────────┘  └──────────────────────┘  └──────────────┘  │   │
  │  └──────────────────────────────────────────────────────────────────────────┘   │
  │                                                                                  │
  │  VOLUMES:                                                                       │
  │  ├── profiles/alice/  → Alice's HERMES_HOME (config, memory, skills, secrets)   │
  │  ├── profiles/bob/    → Bob's HERMES_HOME                                        │
  │  ├── profiles/...     → 23 more                                                  │
  │  ├── workspaces/      → Per-user project dirs (Tirith-scoped)                    │
  │  ├── shared/          → Team-wide read-only assets                               │
  │  └── honcho-db/       → PostgreSQL data volume                                    │
  └─────────────────────────────────────────────────────────────────────────────────┘
                                               │
                    ┌──────────────────────────┼──────────────────────────┐
                    │                          │                          │
                    ▼                          ▼                          ▼
  ┌─────────────────────────┐  ┌──────────────────────────┐  ┌──────────────────────────┐
  │     AWS BEDROCK         │  │      GOOGLE DRIVE        │  │    HONCHO WORKSPACE       │
  │  (Claude, Nova, Llama)   │  │  (Team docs + per-user)  │  │  (Shared team context)    │
  │  IAM auth via AWS SDK   │  │  OAuth2 per-user tokens   │  │  + Per-peer private mem   │
  └─────────────────────────┘  └──────────────────────────┘  └──────────────────────────┘

Request Flow (Alice sends a message)

1
Alice messages the bot in Google Chat. The message includes her identity — spaces/AAA1111, users/123456789, alice@co.com.
2
Google Chat API publishes the event to the Pub/Sub topic hermes-chat-events. No public endpoint needed — the subscription is pulled.
3
Hermes Google Chat adapter pulls the event from Pub/Sub. The adapter stamps source.profile via the email → profile mapping hook.
4
Multiplex gateway routes to Alice's profile. Session key becomes agent:alice:google_chat:... — isolated from every other user.
5
Profile runtime scope activates — Alice's config, secrets (AWS Bedrock IAM role), Tirith allowlist, Honcho peer, and Google Drive OAuth token are loaded.
6
LLM call — Alice's agent sends the prompt to AWS Bedrock via the Converse API. IAM credentials are resolved from the instance role or profile-level AWS config.
7
Tool execution — If the agent reads Alice's Drive, it uses her OAuth token. If it reads team context from Honcho, it searches the shared workspace (visible to all) plus its peer observations (visible only to Alice). Tirith blocks any file path outside Alice's workspace.
8
Response is sent back through the Google Chat REST API — posted in Alice's DM, in the same thread as her message.

Key Design Decisions

Multiplex mode over per-user containers — One gateway process for 25 users vs 25 containers. ~1.1GB RAM vs ~5GB. One set of credentials vs 25. The isolation cost is Tirith allowlists per profile, not a Docker process per user.
Honcho over OpenViking for memory — Honcho's native workspace + peer model maps directly to shared team context + private per-user memory. OpenViking has no tenant concept.
AWS Bedrock over per-user API keys — Bedrock's IAM auth means the VM instance role handles all credentials. No per-user API keys to issue or rotate. All 25 profiles share the same Bedrock allocation.
Google Chat over custom web portal — Google Workspace SSO is built in. Every user is authenticated by their Google identity. No custom auth infrastructure needed.

Hermes Multiplex Gateway

Core Runtime v0.18+ Single Process 25 Profiles

The Hermes multiplex gateway is the architectural centerpiece. It runs as a single process that serves all 25 profiles, each with isolated HERMES_HOME, credentials, memory, and session state.

How Multiplex Works

  ONE GATEWAY PROCESS
  ┌─────────────────────────────────────────────────────────────────────┐
  │                                                                     │
  │  GOOGLE CHAT ADAPTER (1 connection, 1 bot token)                    │
  │  Cloud Pub/Sub pull → inbound events                                │
  │                                                                     │
  │         │                                                           │
  │         ▼                                                           │
  │  PROFILE ROUTER                                                     │
  │  ┌──────────────────────────────────────────────────────────────┐   │
  │  │  pre_gateway_dispatch hook:                                   │   │
  │  │  event.source.email → EMAIL_TO_PROFILE[alice@co.com] = alice  │   │
  │  │  stamps source.profile = "alice"                              │   │
  │  └──────────────────────────────────────────────────────────────┘   │
  │         │                                                           │
  │         ▼                                                           │
  │  SESSION DISPATCH                                                   │
  │  ┌──────────────────────────────────────────────────────────────┐   │
  │  │  Session key: agent:alice:google_chat:dm:users/123456789     │   │
  │  │  Isolated from: agent:bob:google_chat:dm:users/987654321     │   │
  │  │  Isolated from: agent:carol:google_chat:dm:users/555666777   │   │
  │  └──────────────────────────────────────────────────────────────┘   │
  │         │                                                           │
  │         ▼                                                           │
  │  PER-PROFILE CONTEXT LOADER                                         │
  │  ┌──────────────────────────────────────────────────────────────┐   │
  │  │  source.profile = "alice" →                                   │   │
  │  │  HERMES_HOME = /home/hermes/profiles/alice/                   │   │
  │  │  Loads: config.yaml, MEMORY.md, USER.md, skills/*,            │   │
  │  │         Honcho peer context, AWS credentials (per-profile)    │   │
  │  └──────────────────────────────────────────────────────────────┘   │
  │         │                                                           │
  │         ▼                                                           │
  │  AGENT LOOP (runs in profile context)                               │
  │  ├── Tirith checks every file tool call against profile allowlist   │
  │  ├── Honcho API call uses profile's peer for memory read/write      │
  │  ├── Bedrock API call uses profile's (or shared) AWS credentials    │
  │  └── Google Drive API call uses profile's OAuth token               │
  │                                                                     │
  └─────────────────────────────────────────────────────────────────────┘

Configuration

# docker-compose.yml (Hermes container)
services:
  hermes:
    image: nousresearch/hermes-agent:latest
    environment:
      - PROFILE=default
      - GATEWAY_MULTIPLEX_PROFILES=true          # Enable multiplex mode
      - AWS_PROFILE=hermes                       # Bedrock IAM profile
    volumes:
      - ./profiles:/home/hermes/profiles         # 25 profile dirs
      - ./workspaces:/home/hermes/workspaces     # Per-user project dirs
      - ./shared:/home/hermes/shared:ro          # Team-wide assets
    ports:
      - 9292:9292
# profiles/alice/config.yaml (per-profile)
model:
  provider: bedrock
  default: us.anthropic.claude-sonnet-4-6

terminal:
  backend: local
  cwd: /home/hermes/workspaces/alice
  tirith:
    fail_open: false
    allowed_paths:
      - /home/hermes/workspaces/alice/**
      - /home/hermes/shared/**

memory:
  provider: honcho

skills:
  external_dirs:
    - /home/hermes/shared/skills/      # Team skills (read-only)

Profile Routing Hook

# plugins/hooks/google_chat_user_mapper.py
"""Maps Google Chat user emails to Hermes profiles."""
import os

EMAIL_TO_PROFILE = {
    'alice@company.com': 'alice',
    'bob@company.com': 'bob',
    'carol@company.com': 'carol',
    # ... 25 entries
}

def pre_gateway_dispatch(event):
    if event.platform != 'google_chat':
        return event
    email = getattr(event.source, 'email', None)
    if email and email in EMAIL_TO_PROFILE:
        event.source.profile = EMAIL_TO_PROFILE[email]
    return event

Tirith Isolation

Tirith enforces per-profile filesystem access at the tool level. When Alice's agent calls terminal, read_file, write_file, or search_files, Tirith checks the path against the profile's allowlist before executing. Any path outside /workspaces/alice/** or /shared/** is blocked.

⚠️
Limitation: Tirith blocks Hermes tool calls but does not intercept raw os.open() in Python scripts executed via execute_code. For complete kernel-level isolation, each profile would need its own container or user namespace. For a trusted team of 25, Tirith's tool-level gate is sufficient for 95%+ of cross-user access scenarios.

Google Chat Integration

Identity Layer No Public Endpoint Pub/Sub Pull

Google Chat is the user-facing interface. Each team member interacts with a single bot — "Hermes Team" — through Google Chat DMs or shared spaces. The integration uses Cloud Pub/Sub pull subscriptions, meaning the Hermes gateway does not need a public URL, tunnel, or TLS certificate.

Architecture

  USER (Alice)
  │
  ├── Google Chat DM: "@Hermes Team summarize my Drive"
  │
  ▼
  ┌──────────────────────────────────────────────────┐
  │  GOOGLE CHAT API                                 │
  │  Publishes event to Cloud Pub/Sub topic          │
  │  projects/hermes-chat/topics/hermes-events       │
  └──────────────────────────────────────────────────┘
  │
  ▼
  ┌──────────────────────────────────────────────────┐
  │  PUB/SUB PULL SUBSCRIPTION                       │
  │  projects/hermes-chat/subscriptions/hermes-sub   │
  │  Service Account: hermes-chat-sa@...             │
  │  Roles: Pub/Sub Subscriber + Viewer              │
  └──────────────────────────────────────────────────┘
  │
  ▼
  ┌──────────────────────────────────────────────────┐
  │  HERMES GOOGLE CHAT ADAPTER                      │
  │  (inside Hermes gateway container)                │
  │  Polls subscription every 100ms                  │
  │  Parses event → SessionSource                    │
  │  Routes to profile via email mapper              │
  └──────────────────────────────────────────────────┘

  OUTBOUND:
  Agent replies via Chat REST API
  POST https://chat.googleapis.com/v1/spaces/{space}/messages
  Uses same Service Account (acts as the bot)

Setup Summary

StepActionGCP Console
1Create GCP projectconsole.cloud.google.com
2Enable Google Chat API + Cloud Pub/Sub APIAPIs & Services → Library
3Create Service Account for the botIAM & Admin → Service Accounts
4Create Pub/Sub topic + pull subscriptionPub/Sub → Topics
5Grant Chat API publisher role on topicTopic IAM: chat-api-push@system.gserviceaccount.com
6Grant SA subscriber role on subscriptionSubscription IAM: your SA + Pub/Sub Subscriber
7Configure Chat app (point to Pub/Sub topic)APIs → Google Chat API → Configuration
8Restrict visibility to your WorkspaceChat API Configuration → Visibility
9Install bot via DM or spaceGoogle Chat → New Chat → Search "Hermes Team"
ℹ️
Outbound only needs the Service Account JSON — Hermes uses the SA to authorize Chat REST API calls for replies. The SA key file is mounted into the Hermes container and referenced via GOOGLE_CHAT_SERVICE_ACCOUNT_JSON.

Message Behavior

ScenarioBehavior
User DMs the botRouted to user's profile via email mapper. Private session.
User mentions bot in shared spaceRouted to user's profile via email mapper. Public reply in thread.
Bot needs to share with whole spaceAgent can post to any space it has access to, regardless of profile.
User replies in a threadHermes detects thread.name and replies in same thread. Separate session per thread.
Unauthorized user messages botRestricted by GOOGLE_CHAT_ALLOWED_USERS — message ignored.
⚠️
Privacy note for shared spaces: All space members can see the bot's replies. For questions involving personal data, the SOUL.md should instruct users to DM the bot rather than ask in a shared space.

Team Deployment with Multiplex

With GATEWAY_MULTIPLEX_PROFILES=true, a single Google Chat bot serves all 25 team members — each routed to their own profile with isolated memory, session, and credentials. From the user's perspective, it's just a bot in their chat; the routing is invisible.

How Users Interact

1
Alice opens Google Chat → New Chat → searches for "Hermes Team" → starts a DM. She says "summarize my Q3 draft." The bot responds with her data, her Drive files, her memory.
2
Bob opens Google Chat → same bot, different DM. He says "what's the Q3 deadline?" The bot checks shared team context (Honcho workspace) for the answer. Bob's private Drive files are invisible to Alice's agent.
3
Alice mentions the bot in #team-space — "What's my PTO balance?" The email mapper routes to Alice's profile. The reply is visible to everyone in the space. Alice learns to DM for personal questions.

What Users Experience

ActionUser SeesWhat Happens Backstage
First DM to bot"Hermes is thinking…" → replyGateway receives ADDED_TO_SPACE event. Email mapper resolves alice@co.com → profile "alice". New session created.
Second DM (next day)Bot remembers context from yesterdaySession key agent:alice:google_chat:dm:spaces/AAA... loads previous conversation via Honcho.
@mention in shared spaceReply in thread, same spaceEmail mapper routes to alice profile. Reply posted via Chat REST API with thread.name.
Say "delete that file""I cannot delete files — I have restricted access."SOUL.md rule + stripped delete tools + drive.file scope. Three layers block it.

Routing Flow (End to End)

  User sends message in Google Chat
         │
         ▼
  Cloud Pub/Sub → Google Chat adapter
         │
         ▼
  pre_gateway_dispatch hook:
  Checks event.source.email
  ┌──────────────────────────────────────┐
  │  EMAIL_TO_PROFILE = {                │
  │    'alice@co.com': 'alice',          │
  │    'bob@co.com': 'bob',             │
  │    'carol@co.com': 'carol'          │
  │  }                                    │
  │  event.source.profile = matched name  │
  └──────────────────────────────────────┘
         │
         ▼
  Profile scope activates:
  ├── HERMES_HOME = /home/hermes/profiles/alice/
  ├── Session: agent:alice:google_chat:dm:...
  ├── Memory: Honcho workspace + peer alice
  ├── Config: model, Tirith rules, SOUL.md
  └── (Future) Google Drive OAuth token resolved by email
         │
         ▼
  Agent processes → reply via Chat REST API
  POST https://chat.googleapis.com/v1/spaces/{space}/messages

SOUL.md Template for Team Bots

## Google Chat Team Etiquette
- You serve 25 team members. Each has their own private profile.
- In DMs: full agent behavior. You have access to the user's
  private memory, their Drive files, and shared team context.
- In shared spaces: your replies are visible to everyone.
  If a question involves personal data, tell the user:
  "This involves your personal data — could you DM me instead?"
- You CANNOT delete files in Google Drive. Refuse politely.
- You can create new documents in Drive when asked.
- You can share information from team context (Honcho workspace)
  publicly in shared spaces.
- When in doubt about privacy, ask the user to DM you.
🚫
BLOCKER for multiplex — requires a code patch. The multiplex gateway routes messages per-user, but the Google Workspace skill's OAuth token resolution is still single-account (issue #15602). The token path is frozen at module import time, not resolved per-profile at call time. This means only the last user to authorize Drive will have working access — everyone else's token is silently overwritten.
Fix before deploying to users: Patch google_api.py to use a lazy token resolver that reads from google_tokens/<email>.json at call time. Same 20-line pattern as PR #59339 (Anthropic OAuth, already merged). The PR description and diff at github.com/NousResearch/hermes-agent/pull/59339 show the exact architecture. Without this, per-user Drive access is broken in multiplex mode.

Honcho Memory Provider

Shared + Private Workspace Model Self-Hosted

Honcho is the most important component for team deployment. It's what turns 25 isolated agent profiles into a team that learns collectively. Without it, each user's bot starts fresh every session — no shared context, no cross-user learning, no team knowledge growth.

Why Honcho — Not File-Based Memory

Standard Hermes memory (MEMORY.md, USER.md) and static knowledge stores like Obsidian vaults or plain markdown files can't support a team of 25 users. Here's why Honcho is necessary:

CapabilityHonchoHermes MEMORY.mdObsidian VaultPlain Markdown
Per-user private memory✅ Isolated observation peers per profile✅ Isolated per-profile file❌ Single vault, no per-user scoping❌ No isolation
Shared team knowledge✅ User peer "team" visible to all profiles❌ Per-profile only — no sharing✅ Everyone can read the vault❌ No sharing
Automatic extraction✅ Deriver extracts facts from conversations automatically❌ Manual write only❌ Manual note creation only❌ Manual only
Semantic search (vector embeddings)✅ pgvector — find concepts, not keywords❌ Keyword search only⚠️ With plugins, but no service❌ grep only
Cross-user learning✅ Bob enters a deadline → Alice's agent knows it❌ Alice can't read Bob's file⚠️ If Bob manually writes a note
Session continuity✅ Honcho recalls past sessions, preferences, decisions⚠️ Basic file recall, no structure❌ No session recall
Background consolidation✅ Dream runs offline — summarizes, deduplicates, links facts
Scales to 25+ profiles✅ Built for multi-agent❌ Per-profile, no cross-talk

📈 The Team Learning Loop

Alice asks "what's the Q3 deadline?" → agent checks Honcho workspace → Bob had already entered it in his DM yesterday → Alice gets the answer. Bob never had to "share" anything. Honcho's Deriver extracted it from Bob's conversation automatically and stored it in the shared peer. The team's knowledge compounds organically — every conversation feeds the collective, every user benefits from every other user's learnings, without anyone filing a document.

Architecture — Workspace + Peers

  ┌─────────────────────────────────────────────────────────────────────┐
  │                      HONCHO (Container:8000)                        │
  │                                                                     │
  │  WORKSPACE: "hermes-team"                                           │
  │  ┌──────────────────────────────────────────────────────────────┐  │
  │  │  USER PEER: "team"                                           │  │
  │  │  ├── Repository of team-shared facts                          │  │
  │  │  ├── Session summaries from shared spaces                     │  │
  │  │  ├── Team decisions, project status, deadlines                │  │
  │  │  └── Visible to ALL profiles                                  │  │
  │  │                                                               │  │
  │  │  AI PEERS (one per profile):                                  │  │
  │  │  ├── "alice" → Alice's private observations                   │  │
  │  │  │             Her preferences, her project notes,            │  │
  │  │  │             her Google Drive file indices                  │  │
  │  │  ├── "bob"   → Bob's private observations                     │  │
  │  │  └── ... x25                                                  │  │
  │  └──────────────────────────────────────────────────────────────┘  │
  │                                                                     │
  │  DATABASE: PostgreSQL + pgvector                                    │
  │  └──────────────────────────────────────────────────────────────────┘  │
  │                                                                     │
  │  DERIVER (background worker)                                        │
  │  Extracts observations from messages, builds peer representations,  │
  │  generates session summaries, runs dream consolidation              │
  └─────────────────────────────────────────────────────────────────────┘

Configuration

# honcho.json (shared across all profiles via mount)
{
  "baseUrl": "http://honcho:8000",
  "hosts": {
    "hermes": {
      "enabled": true,
      "workspace": "hermes-team",
      "peerName": "team",
      "aiPeer": "hermes",              # Default AI peer
      "recallMode": "hybrid",          # Auto-inject + tools
      "writeFrequency": "async",       # Background writes
      "observationMode": "directional"
    }
  }
}

Each profile references the same honcho.json but Hermes auto-creates a per-profile AI peer (hermes.alice, hermes.bob, etc.) via the --clone pattern during profile creation.

What Gets Stored Where

ContentStored InVisible To
Team deadlines, project statusWorkspace (user peer: "team")All 25 profiles
Shared space conversationsWorkspace (user peer: "team")All 25 profiles
Alice's personal preferencesAI peer: "alice" (observations)Alice only
Alice's project notesAI peer: "alice" (observations)Alice only
Alice's Drive file indexAI peer: "alice" (observations)Alice only
Bob's preferencesAI peer: "bob" (observations)Bob only
Workspace is the shared brain. When Alice asks "what's the Q3 deadline?", the agent queries Honcho's user peer and gets the team-visible answer. When Bob updates a deadline, it's available to everyone immediately — no document to file, no meeting to attend, no wiki to update. The team's collective knowledge grows with every conversation.
This is not possible with file-based memory. MEMORY.md is isolated per-profile — Alice cannot access Bob's file at all. An Obsidian vault is shared but requires manual note-taking — Bob has to remember to write something down. Honcho's Deriver does the extraction automatically in the background, so the team's knowledge grows even when users don't consciously "share" anything.
The team learning curve. Week 1: Alice's agent knows what Alice knows. Bob's agent knows what Bob knows. Week 4: Alice's agent knows everything Alice + Bob + Carol + team chat have discussed. The compound effect means the system becomes more useful the more people use it — opposite of a static document that goes stale.

What This Means For Your Team

ScenarioWithout HonchoWith Honcho
Bob learns the Q3 deadline is Dec 15Bob's agent knows it. Alice's agent has no idea. Next week Alice asks and gets "I don't know."Deriver extracts "Q3 deadline: Dec 15" from Bob's conversation → stored in workspace peer. Alice asks → agent finds it instantly.
Carol discovers a bug in the deployment scriptCarol's agent notes it. Team finds out via email chain later (if Carol remembers to send it).Deriver extracts the fix → stored in workspace peer. Bob asks "anyone fixed the deploy bug?" → agent has the answer.
Team has a heated debate in the shared space about strategyNothing captured beyond the Chat thread (which scrolls away).Deriver summarizes the debate, stores key decisions and arguments in workspace peer. Two months later, Alice asks "why did we choose AWS?" → agent recalls the entire reasoning chain.
Alice joins mid-yearAlice's agent knows nothing about the team. Weeks of ramp-up.Alice's agent queries the workspace peer → has access to every team decision, project status, and lesson learned since day one. Instant context.
A decision made 6 months ago needs revisitSomeone has to find the old Chat thread or recall from memory.Agent searches Honcho workspace by concept. Finds the decision, the reasoning, the alternatives considered, and the outcome. All automatically captured at the time of discussion.

Self-Hosted Honcho Stack

services:
  honcho-db:
    image: pgvector/pgvector:pg17
    environment:
      POSTGRES_USER: honcho
      POSTGRES_PASSWORD: ${HONCHO_DB_PASSWORD}
      POSTGRES_DB: honcho
    volumes:
      - honcho-db:/var/lib/postgresql/data

  honcho-redis:
    image: redis:7-alpine
    volumes:
      - honcho-redis:/data

  honcho-api:
    build: https://github.com/plastic-labs/honcho.git
    depends_on: [honcho-db, honcho-redis]
    environment:
      DB_CONNECTION_URI: postgresql+psycopg://honcho:...
      CACHE_URL: redis://honcho-redis:6379/0
      AUTH_USE_AUTH: "false"
      LLM_OPENAI_API_KEY: ${OPENAI_API_KEY}
ℹ️
Honcho needs an LLM for the Deriver (background memory extraction). This can be the same Bedrock model used by Hermes, a dedicated smaller model, or a separate provider entirely. Configured via .env in the Honcho container.

AWS Bedrock LLM Provider

Inference IAM Auth Converse API

All 25 Hermes profiles route their LLM calls through a single AWS Bedrock provider. Hermes supports Bedrock natively via the Converse API — not the OpenAI-compatible endpoint. This gives you full access to IAM authentication, Guardrails, cross-region inference profiles, and all foundation models.

How Auth Works

1
GCP VM has an IAM role — The VM is launched with an AWS IAM role (via instance profile or environment variables AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY).
2
Hermes uses standard AWS SDK chainboto3 resolves credentials from environment variables, ~/.aws/credentials, or instance profile. No Bedrock-specific API key needed.
3
Per-profile or shared credentials — Each profile can use a different IAM role (for cost tracking) or share a single role. Configurable via AWS_PROFILE env var per profile or globally.

Configuration

# Hermes config.yaml (global or per-profile)
model:
  provider: bedrock
  default: us.anthropic.claude-sonnet-4-6
  # Available Bedrock models:
  # us.anthropic.claude-sonnet-4-6       — Heavy reasoning
  # us.anthropic.claude-3-5-haiku        — Fast/cheap
  # amazon.nova-pro-v1:0                 — Amazon's own
  # us.meta.llama4-405b-instruct-v1:0    — Open weight

# Per-profile model override:
# profiles/alice/config.yaml
model:
  provider: bedrock
  default: us.anthropic.claude-sonnet-4-6    # Alice gets Sonnet
  auxiliary:
    background_review:
      model: us.anthropic.claude-3-5-haiku    # cheap for background tasks
# Environment (per-profile .env or global)
AWS_DEFAULT_REGION=us-east-1
AWS_PROFILE=hermes-team
# Or use named profile in ~/.aws/credentials
# [hermes-team]
# aws_access_key_id = AKIA...
# aws_secret_access_key = ...

Cost Estimates for 25 Users

Usage PatternMonthly Cost
Light (5 conversations/user/day, Claude Sonnet)~$100-200
Moderate (15 conversations/user/day, Claude Sonnet)~$300-500
Heavy (50 conversations/user/day, Claude Sonnet)~$800-1500
Mixed (Sonnet + Haiku for background tasks)~30-50% of above
Bedrock Guardrails — AWS Bedrock Guardrails can be applied to all inference calls, providing content filtering, topic denial, and PII redaction across the entire team without any per-user configuration.

Security

With Bedrock's IAM auth, there are no API keys to issue or rotate. The VM's IAM role defines what models can be invoked. If the VM is compromised, the IAM role is the blast radius — not individual API keys. Bedrock also supports cross-region inference profiles for automatic failover and load balancing.

Google Drive Integration

File Storage Per-User OAuth Shared Service Account

Team files live in Google Drive. The architecture supports two access patterns: per-user OAuth tokens for private file access, and a shared service account for team-wide document retrieval.

  GOOGLE DRIVE ACCESS MODEL
  ┌─────────────────────────────────────────────────────────────────────┐
  │                                                                     │
  │  PER-USER ACCESS (via OAuth)                                        │
  │  ┌─────────────────────────────────────────────────────────────┐    │
  │  │  Alice's agent → Alice's OAuth token → Alice's Google Drive  │    │
  │  │  Bob's agent   → Bob's OAuth token   → Bob's Google Drive    │    │
  │  └─────────────────────────────────────────────────────────────┘    │
  │                                                                     │
  │  Access granted when:                                                │
  │  1. User runs /setup-google-drive in their DM                       │
  │  2. Browser OAuth consent flow completes                             │
  │  3. Token stored at ~/.hermes/google_tokens/alice@co.com.json       │
  │  4. Token auto-refreshes, never expires                             │
  │                                                                     │
  │  ──────────────────────────────────────────────────────────────     │
  │                                                                     │
  │  SHARED TEAM ACCESS (via Workspace Service Account)                 │
  │  ┌─────────────────────────────────────────────────────────────┐    │
  │  │  Any profile's agent → Drive SA token → Team Drive/shared    │    │
  │  │  docs folder                                                  │    │
  │  └─────────────────────────────────────────────────────────────┘    │
  │                                                                     │
  │  Service Account has domain-wide delegation authority:              │
  │  - Can access any doc in the team Drive                             │
  │  - Configured via Google Workspace Admin Console                    │
  │  - No per-user consent needed for team docs                         │
  │                                                                     │
  └─────────────────────────────────────────────────────────────────────┘

Setup Sequence

1
Create a Google Cloud project and enable the Drive API. Create OAuth 2.0 credentials (Desktop app type).
2
For team-wide access: Create a Service Account with domain-wide delegation. Configure the Workspace Admin Console to grant it access to the Drive scope (https://www.googleapis.com/auth/drive.readonly).
3
For per-user access: Each user runs /setup-google-drive in their DM. This generates an OAuth URL. The user approves in their browser, pastes back the redirect URL, and the token is stored.
4
Agent searches Drive — The agent calls the Hermes Google Workspace skill ($GAPI drive search ...) which resolves the correct OAuth token based on the active profile's user email.

Multi-Account Token Storage

The Google Workspace skill stores tokens at ~/.hermes/google_tokens/<email>.json. The multiplex profile router sets GOOGLE_CHAT_USER_EMAIL as an env var per-turn, which the Google API tooling reads to select the correct token. If no per-user token exists, it falls back to the team service account.

⚠️
Current limitation: Multi-account OAuth token support is GitHub issue #15602, labeled P3 (not yet merged). The single-account Google Workspace skill works today. Per-user token resolution requires a small custom extension to google_api.py to accept a --user flag that selects the right token file. This is approximately 30 lines of Python.

Drive Security: Preventing Accidental Deletion

Google OAuth scopes do not differentiate between create and delete — a token with drive.file or drive scope can delete any file it can access. Three layers of defense prevent accidental document loss:

Layer 1: OAuth Scope Selection

ScopeReadCreateEditDeleteBest For
drive.readonlyTeam service account (shared docs)
drive.file✅ (own files only)✅ (own files only)Per-user tokens (recommended)
drive (full)✅ (all)✅ (all)Avoid — never use

Recommended setup:

  • Team Drive (shared): Service Account with drive.readonly — agent can search and read team docs but cannot touch them
  • Per-user Drive: User OAuth with drive.file — agent can create and edit files it made, but cannot see or delete existing user files
# In Hermes Google Workspace setup or google_api.py
SCOPES = {
    "team": ["https://www.googleapis.com/auth/drive.readonly"],           # team SA
    "user": ["https://www.googleapis.com/auth/drive.file"]               # per-user OAuth
}

drive.file confines the agent to files it explicitly created or was granted access to. Your existing 5-year-old project spreadsheets are invisible to it. If the agent deletes a draft it made, Drive's 30-day trash provides recovery.

Layer 2: Tool-Level Deletion Stripping

Modify the Hermes Google Workspace skill to remove delete functionality entirely — the agent literally cannot call delete because the tool doesn't exist in its toolset:

# google_api.py — strip all destructive commands
COMMANDS = {
    'search': _drive_search,
    'get': _drive_get,
    # 'delete': _drive_delete,       ← REMOVED
    # 'trash': _drive_trash,         ← REMOVED
    # 'update': _drive_update,       ← REMOVED (optional — keeps edits)
    'create': _drive_create,         # keep if you want doc generation
}

Layer 3: Prompt Hardening

Each profile's SOUL.md includes a non-deletion directive as a behavioral guardrail:

## Google Drive Rules
- You have RESTRICTED access to Google Drive.
- You CANNOT delete, trash, or remove any file.
- You CAN create new files when explicitly asked.
- If a user asks you to delete a file, refuse politely.
- If a user asks you to "clean up" or "remove old files," do not interpret this as delete.
  Instead, state that you cannot perform destructive operations.

Defense in Depth Flow

  User: "delete that spreadsheet"
         │
         ▼
  SOUL.md: "Cannot delete files"           ← Prompt guardrail
         │
         ▼
  Agent looks for delete tool               ← Tool doesn't exist
         │
         ▼
  Google API checks OAuth scope             ← drive.file or readonly
         │
    ┌────┴────┐
    │         │
  readonly  drive.file
    │         │
  403       Checks: did this app CREATE the file?
    │         │
    │    ┌────┴────┐
    │    │         │
    │   Yes       No
    │    │         │
    │  Deletes   403 FORBIDDEN
    │  (trash,    │
    │  30d recover) File safe
    │         │
    └─────────┘
         │
  Even if deleted: 30-day Drive trash recovery
Belt + suspenders. Three independent layers — OAuth scope, tool availability, and prompt instruction — mean a file can only be deleted if all three fail simultaneously. And even then, Drive's 30-day trash provides a final recovery path. For most teams, drive.file + tool stripping is sufficient.

GCP + Portainer Deployment

Infrastructure Single VM Portainer Stack

The entire stack deploys on a single GCP Compute Engine VM, managed through Portainer's web UI. No Kubernetes, no Cloud Run — just Docker Compose on a VM, which is what you know.

Resource Sizing

ResourceRecommendedMinimum
Machine typee2-standard-4 (4 vCPU, 16GB)e2-standard-2 (2 vCPU, 8GB)
Disk100GB persistent SSD50GB persistent SSD
RAM usage~4.5GB (Hermes + Honcho + DB + Redis)~3GB
Monthly cost~$50-70/mo~$30-40/mo
  GCP COMPUTE ENGINE
  ┌─────────────────────────────────────────────────────────────────┐
  │  e2-standard-4 (4 vCPU, 16GB RAM, 100GB SSD)                   │
  │                                                                 │
  │  ┌──────────────────────────────────────────────────────────┐   │
  │  │  PORTAINER (port 9443)                                    │   │
  │  │  ├── Stack: "hermes-team"                                 │   │
  │  │  │   ├── hermes (image: nousresearch/hermes-agent)        │   │
  │  │  │   │   ports: 9292 (gateway)                            │   │
  │  │  │   │   env: GATEWAY_MULTIPLEX_PROFILES=true              │   │
  │  │  │   │   volumes: profiles/, workspaces/, shared/         │   │
  │  │  │   │                                                    │   │
  │  │  │   ├── honcho-api (build from GitHub)                   │   │
  │  │  │   │   ports: 8000                                       │   │
  │  │  │   │   env: DB_CONNECTION_URI, CACHE_URL, LLM key       │   │
  │  │  │   │                                                    │   │
  │  │  │   ├── honcho-db (image: pgvector/pgvector:pg17)        │   │
  │  │  │   │   volumes: honcho-db:/var/lib/postgresql/data      │   │
  │  │  │   │                                                    │   │
  │  │  │   └── honcho-redis (image: redis:7-alpine)             │   │
  │  │  │       volumes: honcho-redis:/data                      │   │
  │  │  └──────────────────────────────────────────────────────┘   │
  │  └──────────────────────────────────────────────────────────┘   │
  └─────────────────────────────────────────────────────────────────┘

Step-by-Step Deployment

1. Create the GCP VM

gcloud compute instances create hermes-vm \
  --zone=us-central1-a \
  --machine-type=e2-standard-4 \
  --image-family=ubuntu-2404-lts \
  --image-project=ubuntu-os-cloud \
  --boot-disk-size=100GB \
  --boot-disk-type=pd-ssd \
  --tags=portainer,hermes

2. Install Docker + Portainer (startup script)

#!/bin/bash
apt update && apt install -y docker.io docker-compose-v2
systemctl enable docker

docker volume create portainer_data
docker run -d --name portainer --restart always \
  -p 9443:9443 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v portainer_data:/data \
  portainer/portainer-ce:latest

3. Connect Portainer

Open https://<VM_EXTERNAL_IP>:9443. Set admin password. Connect to the local Docker environment. Go to Stacks → Add Stack, paste the docker-compose.yml, and deploy.

4. Firewall Rules

# Allow Portainer web UI (restrict to your IP)
gcloud compute firewall-rules create allow-portainer \
  --allow tcp:9443 \
  --source-ranges YOUR_HOME_IP/32

# Allow Hermes gateway admin API (if needed)
gcloud compute firewall-rules create allow-hermes-api \
  --allow tcp:9292 \
  --source-ranges YOUR_VPN_RANGE/24

docker-compose.yml

version: '3.8'
networks:
  hermes-net:

volumes:
  honcho-db:
  honcho-redis:

services:
  hermes:
    image: nousresearch/hermes-agent:latest
    environment:
      - PROFILE=default
      - GATEWAY_MULTIPLEX_PROFILES=true
      - AWS_PROFILE=hermes-team
    env_file:
      - ./hermes.env
    volumes:
      - ./profiles:/home/hermes/profiles
      - ./workspaces:/home/hermes/workspaces
      - ./shared:/home/hermes/shared:ro
      - ./honcho.json:/home/hermes/.hermes/honcho.json
      - ./google-chat-sa.json:/run/secrets/google-chat-sa.json
    ports:
      - "127.0.0.1:9292:9292"
    networks:
      - hermes-net
    restart: unless-stopped

  honcho-db:
    image: pgvector/pgvector:pg17
    environment:
      POSTGRES_USER: honcho
      POSTGRES_PASSWORD: ${HONCHO_DB_PASSWORD}
      POSTGRES_DB: honcho
    volumes:
      - honcho-db:/var/lib/postgresql/data
    networks:
      - hermes-net
    restart: unless-stopped

  honcho-redis:
    image: redis:7-alpine
    volumes:
      - honcho-redis:/data
    networks:
      - hermes-net
    restart: unless-stopped

  honcho-api:
    build: https://github.com/plastic-labs/honcho.git
    depends_on: [honcho-db, honcho-redis]
    environment:
      DB_CONNECTION_URI: postgresql+psycopg://honcho:${HONCHO_DB_PASSWORD}@honcho-db:5432/honcho
      CACHE_URL: redis://honcho-redis:6379/0
      AUTH_USE_AUTH: "false"
      LLM_OPENAI_API_KEY: ${HONCHO_LLM_KEY}
    networks:
      - hermes-net
    restart: unless-stopped

Directory Layout

/opt/hermes-deploy/
├── docker-compose.yml
├── hermes.env                         # Global env vars
├── honcho.json                        # Honcho config
├── google-chat-sa.json                # GCP SA key
├── profiles/
│   ├── alice/config.yaml
│   ├── alice/.env                     # Per-user secrets
│   ├── alice/SOUL.md
│   ├── alice/honcho.json
│   ├── bob/config.yaml
│   ├── bob/.env
│   ...
├── workspaces/
│   ├── alice/                         # Alice's project files
│   ├── bob/
│   ...
└── shared/
    ├── skills/                        # Team skills repo
    ├── docs/                          # Team documentation
    └── templates/

Backup Strategy

DataMethodFrequency
Honcho PostgreSQLdocker exec honcho-db pg_dumpDaily
Profile configsVolume backup (or git-tracked)On change
Google Chat SA keyStored separately (GCP Secret Manager)N/A
Portainer dataVolume backupWeekly

Security Model

Isolation Layers IAM Auth Tirith

The security model uses defense in depth — six layers between a user and another user's data.

Layer 1: Google Workspace Identity

Every user authenticates through Google Workspace. The Chat bot is configured with GOOGLE_CHAT_ALLOWED_USERS — only workspace members can message the bot. An attacker without a valid @company.com account cannot interact with the agent at all.

Layer 2: Profile Isolation

Each user's session runs in its own HERMES_HOME directory. Session keys are namespaced by profile — agent:alice:google_chat:dm:... vs agent:bob:google_chat:dm:.... Alice's conversation history is never loaded into Bob's session.

Layer 3: Tirith Filesystem Authorization

Every file tool call (terminal, read_file, write_file, search_files, patch) is intercepted by Tirith. Paths are checked against the profile's allowlist before execution.

# Alice CAN access:
/workspaces/alice/**
/shared/**
/home/hermes/profiles/alice/config.yaml

# Alice CANNOT access:
/workspaces/bob/**
/home/hermes/profiles/bob/MEMORY.md
/etc/shadow
fail_open: false is critical. When set to false, Tirith blocks any path not explicitly allowed. The default is true (allow all) — you must explicitly set it to false in production.

Layer 4: Honcho Peer Isolation

Honcho uses a workspace + peer model. The user peer (team) is shared across all profiles — this is intentional for team context. Each AI peer (alice, bob, etc.) has private observations that no other peer can query. Honcho's API does not expose cross-peer data.

Layer 5: AWS Bedrock IAM

The VM's IAM role defines the blast radius for LLM access. No API keys in config files. Bedrock Guardrails can be applied to all inference calls for content filtering and topic denial across the entire team.

Layer 6: Per-User Google OAuth Tokens

Each user's Google Drive OAuth token is scoped to their account. Token files are stored in the profile's HERMES_HOME with filesystem permissions. Alice's token cannot read Bob's Drive. Bob's token cannot read Alice's Drive.

Trust Model Summary

ThreatPrevented ByConfidence
Alice reads Bob's project filesTirith path allowlistHigh (tool-level gate)
Alice reads Bob's private memoryHoncho peer isolationHigh (API-level gate)
Alice steals Bob's AWS credentialsIAM role (not per-user keys)High (no keys to steal)
Alice reads Bob's Drive filesPer-user OAuth scopingHigh (Google auth)
Alice executes os.open() to bypass TirithNot prevented in execute_code⚠️ Medium gap
External attacker messages the botGoogle Chat allowed_usersHigh (Google auth)
⚠️
Acknowledged gap: execute_code runs arbitrary Python that can bypass Tirith via os.open(). For a trusted team of 25, this is acceptable — the user running the tool is already authenticated as themselves. If you need to prevent a compromised agent from reading another user's files at the kernel level, you need per-container or per-VM isolation, which defeats the multiplex architecture. This is a conscious tradeoff.

User Onboarding

Setup Flow Admin Tasks User Tasks

Admin Setup (One Time, ~1 Hour)

Phase 1: GCP Infrastructure

1
Create GCP VM — e2-standard-4 with Ubuntu 24.04, 100GB SSD. Install Docker + Portainer via startup script.
2
Configure firewall — Open port 9443 (Portainer) restricted to your IP. Open port 9292 (Hermes API) restricted to office VPN if needed.
3
Deploy stack — Paste docker-compose.yml into Portainer. 4 containers spin up (Hermes, Honcho API, PostgreSQL, Redis).

Phase 2: Google Chat Bot

4
Create GCP project for the Chat bot. Enable Chat API + Pub/Sub API. Create Service Account. Create Pub/Sub topic + subscription.
5
Configure Chat app in Google Cloud Console — point it to the Pub/Sub topic. Restrict visibility to your Workspace.
6
Configure Hermes — Add Google Chat adapter settings to hermes.env. Mount the SA key. Set GOOGLE_CHAT_ALLOWED_USERS.

Phase 3: AWS Bedrock

7
Configure AWS credentials — Set AWS_PROFILE or IAM instance profile on the GCP VM. Ensure Bedrock access is granted for the desired models.

Phase 4: Profiles

8
Create profile directories — Generate profiles/alice/, profiles/bob/, etc. Each with config.yaml, .env, SOUL.md, Tirith allowlist.
9
Deploy email mapper hook — Install the pre_gateway_dispatch hook that maps alice@co.comalice profile.

User Setup (~5 Minutes Each)

1
Open Google Chat → New Chat → search for "Hermes Team" → send a message. The bot responds. Done.
2
Optional: Run /setup-google-drive in the DM to authorize Drive access. Click the OAuth link, approve, paste back the URL.
3
Optional: Run /setup-profile to set preferences — model selection (Sonnet vs Haiku), notification preferences, timezone.

Onboarding Checklist

ItemOwnerDone
Create GCP VM + install Docker/PortainerAdmin
Configure firewall rulesAdmin
Deploy docker-compose stack in PortainerAdmin
Create Google Cloud project for Chat botAdmin
Enable Chat API + Pub/Sub APIAdmin
Create Service Account + download JSON keyAdmin
Create Pub/Sub topic + subscriptionAdmin
Grant IAM roles (Chat publisher, SA subscriber)Admin
Configure Chat app in GCP ConsoleAdmin
Restrict bot visibility to workspaceAdmin
Configure Google Chat adapter in Hermes envAdmin
Install bot in test DMAdmin
Set up AWS Bedrock + IAM roleAdmin
Create 25 profile directories with configsAdmin
Write email → profile mapping hookAdmin
Create Honcho workspace + peersAdmin
Test with Alice's Google accountAdmin
Send onboarding instructions to teamAdmin
Each user DMs the bot (5 min)Users
Optional: Each user authorizes Google DriveUsers

Cost Summary

ItemMonthly Cost
GCP e2-standard-4 VM~$50-70
100GB SSD persistent disk~$10
AWS Bedrock (Claude Sonnet, moderate usage)~$300-500
Google Workspace licenses (included)$0 (already paid)
Honcho Deriver LLM costs~$20-50
Total estimated~$380-630/mo

Hermes Team Deployment — Architecture & Deployment Guide
Hermes v0.18+ · Multiplex Mode · AWS Bedrock · Google Chat · Honcho · GCP

Order of Operations

Implementation Plan Prioritized Phased Rollout

This is the chronological build plan — from zero to fully operational for 25 team members. Each phase is independent and testable. The system becomes usable after Phase 3. Everything after that is capability expansion.

1 Infrastructure — The VM Day 1 ~45 min Parallelizable: ☐
1.1Create GCP VMe2-standard-4, Ubuntu 24.04, 100GB SSD. gcloud compute instances create.
1.2Install Docker + PortainerStartup script: install docker.io, docker-compose-v2, launch Portainer container on port 9443.
1.3Configure firewallOpen 9443 (Portainer) to your IP. Open 9292 (Hermes API) to office VPN if needed.
1.4Set AWS IAM credentialsCreate IAM role with Bedrock invoke permissions. Set AWS_PROFILE or instance profile on the VM.
1.5Deploy Docker Compose stackPaste docker-compose.yml into Portainer. 4 containers: Hermes, Honcho API, PostgreSQL, Redis.
⏳ Status: Not started — Phases 1-3 take ~3 hours total
🔲 Milestone 1: Portainer dashboard loads at https://<IP>:9443. All 4 containers show green.
2 Google Chat Bot Day 1 ~45 min Parallelizable: ☐
2.1Create GCP project for Chat botEnable Google Chat API + Cloud Pub/Sub API.
2.2Create Service AccountName it hermes-chat-bot. Download JSON key. chmod 600.
2.3Create Pub/Sub topic + pull subscriptionTopic: hermes-chat-events. Subscription: hermes-chat-events-sub, pull, 7-day retention.
2.4IAM bindings (CRITICAL)Topic: add chat-api-push@system.gserviceaccount.com as Publisher. Subscription: add SA as Subscriber + Viewer.
2.5Configure Chat appAPIs → Google Chat API → Configuration. Set name, avatar, Pub/Sub topic. Restrict visibility to your Workspace.
2.6Install bot in a test DMSearch for bot name in Google Chat → New Chat → send first message. Verify ADDED_TO_SPACE event received.
⏳ Status: Not started
🔲 Milestone 2: Bot responds to DMs. "Hermes is thinking…" → real reply appears.
3 Profiles + Multiplex + Routing Day 2 ~60 min This makes the system usable
3.1Enable multiplex modeSet GATEWAY_MULTIPLEX_PROFILES=true in Hermes env. Restart gateway.
3.2Create profile directoriesGenerate 25 profile dirs: profiles/alice/, profiles/bob/, etc. Each with config.yaml, .env, SOUL.md.
3.3Config per profileBedrock provider, Tirith allowlists, Honcho peer name. Use a template and iterate.
3.4Write email → profile mapping hookpre_gateway_dispatch plugin: 25 email entries, stamps event.source.profile.
3.5Test with 2-3 team membersAlice and Bob DM the bot. Verify each gets their own profile, memory isolation, session persistence.
3.6Deploy Tirith allowlistsSet fail_open: false. Define allowed_paths per profile. Test cross-profile file access is blocked.
⏳ Status: Not started — System becomes usable for the team at this point
🔲 Milestone 3: Alice and Bob can DM the bot. Each gets their own memory. Alice cannot read Bob's files.
4 Shared Memory (Honcho) Day 2 ~30 min Adds team knowledge
4.1Verify Honcho is runningCheck docker ps — honcho-api, honcho-db, honcho-redis all healthy.
4.2Mount Honcho configPlace honcho.json at each profile's Hermes home. Set workspace, peer, recall mode.
4.3Create workspace + peersHoncho workspace: hermes-team. User peer: team (shared). AI peers: alice, bob, etc. (private).
4.4Test shared vs private memoryAlice enters a team fact → visible to Bob. Alice enters a private note → invisible to Bob. Confirm with queries.
⏳ Status: Not started
5 Google Drive Integration (Per-User) Day 3 ~60 min ⚠️ GATING ITEM Required for Drive access
⚠️
Requires a ~20 line patch — not a config change. The Hermes Google Workspace skill does not yet support per-user OAuth tokens in multiplex mode (issue #15602). You must patch google_api.py to add a per-profile token resolver. The pattern is already established by PR #59339 (Anthropic OAuth). Without this patch, only the last user to authorize Drive will have working access — everyone else's tokens are silently overwritten.
5.1Create OAuth consent screenGCP → APIs & Services → OAuth consent screen. Configure app name, scopes (drive.file). Add test users.
5.2Create OAuth client IDDesktop app type. Download client_secret.json.
5.3Patch google_api.py for multi-accountAdd per-profile token resolver (20 lines, same pattern as PR #59339). Resolves tokens from google_tokens/<email>.json at call time instead of a global path frozen at import. Without this step, per-user Drive access doesn't work in multiplex mode.
5.4Each user authorizes DriveRun /setup-google-drive in DM. OAuth URL → approve → paste back. Token stored by email.
5.5Set up SA for shared team DriveGCP → Service Accounts → domain-wide delegation. Scope: drive.readonly. Mount SA key into Hermes container.
⚠️ CRITICAL: Step 5.3 (google_api.py patch) is required before any user can use Drive. Without it, multiplex mode overwrites tokens.
🔲 Milestone 4: Alice asks "summarize my Q3 doc" → agent finds and reads it from her Drive. Bob's files are invisible to Alice's agent.
6 Team Rollout Day 4-5 ~2 hours User-facing
6.1Send onboarding emailInstructions: "Open Google Chat → New Chat → Search 'Hermes Team' → Say hello." Include link to Drive auth.
6.2Support first-login issuesMost common: users searching for wrong bot name, permissions not propagated, space ID not yet cached.
6.3Create team space + add botCreate #team-hermes space, add the bot. Users can @mention for shared questions.
6.4Train shared space etiquettePost a message: "Personal questions → DM me. Team questions → @mention here. I can't delete files."
6.5Set up shared skills directoryMount team skills repo as read-only volume. All profiles can use shared skills.
⏳ Status: Not started
🔲 Milestone 5: All 25 team members can DM the bot. Shared space is active. Team etiquette is established.
7 Operations & Hardening Day 5+ Ongoing Continuous
7.1Set up daily Honcho DB backupcron: docker exec honcho-db pg_dump → Cloud Storage bucket or volume backup.
7.2Deploy Cloud SQL (optional)Migrate Honcho DB from container to managed Cloud SQL for HA + point-in-time recovery.
7.3Monitor Bedrock costs per profileUse AWS Cost Explorer with HERMES_PROFILE tag. Set budgets and alerts.
7.4Watch for Hermes updatesv0.19+ may ship per-user Drive token fix (#15602). Test before upgrading production.
7.5Iterate SOUL.md per profileRefine each user's system prompt based on usage patterns. Collect feedback weekly.
7.6Scale if neededBeyond 25 users → resize VM to e2-standard-8 or migrate to GKE for autoscaling.
⏳ Status: Not started
🔲 Final milestone: System is stable, backed up, monitored. Team is self-sufficient. Roadmap items tracked.

Dependency Map

  Phase 1 (VM + Docker) ───────────────────────┐
                                               │
  Phase 2 (Google Chat bot) ───────────────────┤
                                               │
  Phase 3 (Multiplex + Profiles + Routing) ◄───┘
        │
        ├──► Phase 4 (Honcho shared memory)
        │
        ├──► Phase 5 (Google Drive per-user)
        │
        └──► Phase 6 (Team Rollout)
                 │
                 └──► Phase 7 (Operations, monitoring, hardening)
  

Critical path: Phase 1 → Phase 2 → Phase 3. Everything else is parallelizable. The system is usable for the team after Phase 3. Phases 4-7 add capability that can be rolled out gradually without disrupting users.

Estimated Timeline

DayDeliverableWho
Day 1VM running, bot responding to DMs, 2-3 test profiles workingAdmin
Day 225 profiles + multiplex + Honcho shared memory activeAdmin
Day 3Google Drive integration (per-user + team SA)Admin
Day 4Team rollout — all 25 users onboardedAdmin + Users
Day 5+Backups, monitoring, cost tracking, refinementsAdmin