Control local Claude Code, Codex CLI, and Pi sessions from Slack. Each terminal session gets a private Slack channel where prompts, responses, tables, and attachments flow both ways. Close the terminal, write in Slack later, and the bridge opens a new Ghostty window and resumes the same native conversation.
The providers deliberately have separate command namespaces: /cc-* is Claude
Code, /codex-* is Codex, and /pi-* is Pi. They share the reliable session,
Slack, tmux, and Ghostty infrastructure without pretending that
provider-specific capabilities are identical. A channel can safely hand work
between providers while preserving a separate resumable native conversation
for each one it has used.
Warning
This is remote code execution by design. Slack-spawned Claude sessions
default to --dangerously-skip-permissions; Slack-spawned Codex sessions
default to --dangerously-bypass-approvals-and-sandbox (--yolo). Pi's
built-in tools are unrestricted by default; SAB's optional --safe
flag adds fail-closed Slack approval per tool call. Anyone able to act as the
bridge owner in Slack can steer processes on this Mac.
Read SECURITY.md before installing. This project is not
affiliated with Anthropic, OpenAI, or Slack.
Note
macOS only: the current implementation uses launchd, Ghostty, and open.
Claude uses the Channels research-preview API; Codex uses lifecycle hooks and
tmux; Pi uses an explicitly loaded native extension. Linux support needs a
service and terminal-spawn adapter.
| Capability | Claude Code | Codex CLI | Pi |
|---|---|---|---|
| Private channel per terminal session | ✓ | ✓ | ✓ |
| Slack prompts and file attachments | ✓ | ✓ | ✓ |
| Native image input when the model supports it | Path | Path | ✓ |
| Return generated files to Slack | ✓ | ✓ | ✓ |
| Mirrored prompts and final responses | ✓ | ✓ | ✓ |
| Terminal-close detection and Slack resume | ✓ | ✓ | ✓ |
| Model and reasoning/thinking controls | ✓ | ✓ | ✓ |
| Approve/deny from Slack in permissioned mode | ✓ | ✓ | --safe |
| Default unattended mode | --dangerously-skip-permissions |
--yolo |
unrestricted tools |
| Live working status with time and token counters | ✓ | ✓ | ✓ |
| Token and cost usage | ccusage |
ccusage |
native event ledger |
| Handoff among providers in one Slack channel | ✓ | ✓ | ✓ |
| Persistent plan/goal/review orchestration | — | — | adaptive; /pi-run controls |
| Claude subscription switching | ✓ | — | — |
| Chrome integration flag | --chrome |
No counterpart | No counterpart |
| Live web search flag | Provider-managed | --search |
model/provider-managed |
While a turn is active, its live status remains the newest channel item: newer messages, bridge output, artifact deliveries, and topic notices re-anchor the timer without resetting its elapsed-time or token state.
Codex output uses stable hook fields and the bridge never parses its unstable
transcript JSONL directly; usage telemetry is delegated to ccusage's public
Codex JSON adapter. Pi uses its native extension API for inbound messages,
lifecycle, settings, usage, and safe-mode decisions; the bridge does not parse
Pi session files. Claude retains its MCP Channel and transcript/status
integration. See the architecture and the
Claude and
Codex feasibility studies, plus the
Pi integration study. Pi's adaptive orchestration is
documented in Managed Pi runs.
- macOS and Ghostty
- Node.js 20 or later,
tmux,jq, andgit - At least one configured provider CLI: Claude Code, Codex CLI, and/or Pi
- A Slack workspace where you may create an app
With Homebrew, the common command-line dependencies are:
brew install node tmux jq gitChoose the provider set when installing. A flagless installation remains Claude-only for compatibility with pre-1.0 behavior.
# Claude Code only (the backward-compatible default)
curl -fsSL https://raw.githubusercontent.com/SergioTCG/SlackAgentBridge/main/install.sh | bash
# Codex only
curl -fsSL https://raw.githubusercontent.com/SergioTCG/SlackAgentBridge/main/install.sh | bash -s -- --provider codex
# Pi only
curl -fsSL https://raw.githubusercontent.com/SergioTCG/SlackAgentBridge/main/install.sh | bash -s -- --provider pi
# Claude + Codex (the historical meaning of "both")
curl -fsSL https://raw.githubusercontent.com/SergioTCG/SlackAgentBridge/main/install.sh | bash -s -- --provider both
# Claude + Codex + Pi
curl -fsSL https://raw.githubusercontent.com/SergioTCG/SlackAgentBridge/main/install.sh | bash -s -- --provider allThe installer opens a pre-filled Slack app page. Create the app, install it to
the workspace, then paste its bot token (xoxb-…) and an app-level Socket Mode
token (xapp-…, scope connections:write). It validates both tokens, installs
the selected hooks and launchers, and loads one local LaunchAgent. Run
/cc-claim in Slack to bind the bridge to your Slack user.
Fresh installations use ~/.slack-agent-bridge. An upgrade keeps an existing
~/.claudeslackproxy checkout, ~/.config/ccs state, Slack channels, and the
historical launchd label. The installer will not create a second daemon or move
a working installation underneath running sessions.
The compatibility installer stages Codex without restarting the live daemon:
./install-codex.shDuring a safe maintenance window, restart the bridge and launch sab-codex.
In that first Codex session, run /hooks and explicitly trust the user hook,
then exit and launch it again. Hook trust is hash-based and is never bypassed.
Stage the launcher and trusted extension without restarting the live daemon:
./install-pi.shPi needs no global hook or extension registration. sab-pi explicitly loads
the versioned bridge extension from this checkout on every bridged launch, so
ordinary pi sessions remain untouched. Restart the daemon only in a
controlled maintenance window after the release checks pass.
Apps upgrading to 1.5 must apply the canonical
Slack app manifest to the same app once to
register the /pi-* namespace and update the two older switch commands for an
explicit Pi target. Older apps also receive any previously missing commands.
This does not change tokens or OAuth scopes and never requires a second Slack
app. Applying it again only updates command registrations, metadata, and
descriptions.
Start a bridged terminal locally:
sab-cc [Claude flags]
sab-codex [Codex flags]
sab-pi [Pi flags]The pre-1.1 commands ccs and ccs-codex remain silent compatibility aliases
throughout the 1.x release line.
A private channel named from the repository, branch, and timestamp appears and you are invited. You may rename it; the bridge stores the immutable channel ID.
| In Slack | Effect |
|---|---|
| Any message in a session channel | Inject into that session; owner Pi prompts are adaptively routed by default |
| File or image attachment | Download locally and provide the path to the agent |
| “Create/export … and send it here” | Generate files and attach them back to this channel or thread |
/cc-new [folder] [flags] / /codex-new … / /pi-new … |
Start the selected provider |
/cc-model [model] / /codex-model … / /pi-model [provider/model] |
Show or change the provider model |
/cc-effort [level] / /codex-effort … / /pi-effort … |
Show or change reasoning/thinking effort |
/pi-run [plan] <goal> [budgets] |
Force a persistent planner → worker → independent-reviewer run; omit the goal for status |
/pi-run mode [auto|always|native] / /pi-run direct <prompt> |
Persist the Pi routing policy or bypass it once |
/cc-flags [flags] / /codex-flags … / /pi-flags … |
Show or replace allowlisted launch flags |
/cc-update / /codex-update / /pi-update |
Update the selected CLI and resume the session |
/cc-status / /codex-status / /pi-status |
Session details or a provider-filtered list |
/cc-stop / /codex-stop / /pi-stop |
Interrupt the current turn; Codex confirms idle or reports that the interrupt is still pending |
/cc-switch [codex|pi] [new] / /codex-switch [claude|pi] [new] / /pi-switch <claude|codex> [new] |
Hand this channel to another provider; new explicitly replaces a missing saved leg |
/cc-kill [id] / /codex-kill [id] / /pi-kill [id] |
End the process; keep its resumable channel |
/cc-help / /codex-help / /pi-help |
Show commands for that provider |
/cc-account [name] |
Bind a Claude session to a stored Claude subscription |
/cc-usage [days [n] | models | limits] |
Claude token, cost, model, and plan-limit usage via ccusage |
/codex-usage [days [n] | models] |
Codex session/project or aggregate token and cost usage via ccusage |
/pi-usage [days [n] | models] |
Pi session/project token, cost, model, and current-context usage from native events |
/cc-health / /cc-cleanup / /cc-claim |
Bridge-wide operations |
With no explicit Slack flags, /cc-new uses
--dangerously-skip-permissions and /codex-new uses Codex's canonical
dangerous flag. Explicit flags replace that default. Operator overrides are
available through CCS_NEW_FLAGS, CCS_CODEX_NEW_FLAGS, CCS_RESUME_FLAGS,
CCS_CODEX_RESUME_FLAGS, CCS_PI_NEW_FLAGS, and CCS_PI_RESUME_FLAGS. Pi
needs no dangerous-mode flag because its built-in tools are already
unrestricted; use SAB --safe for fail-closed Slack approval of each Pi tool
call. Pi's native --approve trusts project-local settings/extensions/skills
for that run and is not a tool-permission flag.
Claude's --chrome has no Codex or Pi equivalent. Codex --search controls
live web search, not a Chrome browser; Pi capabilities come from its selected
provider/model and configured extensions/tools. Browser automation requires a
separately configured integration.
Run the source provider's switch command in an active, idle session channel and
name the target: /cc-switch pi, /codex-switch pi, or
/pi-switch claude, for example. The historical bare /cc-switch and
/codex-switch forms still default to Codex and Claude respectively; Pi always
requires an explicit target. The command namespace identifies the source. The
bridge previews the target leg and its provider-native flags, then waits for
owner confirmation.
The source first produces a private, structured handoff. The bridge stores it
under ~/.config/ccs/handoffs with restrictive permissions, stops the source,
starts or resumes the target's own native conversation, and runs a read-only
readiness turn. The Slack channel changes hands only after that turn succeeds.
Owner messages arriving during the transaction are queued and receive fresh
artifact grants after commit; collaborators are blocked until it finishes. On
failure or daemon restart, the provisional target is discarded and the source
mapping is restored.
A provisional target does not receive its private validation prompt merely because tmux exists. Claude and Codex wait for their visible input surfaces; Pi waits for its authenticated native extension stream. The bridge reports any local trust gate in Slack and requires the target adapter to claim the native session before commit. The channel topic intentionally remains on the source provider throughout this private validation window.
Each channel may therefore have one active leg and up to two preserved standby
legs. Models, effort, launch flags, and Claude subscription choice stay with
their native provider and are never translated. A round trip resumes the
original native conversation. If a saved state record is missing, the bridge
refuses to replace it silently and asks for the source provider's explicit
-switch <target> new form.
Before the first switch, the bridge inspects only repository-root AGENTS.md
and CLAUDE.md; it never imports provider-global memory or MEMORY.md. When
they need alignment, an auxiliary provider returns bounded document sections
from a private neutral directory; the bridge constructs the constrained Git
patch itself. The owner reviews the complete proposal before it is applied as
ordinary uncommitted work. Applying is protected by file hashes, path and
symlink validation, git apply --check, and Codex's 32 KiB project instruction
budget. Progress is reported every minute. Generation defaults to a bounded
ten-minute ceiling; set CCS_INSTRUCTION_TIMEOUT_SECONDS in
~/.config/ccs/env to choose a value from 60 through 1800 seconds. Switching
without changing instructions remains available.
/cc-status, /codex-status, or /pi-status in the matching session channel
provides a user-picker for collaborators. Allowed teammates may send labelled
prompts to a live session, but cannot run slash commands, answer permission
prompts, or resurrect it. All other actions remain owner-only. The per-channel
allowlist is persisted across daemon restarts.
Ask naturally in a session channel, for example: “Export report.html as a PDF
and send it here.” The accepted prompt gives that agent turn a short-lived,
one-use capability to invoke sab-upload; the bot then attaches the generated
file to the same Slack channel or existing thread.
The destination is daemon-controlled. Files must resolve inside the session's workspace, be regular files, and total no more than 100 MiB across at most ten files. Path traversal and symlink escapes are rejected. The owner and explicitly allowed channel collaborators may request artifacts; messages from everyone else are ignored before an upload grant exists. If the daemon restarts before delivery, resend the Slack request to obtain a fresh grant.
ccs-account add tina
ccs-account listUse /cc-account tina in a Claude session or start one with
/cc-new <folder> --account tina. Tokens remain in
~/.config/ccs/accounts with mode 0600; the launcher resolves them through
the environment so bearer tokens never appear in process arguments.
The public name and canonical launchers changed without replacing the installed protocol:
/cc-*remains Claude and/codex-*remains Codex; 1.5 adds/pi-*without changing either established namespace or their bare-switch defaults.sab-cc,sab-codex, andsab-piare canonical;sab-uploadis their shared, grant-bound artifact helper;ccsandccs-codexremain aliases.CCS_*,~/.config/ccs, state records, and port8877are unchanged.- Existing
~/.claudeslackproxyinstallations remain in place. si.sergej.claudeslackproxyremains the sole LaunchAgent label.- Existing
#claude-code-bridgecontrol channels are reused. Fresh installs use#slack-agent-bridge. - The installer updates only the historical upstream Git remote; contributor forks are left untouched.
See the 1.0 migration guide before rolling a live
installation forward or back. Existing 1.0 installations can follow the
1.1 launcher migration to put sab-* on PATH.
For the new Codex usage command and its one-time manifest refresh, see the
1.2 migration guide.
Generated-file delivery requires no Slack app change; see the
1.3 migration guide.
Provider handoff requires the same-app command refresh described in the
1.4 migration guide.
Pi activation and the one-time /pi-* manifest refresh are covered in the
1.5 migration guide.
- Logs:
tail -f daemon.log - Config/state:
~/.config/ccs/(env,state.json, accounts, and private handoffs) - Restart:
launchctl kickstart -k gui/$(id -u)/si.sergej.claudeslackproxy - Disable self-update: set
CCS_AUTO_UPDATE=0in~/.config/ccs/env - Dockless Ghostty windows: set
CCS_GHOSTTY_HIDDEN=1 - Uninstall: boot out
~/Library/LaunchAgents/si.sergej.claudeslackproxy.plist, then remove the launchers and exact hook entries
The daemon self-updater fast-forwards only a clean checkout with no local
commits. It refreshes dependencies when package.json changes, waits for active
turns when possible, exits, and lets launchd restart it. Sessions continue in
tmux and are re-adopted after restart.
Read AGENTS.md before changing runtime behavior. The release and migration invariants are tested with:
npm ci
npm run audit
npm test
npm run checkMIT © 2026 Sergej Berišaj