One Feishu Bot, Multiple Hermes Profiles: A Hands-On v0.19 Profile Routing Tutorial


Before Hermes Agent v0.19, if you wanted different agent personas in different Feishu groups, the straightforward approach was: create a separate Feishu bot app for each group and run a separate Hermes Gateway for each. Many tokens, many processes, and scattered configuration.

v0.19’s multiplex_profiles + profile_routes let you use a single Feishu bot app and a single Gateway process to distribute messages from different groups or threads to different Profiles. Each Profile keeps its own model, skills, memory, and secrets, while sharing the same bot identity.

This post is based on the official Hermes v0.19.0 release and existing project docs, and provides a complete, ready-to-use configuration example.

Want the full picture first? Read our Hermes v0.19.0 Quicksilver release overview and the official v0.19.0 release notes.

Prerequisites

  • Hermes Agent >= v0.19.0
  • A created and approved Feishu (Lark) bot app
  • Event subscription enabled on the bot, able to receive im.message.receive_v1 and other message events
  • You have obtained app_id, app_secret, encrypt_key, and verification_token from the Feishu Open Platform

If you have not yet connected a Feishu bot to Hermes, start by setting the base credentials in ~/.hermes/.env:

FEISHU_ALLOWED_USERS=ou_xxxxxxxx,ou_yyyyyyyy
FEISHU_APP_ID=cli_xxxxxxxxxxxxxxxx
FEISHU_APP_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
FEISHU_ENCRYPT_KEY=xxxxxxxxxxxxxxxx
FEISHU_VERIFICATION_TOKEN=xxxxxxxxxxxxxxxx

Hermes’s Feishu adapter has been a full Gateway adapter since v0.6.0, supporting message cards, group chats, image/file attachments, and interaction callbacks, so basic connectivity should not be a blocker.

Core Concepts: multiplex_profiles + profile_routes

Before v0.19, Hermes Gateway already supported “one process connected to multiple platforms.” The new capability in v0.19 is: the same platform, the same bot token, and then route by source to different Profiles.

Key configuration items:

  • gateway.multiplex_profiles: true — enables multi-Profile reuse mode
  • gateway.profile_routes — defines the list of source-matching rules

Note: In multiplex mode, port-binding platforms (webhook, api_server, feishu, etc.) can only be configured in the default Profile; other Profiles receive messages through routing rules. This article discusses exactly that pattern: the default Profile runs the Feishu platform entrypoint, and profile_routes dispatches messages to work, personal, and other Profiles.

Feishu Configuration Example

Suppose you have three Feishu groups:

Group Purpose Target Profile
On-call tech group Handle alerts, check logs, run security commands ops
Product discussion group Write PRDs, do competitor analysis product
Personal assistant group Personal schedule, look up information personal

In ~/.hermes/config.yaml, write:

profiles:
  default:
    # The Feishu platform entrypoint must live in the default profile
    gateway:
      platforms:
        - platform: feishu
          app_id: "cli_xxxxxxxxxxxxxxxx"
          app_secret: "{{env.FEISHU_APP_SECRET}}"
          encrypt_key: "{{env.FEISHU_ENCRYPT_KEY}}"
          verification_token: "{{env.FEISHU_VERIFICATION_TOKEN}}"
          allowed_users:
            - "ou_xxxxxxxx"
            - "ou_yyyyyyyy"

  ops:
    model: "claude-sonnet-5"
    system_prompt: "You are an on-call technical assistant, skilled at log troubleshooting, container operations, and security response."
    skills:
      - kubernetes
      - sentry
    approvals:
      smart_approvals: true
    deny_rules:
      - pattern: "kubectl delete.*prod"
        reason: "Production delete operations are not allowed to run automatically."

  product:
    model: "gpt-5.6-sol"
    system_prompt: "You are a product manager assistant, skilled at writing PRDs, competitor analysis, and organizing user feedback."
    skills:
      - notion
      - web_search

  personal:
    model: "grok-4.5"
    system_prompt: "You are a personal productivity assistant with a relaxed tone."

gateway:
  multiplex_profiles: true
  profile_routes:
    - name: feishu-ops
      platform: feishu
      chat_id: "oc_xxxxxxxxxxxxxxxx"
      profile: ops

    - name: feishu-product
      platform: feishu
      chat_id: "oc_yyyyyyyyyyyyyyyy"
      profile: product

    - name: feishu-personal
      platform: feishu
      chat_id: "oc_zzzzzzzzzzzzzzzz"
      profile: personal

    # Fallback: route all direct messages from a given user to personal
    - name: feishu-dm
      platform: feishu
      user_id: "ou_xxxxxxxx"
      profile: personal

After saving, run:

hermes config validate
hermes gateway restart

Feishu Routing Fields Explained

v0.19 profile_routes supports the following fields for Feishu/Lark, ordered by match specificity:

