Libra CodeHub

CedarCopilot/cedar-mail

Branch: staging

feat(config): inbox customization, task groups, and external-system credentials on the config service

merged#2549CedarCopilot

CedarCopilot wants to merge 7 commits into staging from feat/config-inbox-task-groups

Live on prod, no production signal yetTimeline and evidence
  1. Opened
    Aug 22, 2026, 10:14 PM
  2. Aug 31, 2026, 11:31 AM
  3. Merged
    Aug 31, 2026, 12:57 PM
  4. Live on prod
    Aug 31, 2026, 12:57 PM
  5. Observed 2 days
    Aug 31, 2026, 12:57 PM
  6. Pipelines steady after this deploy
    Aug 31, 2026, 12:57 PM
  7. Unobserved

    Live on prod, no production signal yet

    Sep 2, 2026, 6:41 PM

Behaviors Libra is checking

CRM integration behavior from tools/apply-systems-change.ts, tools/applyConfigChangeTool.ts, tools/readConnectionSettingsTool.ts keeps working in prod.Inconclusivelow confidence

Strict CloudWatch fallback found 28 recent prod failure log lines for [UpdateExternalCrmWorkflow] Driver update failed (Step updateOpportunityField failed: HTTP 400: [{\), but the same failure had 16 log lines in the comparable pre-deploy baseline. Libra is not blaming this PR.

prod, checked Aug 31, 2026, 2:45 PM
Email workflow behavior from inboxes/inbox-settings-config.ts keeps working in prod.Inconclusivelow confidence

Strict CloudWatch fallback found 2 recent prod failure log lines for mirror.upsertEmailThread failed (write CONNECTION_CLOSED aws-1-us-east-2.pooler.supabase.com:6543), but the same failure had 1 log lines in the comparable pre-deploy baseline. Libra is not blaming this PR.

prod, checked Sep 2, 2026, 6:41 PM
Observability telemetry behavior from external/tool-call-observability.ts keeps working in prod.Inconclusivelow confidence

Strict CloudWatch fallback found no success or completion log lines matching /tool-call-observability.ts, applyconfigchangetool, readconnectionsettingstool, configtool, workspacewritetool in the last 24h.

prod, checked Sep 2, 2026, 6:41 PM

Libra has verdicts on 0 of 3 tracked behaviors on prod; 3 are still being checked. Libra checks hourly for 3 days after each deploy.

What

Adds three configuration surfaces to Cedar's chat/MCP config service, plus task→group reassignment:

  1. Task groups , CRUD via apply-change
  2. Inbox customization , layout scalars + split CRUD
  3. External systems , credentials and MCP servers (new; see below)

1. Task Groups , CRUD via apply-change

  • Extracted the inline tRPC CRUD into services/task-groups/manage-task-groups.ts (ownership guard + Gmail-label side-effects); the tRPC route delegates.
  • New manage_task_group ConfigChange variant: op: create | update | delete | reorder.

2. Inbox Customization , via apply-change

  • update_inbox_settings , layout scalars (inboxLayout, importantSignal, inboxOrder).
  • manage_inbox , split CRUD, delegating to inbox-definitions.ts. accountId resolved server-side.

3. External systems , the new systems-write tool

PR #2623 shipped the credential vault and org-shared MCP with a complete resolve path, but writes reachable only from tRPC and the settings UI. An agent could use a credential and not store one, so onboarding a customer's Xero or internal API was still a human clicking through Settings. This adds the write half.

Three variants: manage_credential_entry, manage_mcp_connection, update_mcp_connection_settings.

A fourth tool, not actions on config-write. That tool's rendered inputSchema sits 385 bytes under the claude.ai connector's silent-drop ceiling (measured; budget enforced by tool-inputschema-size.test.ts). These variants are several KB, and going over makes the whole config write surface vanish from tools/list with no error anywhere. Same split, and same reason, as workspace-write.

Closes a gap in #2623 while extracting. services/integrations/mcp/manage-mcp-connections.ts comes out of the tRPC route (single writer, as manage-task-groups.ts already is here). The manual/API-key path never stamped scope, so a bearer-token MCP server could not be org-shared even though an OAuth one could. The read side needed nothing , selectMcpConnections already resolves user-over-org.

4. Read support

inboxes, task_groups and credentials sections on read-settings. The credentials section returns CredentialEntrySummary, which cannot carry a secret by construction (field NAMES only; needsAttentionReason is a classification code).

5. Task→group reassignment

Nullable taskGroupId on the update-task surface (null = Misc), with the ownership check and Gmail relabel from taskGroups.moveTaskToGroup.

Secrets travel in, never out

Results name FIELDS, never values. That asymmetry is what lets systems-write be reachable over external MCP at playbook:write rather than taking config-read.get-credentials' in-app-only treatment , that action returns raw tokens; this one only accepts them. Headless account setup is the driving use case and in-app would lock it out.

scope: 'org' never takes an organizationId from the caller: it is resolved from their own membership and gated on userIsOrgAdmin (the same rule credential-vault's orgAdminProcedure applies on the tRPC path , verified equivalent, both read user.organizationRole).

Redaction is at mcp/external/tool-call-observability.ts, not in the tool. Found by driving the real /mcp endpoint: a redaction inside applyConfigChangeTool left the approval card clean while Axiom recorded "authorizationHeader":"Bearer sk-live-…" in full, because that wrapper reads the arguments before any tool body runs. It feeds two sinks (telemetry inputPreview, and the chat/Slack intent sink). utils/redact-secrets.ts is therefore tool-agnostic, keyed on field name, and recursive , the leaked field was two levels down at arguments.change.authorizationHeader , so it covers every tool now and later. The handler still receives the real values.

Merge with staging

Staging shipped #2622's user-authored-task guard, whose rationale quotes the reporter: *

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/index.tsno production surface mapped
  • apps/server/src/mastra/mcp/external/__tests__/scope-map.test.tsno production surface mapped
  • apps/server/src/mastra/mcp/external/__tests__/tool-call-observability.test.tsno production surface mapped
  • apps/server/src/mastra/mcp/external/scope-map.tsno production surface mapped
  • apps/server/src/mastra/mcp/external/server.tsno production surface mapped
  • apps/server/src/mastra/mcp/external/tool-call-observability.tsno production surface mapped
  • apps/server/src/mastra/skills/account-config/tools/__tests__/apply-systems-change.test.tsno production surface mapped
  • apps/server/src/mastra/skills/account-config/tools/__tests__/applyConfigChangeTool.test.tsno production surface mapped
  • apps/server/src/mastra/skills/account-config/tools/apply-systems-change.tsno production surface mapped
  • apps/server/src/mastra/skills/account-config/tools/applyConfigChangeTool.tsno production surface mapped
  • apps/server/src/mastra/skills/account-config/tools/readConnectionSettingsTool.tsno production surface mapped
  • apps/server/src/mastra/tools/config/__tests__/configTool.test.tsno production surface mapped
  • apps/server/src/mastra/tools/config/__tests__/workspaceWriteTool.test.tsno production surface mapped
  • apps/server/src/mastra/tools/config/config-read-tool.tsno production surface mapped
  • apps/server/src/mastra/tools/config/config-write-tool.tsno production surface mapped
  • apps/server/src/mastra/tools/config/systems-write-tool.tsno production surface mapped
  • apps/server/src/mastra/tools/config/workspace-write-tool.tsno production surface mapped
  • apps/server/src/mastra/tools/task/__tests__/updateTaskTool.test.tsno production surface mapped
  • apps/server/src/mastra/tools/task/schemas.tsno production surface mapped
  • apps/server/src/mastra/tools/task/taskTool.tsno production surface mapped
  • apps/server/src/mastra/tools/task/updateTaskTool.tsno production surface mapped
  • apps/server/src/mastra/tools/task/user-authored-task-guard.tsno production surface mapped
  • apps/server/src/mastra/utils/__tests__/redact-secrets.test.tsno production surface mapped
  • apps/server/src/mastra/utils/redact-secrets.tsno production surface mapped
  • apps/server/src/services/integrations/mcp/__tests__/manage-mcp-connections.test.tsno production surface mapped
  • apps/server/src/services/integrations/mcp/manage-mcp-connections.tsno production surface mapped
  • apps/server/src/services/mail/inboxes/__tests__/resolve-default-email-account.test.tsno production surface mapped
  • apps/server/src/services/mail/inboxes/inbox-settings-config.tsno production surface mapped
  • apps/server/src/services/organizations/__tests__/org-admin.test.tsno production surface mapped
  • apps/server/src/services/organizations/org-admin.tsno production surface mapped
  • apps/server/src/services/organizations/organizations.tsno production surface mapped
  • apps/server/src/services/playbook/playbook-webhook-registration.tsno production surface mapped
  • apps/server/src/services/task-groups/__tests__/manage-task-groups.test.tsno production surface mapped
  • apps/server/src/services/task-groups/manage-task-groups.tsno production surface mapped
  • apps/server/src/trpc/routes/__tests__/integrations-mcp-delete.test.tsno production surface mapped
  • apps/server/src/trpc/routes/integrations.tsno production surface mapped
  • apps/server/src/trpc/routes/org-admin.tsno production surface mapped
  • apps/server/src/trpc/routes/task-groups.tsno production surface mapped
  • docs/design/config-service-credentials-and-mcp.mdno production surface mapped
  • docs/design/config-service-inbox-and-task-groups.mdno production surface mapped