Libra CodeHub

CedarCopilot/cedar-mail

Branch: staging

fix(slack): surface the incoming channel to the headless chat agent

merged#2524CedarCopilot

CedarCopilot wants to merge 0 commits into staging from fix/headless-slack-channel-context

Live on prod, no production signal yetTimeline and evidence
  1. Opened
    Aug 19, 2026, 10:51 AM
  2. Merged
    Aug 20, 2026, 10:13 AM
  3. Live on prod
    Aug 20, 2026, 10:13 AM
  4. Observed 31 hours
    Aug 20, 2026, 10:13 AM
  5. Pipelines steady after this deploy
    Aug 20, 2026, 10:13 AM
  6. Unobserved

    Live on prod, no production signal yet

    Aug 21, 2026, 5:26 PM

Behaviors Libra is checking

Chat workflow behavior from slack/slack-bot-chat.ts keeps working in prod.Inconclusivelow confidence

Strict CloudWatch fallback found 6 recent prod failure log lines for [backfillSlackChannelHistory] Backfill failed (Failed query: insert into \), but the same failure had 10 log lines in the comparable pre-deploy baseline. Libra is not blaming this PR intent without a.

prod, checked Aug 21, 2026, 5:26 PM
Slack integration behavior from slack/slack-origin-context.ts keeps working in prod.Inconclusivelow confidence

Strict CloudWatch fallback found 6 recent prod failure log lines for [backfillSlackChannelHistory] Backfill failed (Failed query: insert into \), but the same failure had 10 log lines in the comparable pre-deploy baseline. Libra is not blaming this PR intent without a.

prod, checked Aug 21, 2026, 5:26 PM

Failures attributed to this change

Customer impact is not proven from the retained evidence. 1 hit · 1 user · no retained trace sample.Introducedmedium confidence

single_user

prod, first seen Aug 20, 2026, 10:32 AM

Libra has verdicts on 0 of 2 tracked behaviors on prod; 2 are still being checked. Libra attributed 1 failure to this change at medium confidence and is still confirming it. Libra checks hourly for 3 days after each deploy.

Problem

When a rep messages the Cedar Slack bot something like "send my meeting preps here from now on", the headless chat agent can't see which channel/DM it's being addressed in, so it can't act on "here" , it guessed "your DM" and told the user everything was already fine.

Root cause: event.channel reaches handleSlackBotInteraction but is dropped at the runChatAgent() boundary. It only survives encoded inside the opaque threadId (slack:{team}:{channel}:{ts}), which the agent never parses. There is no channel field anywhere in the prompt or the headless chat context.

Fix

  • Thread a SlackOrigin { channelId, isDm } from the DM/mention/thread handler into runChatAgent.
  • Add buildSlackOriginContext() , a small dependency-free module (routeHandlers/slack/slack-origin-context.ts, so it's cheap to unit-test) that produces a prompt fragment naming the concrete channel ID and mapping "here" / "this channel" to it, or stating it's a DM.
  • The /cedar next DM digest passes nothing (correctly a DM), and buildSlackOriginContext(undefined) returns '' so the caller's .filter(Boolean) drops it.

Scope is deliberately just the input side (letting the agent see its channel). Where a recurring output is routed is unchanged and already agent-editable , e.g. meeting-prep delivery is the meeting-prep subagent's own notify/send slack.channelId.

Tests

slack-origin-context.test.ts , channel vs DM vs none, and that a channel message names the ID + points routing at the producing surface. All green.

Related follow-up (not in this PR)

listSlackChannels (slack-api.ts) lists channels via the superglue slack-list-channels workflow, which uses conversations.list (workspace public channels , ~9,982 in one workspace) and returns zero private channels, even ones the user is a member of and has groups:read for. Verified against a real user token=[redacted],private_channel returns their ~103 memberships *including* private channels. So an agent asked to route to a private channel *by name* still can't discover it (the "here"/event.channelpath in this PR is unaffected). Worth a separate PR switchinglistSlackChannelstousers.conversations` with both channel types.

🤖 Generated with Claude Code

Greptile Summary

The PR passes the originating Slack channel or DM into the headless chat-agent prompt so references such as “here” resolve to the correct surface.

  • Adds a typed Slack-origin prompt builder for channel, DM, and unknown-origin cases.
  • Threads event channel metadata through handleSlackBotInteraction into runChatAgent.
  • Adds focused unit coverage for generated origin context.

Confidence Score: 4/5

The PR appears safe to merge after the non-blocking import-path convention issue is corrected.

The Slack-origin data is threaded into prompt construction with focused tests, and no concrete runtime or security failure remains; only the two new relative imports conflict with repository standards.

Files Needing Attention: apps/server/src/mastra/routeHandlers/slack/slack-bot-chat.ts; apps/server/src/mastra/routeHandlers/slack/tests/slack-origin-context.test.ts

Important Files Changed

FilenameOverview
apps/server/src/mastra/routeHandlers/slack/slack-bot-chat.tsThreads Slack-origin metadata into the agent prompt correctly, but the new helper import violates the absolute-import convention.
apps/server/src/mastra/routeHandlers/slack/slack-origin-context.tsAdds a small typed prompt builder that distinguishes channel, DM, and absent-origin contexts.
apps/server/src/mastra/routeHandlers/slack/tests/slack-origin-context.test.tsCovers the helper's principal output variants, but its new import also violates the absolute-import convention.

Sequence Diagram

rendering diagram…
Show production surfaces and changed-file mapping

Production surfaces

Libra has not measured any production surfaces for this change yet.

Changed files → surfaces

  • apps/server/src/mastra/routeHandlers/slack/__tests__/slack-origin-context.test.tsno production surface mapped
  • apps/server/src/mastra/routeHandlers/slack/slack-bot-chat.tsno production surface mapped
  • apps/server/src/mastra/routeHandlers/slack/slack-origin-context.tsno production surface mapped