Field Meaning Example Specificity
platform Platform type, required feishu Base
chat_id Feishu group/session ID (starts with oc_) oc_xxxxxxxxxxxxxxxx High
thread_id Feishu topic/thread ID omt_xxxxxxxxxxxxxxxx Highest
user_id Feishu user ID (starts with ou_) ou_xxxxxxxx Medium-high
tenant_id Enterprise/tenant ID (multi-tenant scenarios) xxx Medium
profile Target Profile name ops
name Rule label feishu-ops

Matching rules:

  1. All declared fields must match (AND logic).
  2. Undeclared fields are ignored and do not participate in matching.
  3. Higher specificity wins: thread_id > chat_id > user_id > tenant_id > platform-only.
  4. At the same specificity level, the earlier declared rule wins.

So you can route an entire group by chat_id, then use thread_id to分流 a specific topic inside that group to a different Profile.

How to Get Feishu chat_id / thread_id / user_id

The easiest way: let Hermes run with the default Profile first, then look at the session_key or event payload in the logs after receiving a message. By default the logs print something like:

[feishu] incoming message chat_id=oc_xxxxxxxxxxxxxxxx thread_id=omt_yyyyyyyy user_id=ou_zzzzzzzz

Or temporarily add an echo skill to the default Profile so it replies with:

chat_id: oc_xxxxxxxxxxxxxxxx
thread_id: omt_yyyyyyyy
user_id: ou_zzzzzzzz

Once you have the IDs, write them into profile_routes and restart the Gateway.

A Common Pitfall: Don’t Configure Feishu in Multiple Profiles

In multiplex mode, if you also write this in the ops Profile:

profiles:
  ops:
    gateway:
      platforms:
        - platform: feishu
          ...

Startup will fail. Because feishu is a port-binding platform, the entrypoint can only belong to the default Profile. Secondary Profiles get their Feishu capability entirely from profile_routes.

If you need process-level hard isolation (for example, ops must never share a process with personal), do not use multiplex. Instead, start a separate Gateway for each Profile with hermes -p ops gateway start.

Debugging and Validation Commands

# Check whether multiplex mode is enabled
hermes config get gateway.multiplex_profiles

# Check the active profile_routes
hermes config get gateway.profile_routes

# Validate configuration syntax
hermes config validate

# Start/restart the Gateway
hermes gateway start
hermes gateway restart

# Check Gateway status and see which Profiles are served under multiplex
hermes status

# View real-time Feishu platform logs (run in another terminal)
hermes gateway --log-level debug

After sending a test message, check the logs for:

[multiplex] routed feishu chat_id=oc_xxx to profile=ops

If you do not see this, the rule did not match. Check whether chat_id is wrong or has extra spaces.

Advanced: Thread Isolation with thread_id Routing

Feishu threads inside a group are like sub-channels. You can route different threads in the same group to different Profiles:

gateway:
  multiplex_profiles: true
  profile_routes:
    - name: feishu-ops-main
      platform: feishu
      chat_id: "oc_xxxxxxxxxxxxxxxx"
      profile: ops

    - name: feishu-ops-oncall
      platform: feishu
      chat_id: "oc_xxxxxxxxxxxxxxxx"
      thread_id: "omt_yyyyyyyyyyyyyyyy"
      profile: ops-oncall

Because thread_id has higher specificity, messages in that thread go to ops-oncall, while other messages in the group go to ops.

Advanced: Multi-Tenant Scenarios with tenant_id

If you install the same bot app in multiple Feishu enterprises (ISV scenario), you can route by tenant_id:

gateway:
  profile_routes:
    - name: tenant-a
      platform: feishu
      tenant_id: "tenant_a_id"
      profile: customer-a

    - name: tenant-b
      platform: feishu
      tenant_id: "tenant_b_id"
      profile: customer-b

Combined with Hermes’s per-profile secret scopes, each tenant can have fully isolated secrets and model configuration.

Security Recommendations

  1. Always set allowed_users: Feishu bots should only respond to whitelisted users, preventing abuse if the bot is invited into an unknown group.
  2. Layer permissions across Profiles: the ops Profile can connect to operational tools, but the product Profile should not have production execution permissions.
  3. Use deny_rules as a safety net: even if a Profile is routed incorrectly, deny rules can prevent dangerous commands from executing automatically. See our earlier Hermes v0.19 smart approvals three-gate tutorial.
  4. Verify chat_id accuracy: Feishu oc_ IDs are easily confused with ou_ IDs. A mistake causes messages to fall back to the default Profile or fail to match entirely.

Summary

Hermes v0.19’s profile_routes turns a Feishu bot from “one bot, one agent” into “one bot, many agents.” The configuration comes down to three steps:

  1. Configure the single feishu platform entrypoint in the default Profile;
  2. Enable gateway.multiplex_profiles: true;
  3. Use gateway.profile_routes to dispatch by chat_id, thread_id, user_id, or tenant_id to different Profiles.

With this, the same Feishu bot can act as an on-call assistant in the tech group, a PRD writer in the product group, and a personal secretary in direct messages—without maintaining multiple bots or Gateway processes.

# Final check and start
hermes config validate
hermes gateway restart
hermes status