Slack Call Summary - Codex
When Tuple transcription completes, headlessly runs Codex to summarize the call (read via the `tuple` CLI), write a title and summary back onto the call, and DM the summary to Slack.
Headlessly runs Codex when Tuple transcription completes: it summarizes the call, writes a title and summary back onto the call (Tuple's Call History), and DMs the summary to Slack.
Unlike the interactive call-summary-codex trigger, this one runs entirely in the background — no terminal window, no UI. You see nothing except a Slack DM arriving a few minutes after your call ends, and the summary showing up on the call.
It's a one-shot over the finished call — no tuple connect, nothing live to follow. Codex finds the call, reads its stored transcript with the tuple CLI, and does the work.
[!WARNING] This trigger runs Codex with
--dangerously-bypass-approvals-and-sandbox— no sandbox, no approval prompts, fully unattended, with a call transcript (untrusted speech-to-text) as input. Codex'sexecmode currently has no narrower way to let an unattended run use connector tools like the Slack send (openai/codex#24135). Read A note on sandboxing before installing, and if that trade-off doesn't work for you, use Slack Call Summary - Claude instead — it runs with a scoped tool allowlist.
Prerequisites
- macOS
- Codex installed so
codexworks in a new terminal - The
tupleCLI on your interactive shell PATH (withtranscriptionsupport)- Install it from the Tuple app: its Transcription settings have an Install button that links
tupleonto your PATH.
- Install it from the Tuple app: its Transcription settings have an Install button that links
- A Slack connector available to Codex with a
slack_send_messagetool. The OpenAI-curated Slack plugin works out of the box — enable it and sign in socodexhas the Slack tools available. - Tuple transcription enabled for the call
Installation
Drop this directory into your Tuple triggers folder:
~/.tuple/triggers/slack-call-summary-codex/
The trigger fires when call transcription completes.
Configuration
By default the summary is sent as a DM to yourself (the authenticated Slack user). To send to a different person or channel, edit the SLACK_RECIPIENT= line near the top of call-transcription-complete:
SLACK_RECIPIENT="${SLACK_RECIPIENT:-#my-channel}" # a channel
SLACK_RECIPIENT="${SLACK_RECIPIENT:-@jack}" # another user by handle
SLACK_RECIPIENT="${SLACK_RECIPIENT:-Jack Hannah}" # another user by display name
Leave it empty (the default) to DM yourself. The environment variable form also works, but Tuple launches triggers outside your shell, so an export in your shell rc won't reach it — use launchctl setenv SLACK_RECIPIENT "#my-channel" if you prefer the environment route.
How it works
call-transcription-complete fires with no call-specific arguments. This trigger:
- Writes
slack-call-summary-codex-prompt.mdinto a working directory (${TMPDIR:-/tmp}/tuple-slack-call-summary-codex/<timestamp>-<pid>), including the configured recipient and all instructions. - Headlessly launches a login zsh (
nohup zsh -lc, socodexandtupleresolve from your normal PATH — no terminal window) that runscodex execin that directory with the prompt on stdin and--dangerously-bypass-approvals-and-sandbox(required for unattended Slack connector use).tupleinBashlets Codex read the call; the Slack connector lets it send the message. - Codex finds the call (
tuple call current/tuple transcription list), reads it (tuple transcription show <id> --with-events), writes the title + summary back (tuple transcription set-title/set-summary), and sends the Slack message.
A note on sandboxing
The trigger passes --dangerously-bypass-approvals-and-sandbox to codex exec. This is required, not a convenience: in non-interactive exec mode Codex auto-cancels any approval-gated connector tool call (user cancelled MCP tool call) because there is no user present to approve it, and as of Codex 0.139 no apps.* / mcp_servers.* approval_mode configuration suppresses that (see openai/codex#24135). Without the flag, the Slack send always fails.
The prompt is fixed, but the transcript it reads is not: call transcripts are speech-to-text of whatever was said (or shown) on the call, which makes them untrusted input to an unsandboxed, unattended agent. If that trade-off doesn't work for you, use the Claude variant of this trigger (which runs with a scoped tool allowlist) or the interactive call-summary-codex trigger (read-only sandbox) instead. If a later Codex release lets exec approve connector tools via configuration (watch the linked issue), the bypass flag here can be replaced with --sandbox workspace-write plus that configuration.
Troubleshooting
- Trigger not firing: Check
/tmp/tuple-trigger-debug.log— the bannercall-transcription-complete fired (slack-call-summary-codex)appears each time the trigger runs. - No Slack DM and no error: Check
slack-call-summary-codex.login the working directory (printed at launch) for the Codex run output. - Slack delivery failed: Look for
slack-call-summary-codex-failed.mdin the working directory — it contains the composed message and the error. Also checkslack-call-summary-codex-last-message.mdfor the final Codex agent message. codex not found/tuple not found: Make sure both are on your login-shell PATH (test withzsh -l -c 'which codex tuple').- Slack connector not available: Open
codexin a terminal and confirm the Slack plugin is signed in. The prompt tells Codex to write a fallback file if the tools are unavailable.
Dry run
To test the trigger without launching Codex, set SLACK_CALL_SUMMARY_CODEX_DRY_RUN=1. The trigger generates the prompt file and exits — nothing is sent to Slack. (Output goes to /tmp/tuple-trigger-debug.log.)