Your Shared Gateway Shouldn't Serve Every Profile: multiplex_profile_allowlist in Hermes

You run one Discord gateway on a shared server, and the machine has five Hermes profiles installed: a general-purpose default, a restricted profile for the kids, two developer profiles. Start the gateway and it boots every profile’s adapters and cron jobs at once. Worse: a message that was supposed to route to the restricted profile arrives while that profile is unavailable — and the gateway quietly runs it under default instead. For a restricted profile that is not graceful degradation; that is crossing the capability boundary. PR #83400, merged on August 11, 2026, closes exactly this gap: gateway.multiplex_profile_allowlist lets you declare which profiles your shared gateway serves, and routing that misses the served set now fails closed — the message is rejected, never silently downgraded.
One config key to define the served set
Add the allowlist to config.yaml:
gateway:
multiplex_profiles: true
multiplex_profile_allowlist:
- worker
- guest
With those four lines, this gateway only starts and serves default, worker, and guest — every other profile installed on the host is neither started nor exposed through this gateway.
The exact semantics of the allowlist
The rules (official multi-profile-gateways.md docs) are worth going through one by one, because the edge cases are all handled:
defaultis always served — you never need to list it;- Unset = historical behavior: serve every valid named profile on the host;
- Empty list
[]= serve onlydefault; - Names are normalized and deduplicated; invalid entries or profiles that aren’t installed are skipped with a warning; a malformed non-list value fails safe to default-only, not to a crash;
- The served set also controls
/p/<profile>/API and webhook prefixes, runtime status,profile_routeseligibility, and which profiles the in-process cron scheduler ticks; - A named profile outside the allowlist is not started by this gateway — but it can still run its own standalone gateway. “Not served by the shared gateway” does not mean “unusable”.
Fail closed: reject, don’t silently downgrade
This is the security-relevant part of the change. Before, the risk was: profile_routes explicitly routed a channel to a restricted profile, but if that profile was unavailable (not installed, broken, outside the served set), traffic would silently fall back to default. The rule is now inverted:
- An explicit route matches but its target profile is not installed or outside the allowlist → the gateway rejects the message and logs the route and target profile — it never runs
defaultfor it; - Traffic that matches no route keeps the historical behavior (goes to
default); profile_routesonly applies whenmultiplex_profiles: true.
Real-world scenario: a restricted profile on a shared gateway
The classic use case is a family-shared bot: one Discord bot where regular channels run on default and the kids’ channel runs on a restricted profile. Set it up in two layers:
- Gateway layer:
multiplex_profile_allowlistlists onlydefault+kids-safe, andprofile_routessends the kids’ channel tokids-safe; - Profile layer: hardening lives in the restricted profile’s own
config.yaml— enabling only the toolset it needs, not inheritingdefault’s credentials, and so on. Profiles are isolated config homes, so that isolation is done at this layer anyway.
One boundary to state plainly: the official docs remind us that profile routing plus an allowlist is not a complete security sandbox. When you need an operating-system-level hard boundary (say, code that must run in an isolated environment), use separate processes or container isolation — don’t expect config-level routing to backstop it.
The takeaway
multiplex_profile_allowlist is a small change that solves a real shared-gateway pain: you have profiles installed for different purposes, but the gateway used to serve them all indiscriminately — and degrade silently when a route missed. Now you can declare exactly who this gateway serves, and turn that degradation into a rejection. For the full profile multi-instance concept, see our multi-profile guide; profile routing in a Feishu setup is covered in that article; the command surfaces live in the hermes-gateway and hermes-profile reference pages.