Libra CodeHub

CedarCopilot/cedar-mail

Branch: staging

feat(config-read): add find-bot-slack-channels for authoring-time delivery checks

merged#2719CedarCopilot

CedarCopilot wants to merge 0 commits into docs/cedar-authoring-skill-fixes from feat/find-bot-slack-channels

Not deployedTimeline and evidence
  1. Opened
    Sep 7, 2026, 10:40 AM
  2. Merged
    Sep 7, 2026, 1:59 PM
  3. Not deployed

    Not deployed

    Pending

Libra has no production signal for this change yet because it has not deployed. Libra checks hourly for 3 days after each deploy.

Summary

  • New config-read action find-bot-slack-channels: resolves which Slack channels Cedar's bot can actually post to, at authoring time , replacing the prior workaround of a raw curl to users.conversations left in skill prose.
  • Distinct from notify's list-slack-channels (a personal notification-destination picker scoped to the caller's own membership) , this answers "can Cedar deliver here," not "where does this rep want their own alerts." That tool is untouched.
  • An org admin/owner sees every channel the bot is in; a regular member sees only the channels they are also personally a member of, so a non-admin caller never learns a private channel exists that they cannot see themselves.
  • The admin/member split rides authorize()'s existing connection_config:org policy row (ORG_ADMIN) rather than a new role predicate , services/auth/ deliberately never exports one for a call site to branch on, enforced by role-reads-confined-to-authority.test.ts. (An earlier version of this PR did export one; the guard test caught it during review and it was redesigned before this commit , see review notes below.)
  • Extracted a shared fetchUsersConversations pagination helper so the new bot-membership listing doesn't duplicate the existing per-user listing's loop.
  • Updated playbook-authoring/SKILL.md's Channel↔DM and ANNOUNCE guidance to point at this tool instead of the prior curl example.

Found while auditing two Aspire org agents whose Slack delivery was authored against a private channel most reps could never resolve by name at runtime , the actual bug and fix are covered in a separate PR; this is the authoring-time prevention.

Base branch note: this stacks on docs/cedar-authoring-skill-fixes (not yet merged), since that branch renamed the field-scoping resource this PR's sibling work also touches contextually. No file overlap between the two PRs.

Review notes (self-reviewed via /thermo-review before opening)

Two real issues were found and fixed during review, not left as follow-ups:

  1. Governance violation: the first implementation added isOrgAdmin as an exported role predicate in services/auth/org-role.ts. role-reads-confined-to-authority.test.ts failed immediately , its own comment literally anticipates and preempts this exact addition ("the precedent a new isOrgAdmin would be added by analogy with"). Redesigned to call authorize() directly instead; org-role.ts is back to its original, untouched state.
  2. Duplication: listBotSlackChannels initially copied listUserSlackChannels's entire pagination loop byte-for-byte. Extracted fetchUsersConversations so both are now thin wrappers over one shared loop.

Test plan

  • pnpm --filter @zero/server exec tsc -p tsconfig.test.json --noEmit , zero errors in any touched file
  • pnpm --filter @zero/server exec vitest run across the touched test files , 395/395 pass, including:
    • services/auth/__tests__/role-reads-confined-to-authority.test.ts (the architectural guard this PR's first draft violated)
    • mastra/mcp/external/__tests__/tool-inputschema-size.test.ts (connector schema-size budget , config-read measured at 6,235/18,000 bytes after this change)
    • New coverage: services/integrations/slack/__tests__/list-bot-slack-channels.test.ts (pagination, bot-token usage, admin/member selection logic) and a new configTool.test.ts describe block for the dispatch wiring

🤖 Generated with Claude Code

https://claude.ai/code/session_01F4mjBtjYZyxnVvLQpehDSb

Greptile Summary

Adds a config-read action for discovering Slack channels reachable by Cedar's bot and updates authoring guidance to use it.

  • Introduces bot-token channel pagination and admin/member result selection.
  • Adds external scope mapping, schemas, dispatch wiring, and unit coverage.
  • Updates playbook-authoring instructions to replace direct Slack API calls.
  • The current tok
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/.claude/skills/playbook-authoring/SKILL.mdno production surface mapped
  • apps/server/src/mastra/mcp/external/__tests__/scope-map.test.tsno production surface mapped
  • apps/server/src/mastra/mcp/external/scope-map.tsno production surface mapped
  • apps/server/src/mastra/tools/config/__tests__/configTool.test.tsno production surface mapped
  • apps/server/src/mastra/tools/config/config-read-tool.tsno production surface mapped
  • apps/server/src/services/integrations/slack/__tests__/list-bot-slack-channels.test.tsno production surface mapped
  • apps/server/src/services/integrations/slack/slack-api.tsno production surface mapped