Skip to content

[Feature]: one gateway serves multiple agents — switch via /profile <name> or @<name> #24913

@unliftedq

Description

@unliftedq

Problem or Use Case

Hermes profiles give you fully isolated agent identities — each with its own
SOUL, memory, skills, and config. But today, the only way to expose them as
distinct "agents" to a user is to run one gateway process per profile, each
bound to its own platform credential.

This works on platforms where multiple credentials are cheap and idiomatic:

  • Telegram: one bot token per profile → users get @CoderHermesBot,
    @WriterHermesBot, etc.
  • Discord: one bot user per profile → users see different bot accounts
    in a server.

But for other channels, a user who wants both a coding assistant and a writing
assistant has to choose one — or run two completely separate gateways and
remember which port/URL is which.

And for some channel, like WeChat, it can only bind to one single instance.

Proposed Solution

Make the gateway profile-agnostic and surface profile switching through
chat-level slash commands. No new platform credentials needed.

User-facing surface

Command Effect
/profile Show the chat's active profile + host info
/profile ls List all available profiles (one per ~/.hermes/profiles/<name>/)
/profile coder Bind this chat to the coder profile (persisted; survives restart)
/profile default Reset to the default profile
@coder fix this bug Route just this turn to coder; chat binding intact

Replies are prefixed with [<agent>] so the user can tell who answered.
Toggle via gateway.show_agent_name: true/false in config.yaml.

Isolation guarantees

  • Memory / skills / soul: hard-isolated per profile (each profile's
    ~/.hermes/profiles/<name>/ directory).
  • Session / transcript: each (chat, agent) pair owns an independent
    session_id/profile coder after talking to default starts (or
    resumes) coder's own conversation. Switching back to default restores
    its prior transcript. Matches "two independent Telegram bots" semantics
    rather than "one bot wearing different hats."
  • Gateway runtime state (sessions DB, gateway config, host platform
    tokens): stays in the host profile — the gateway is the orchestrator,
    the agents are what it routes between.

Mechanism (one paragraph)

HERMES_HOME becomes a ContextVar consulted by hermes_constants.get_hermes_home()
before the env var, so each turn runs inside agent_home_scope(<agent.home>)
and every profile-aware path (memory, skills, SOUL.md) resolves to the right
profile without rebinding the process env var. build_session_key takes an
agent_name parameter so (chat, agent) pairs naturally get distinct
session_keys → distinct session_ids → distinct transcripts. Chat-level
bindings persist to sessions/chat_bindings.json.

Backward compatibility

  • Default agent keeps the legacy agent:main:... session_key prefix → existing
    state.db and sessions.json work with zero migration.
  • Single-profile users see no behavior change: get_chat_agent defaults to
    default, response prefix is on by default but can be disabled, no new
    commands required.
  • build_session_key(source) without agent_name still works (defaults to
    default).

Alternatives Considered

No response

Feature Type

Gateway / messaging improvement

Scope

Large (new module or significant refactor)

Contribution

  • I'd like to implement this myself and submit a PR

Debug Report (optional)

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Low — cosmetic, nice to havecomp/gatewayGateway runner, session dispatch, deliverytype/featureNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions