Skip to content

feat(bridges): render agents under their display name on Mattermost - #346

Merged
raullopez-sandbox merged 2 commits into
feat/display-name-03-teams-telegramfrom
feat/display-name-05-mattermost
Sep 4, 2026
Merged

feat(bridges): render agents under their display name on Mattermost#346
raullopez-sandbox merged 2 commits into
feat/display-name-03-teams-telegramfrom
feat/display-name-05-mattermost

Conversation

@raullopez-sandbox

Copy link
Copy Markdown
Collaborator

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_name and the username stays the
identifier, untouched.

Two things fall out of that:

  • Adoption was already broken. When Switch re-adopts an existing bot it
    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.
  • The name is a name field, not message text. It takes the label
    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 TeammateNameDisplay says
otherwise, 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 --check mode gates CI and would have
failed the first three on their own.

Reviewer note, deliberate trade-off: TeammateNameDisplay is 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:

TeammateNameDisplay post header
full_name (this PR) Switch Dev
username (stock) switchdev

The stored account record was identical in both — username: "switchdev",
first_name: "Switch Dev". That contrast is the entire argument for the
deploy 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_text
to close it.

🤖 Generated with Claude Code

raullopez-sandbox and others added 2 commits September 2, 2026 12:18
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
raullopez-sandbox merged commit d36d1ae into feat/display-name-03-teams-telegram Sep 4, 2026
10 checks passed

@abeldantas abeldantas left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants