You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A Discord message whose whole content was a video, an image or a sticker reached a sidecar agent as an empty prompt: the bridge passed only message.clean_content. Monster answered one such video with "Tsc. Até pra falar você travou, criatura.", reading the silence as the person freezing mid-sentence. Sidecar is the transport for every codex and opencode channel agent; the embedded plugin transport used by claude agents already carried media both ways.
Inbound
channel_message/inbound_media.py downloads each attachment into <state-directory>/inbox/<message-id>/ and appends a <discord-media> block naming every attachment and sticker. A downloaded file is named by absolute path so the agent can open it; anything over 25 MB is named by URL instead; a failed download still reports that the attachment arrived. Attachment file names are sanitized, so a crafted name cannot write outside the inbox.
A message carrying only content the bridge still drops now runs no turn at all, rather than spending one on an empty prompt and drawing the same nonsense answer.
Outbound
channel_message/outbound_reply.py treats a reply line that is nothing but an absolute path to a file inside the agent's own workspace as an attachment: the line is stripped from the message and the file is uploaded with the first chunk. This is what makes clawde-agent-voice-note and clawde-agent-gif-search usable from a sidecar agent at all, since a sidecar has no reply tool and no files argument. Paths outside the workspace, symlinks escaping it, files over 25 MB and everything past Discord's ten-attachment limit are refused and logged rather than uploaded.
Retention
channel_message/inbox_retention.py keeps the downloads from becoming unbounded disk that a guest controls: two day retention, and oldest-first eviction once the inbox passes one gigabyte.
discord-runtime-sidecar.md documents both directions for the agent.
Verification
nix build .#checks.aarch64-darwin.unit-tests: 646 passed, including 33 new tests. Three of them drive on_message end to end: a video-only message saves its file and names it in the prompt, a reply line naming a workspace file leaves as an attachment, and an unrenderable message never reaches the harness. formatting and discord-transport-eval are green too.
A message whose whole content was an attachment or a sticker reached a
sidecar agent as an empty prompt, because the bridge passed only
clean_content, and the agent answered as if the person had said nothing.
Downloaded attachments now land in a per-message inbox under the agent's
channel state directory and are named to the agent by absolute path,
with oversized ones offered by URL instead.
The same channel carried nothing back: a sidecar agent had no reply tool
and no files argument, so every path printed by a media tool was dead
text. A reply line that is nothing but a path to a file inside the
agent's own workspace is now stripped from the message and uploaded as
an attachment.
Agent-Machine: kira
Agent-Resume: claude --resume efee1316-8d94-438e-951e-e9c978626531
Attachments and stickers now reach the agent, but a message carrying
only content the bridge still drops would arrive as an empty prompt and
draw the same nonsense answer. The bridge logs it and runs no turn.
The bridge-level tests exercise the whole path: a video-only message
saves its file and names it in the prompt, and a reply line naming a
workspace file leaves as an attachment.
Agent-Machine: kira
Agent-Resume: claude --resume efee1316-8d94-438e-951e-e9c978626531
…orever
Downloading every attachment a guild posts turned the channel state
directory into unbounded disk, which a guest controls: nothing capped
the total and the seven day window only slowed it down. Retention drops
to two days and the inbox now evicts its oldest messages once it passes
one gigabyte.
The retention policy moves into its own module, since deciding what to
keep on disk is not the same job as describing what arrived.
Agent-Machine: kira
Agent-Resume: claude --resume efee1316-8d94-438e-951e-e9c978626531
Discord's upload ceiling depends on the guild's boost level, so a file
this bridge considers small enough is still rejected at 413, and the
exception took the agent's text down with it. The upload failure is
logged and the text goes out on its own.
Agent-Machine: kira
Agent-Resume: claude --resume efee1316-8d94-438e-951e-e9c978626531
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
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.
A Discord message whose whole content was a video, an image or a sticker reached a sidecar agent as an empty prompt: the bridge passed only
message.clean_content. Monster answered one such video with "Tsc. Até pra falar você travou, criatura.", reading the silence as the person freezing mid-sentence. Sidecar is the transport for every codex and opencode channel agent; the embedded plugin transport used by claude agents already carried media both ways.Inbound
channel_message/inbound_media.pydownloads each attachment into<state-directory>/inbox/<message-id>/and appends a<discord-media>block naming every attachment and sticker. A downloaded file is named by absolute path so the agent can open it; anything over 25 MB is named by URL instead; a failed download still reports that the attachment arrived. Attachment file names are sanitized, so a crafted name cannot write outside the inbox.A message carrying only content the bridge still drops now runs no turn at all, rather than spending one on an empty prompt and drawing the same nonsense answer.
Outbound
channel_message/outbound_reply.pytreats a reply line that is nothing but an absolute path to a file inside the agent's own workspace as an attachment: the line is stripped from the message and the file is uploaded with the first chunk. This is what makesclawde-agent-voice-noteandclawde-agent-gif-searchusable from a sidecar agent at all, since a sidecar has no reply tool and nofilesargument. Paths outside the workspace, symlinks escaping it, files over 25 MB and everything past Discord's ten-attachment limit are refused and logged rather than uploaded.Retention
channel_message/inbox_retention.pykeeps the downloads from becoming unbounded disk that a guest controls: two day retention, and oldest-first eviction once the inbox passes one gigabyte.discord-runtime-sidecar.mddocuments both directions for the agent.Verification
nix build .#checks.aarch64-darwin.unit-tests: 646 passed, including 33 new tests. Three of them driveon_messageend to end: a video-only message saves its file and names it in the prompt, a reply line naming a workspace file leaves as an attachment, and an unrenderable message never reaches the harness.formattinganddiscord-transport-evalare green too.