feat(bridges): render agents under their display name on Mattermost - #346
Merged
raullopez-sandbox merged 2 commits intoSep 4, 2026
Conversation
Mattermost is the one platform that gives each agent an account of its own, so there is no per-message name to override. The bot's username is the routing handle — the mention, the channel member-list key, and the key an existing bot is adopted back by — and is constrained to lowercase alphanumerics besides, so it stays the identifier. The bot's separate display_name field is the presentation half, and takes the label. Adoption previously left it behind: a bot Switch re-adopts on start has its icon re-applied but never its name, so a display name changed after the bot existed stayed stale forever. It is now patched when it differs, and left alone when it does not. Whether any of this is visible is the server's call. Mattermost renders a bot under its username unless TeammateNameDisplay says otherwise, and the default says nothing else — so the name can be stored correctly and seen by nobody, with no write failing. Rather than ship a setting that quietly does nothing, warn once naming the setting and the two values that render it, and say so too when the config cannot be read to check. The label goes in as written. display_name is a name field Mattermost renders on its own, not message text, so escaping it would bake the zero-width spaces that defuse markup into the stored name. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Mattermost shows a bot under its username unless the server is told otherwise, so the display name the bridge now writes to each agent's bot account is stored and shown to nobody on a default server. The bridge warns when it detects that, but a warning is not a working feature. Set `TeammateNameDisplay` to the full name wherever Switch owns the Mattermost: the local compose, the standalone compose and the Helm chart. The bundled copy Switch Console ships is re-synced from the standalone compose by `sync-standalone-compose.mjs`, whose `--check` mode gates CI. This is a server-wide setting, so human members of these deployments render under their full names too. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
raullopez-sandbox
requested review from
amaudruz and
christian-mcdermott
as code owners
September 2, 2026 12:37
raullopez-sandbox
merged commit Sep 4, 2026
d36d1ae
into
feat/display-name-03-teams-telegram
10 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #338. Two commits: the bridge change, then the deploy default.
Why Mattermost needed its own PR
Every other platform lets a single bot post under a different name per
message. Mattermost doesn't — it gives each agent its own bot account, and
that account's username is the routing handle: the mention, the member-list
key, and how Switch re-adopts the bot after a restart. Usernames are also
3-22 chars, lowercase, no spaces, so "Switch Dev" cannot be one.
So the label goes on the bot's
display_nameand the username stays theidentifier, untouched.
Two things fall out of that:
re-applies the icon but never touched the display name. Renaming an agent
left the old label on the account forever. The adopt path now patches it
when stale.
verbatim, not the zero-width-defused body form. Sending the escaped form
would bake invisible characters permanently into a stored account name —
invisible in a diff, and there for good.
The deploy commit
Mattermost renders a bot under its username unless
TeammateNameDisplaysaysotherwise, and the default says username. Without the second commit, Switch
writes "Switch Dev", the write succeeds, nothing errors, and every human still
reads
switchdev— the silent-degradation case this repo explicitly forbids.The bridge warns when it detects that (once, and only when a label would
actually be hidden). The deploy commit makes it work wherever Switch owns
the server: local compose, standalone compose, Helm chart, plus the pinned
copy Switch Console bundles — re-synced with the repo's own
sync-standalone-compose.mjs, whose--checkmode gates CI and would havefailed the first three on their own.
Reviewer note, deliberate trade-off:
TeammateNameDisplayis server-wide,so human members of these deployments render under their full names too. And
because Mattermost freezes any setting supplied via env var, this becomes
fixed in the System Console rather than admin-editable. Both are consequences
worth accepting for the feature to do anything at all, but they are product
choices, not implementation details.
Verification
Core: 2201 pass, ruff and mypy clean, compose drift check green.
I ran a controlled experiment against a real Mattermost 11.9.0 rather than
trusting the docs — same server, same bot, same post, only the setting
changed:
TeammateNameDisplayfull_name(this PR)username(stock)The stored account record was identical in both —
username: "switchdev",first_name: "Switch Dev". That contrast is the entire argument for thedeploy commit.
I also mutation-tested the bridge commit. The one the suite initially missed:
swapping the verbatim label for the escaped body form passed all 1086 tests,
so I added
test_a_mattermost_bot_display_name_is_not_escaped_for_message_textto close it.
🤖 Generated with Claude Code