DEV Community

Cover image for I Built a Slack Bridge for Local Codex Sessions So I Could Leave My Desk
Duncan Brown
Duncan Brown

Posted on

I Built a Slack Bridge for Local Codex Sessions So I Could Leave My Desk

Coding agents like Codex have certainly made my life easier, and - if I'm being perfectly honest - they border on being addictive.

So what do you do when you're in the middle of orchestrating some long-running agent sessions and you have to run an errand?

Why, you build a small bridge between local Codex CLI sessions and Slack, of course.

I wanted to be able to step away from my desk — go for a walk, run an errand, or hit the gym — without losing momentum on a Codex session running on my laptop.

I also don't make a lot of use of cloud-based Codex sessions as I don't find them a terribly good fit for my workflows.

Those constraints shaped everything that followed.


What the Bridge Actually Is

The “Codex Slack Bridge” is a thin layer that turns Slack into an additional interface over local Codex sessions.

Codex Cloud already offers the ability to manage cloud-based Codex sessions, but the ability to manage local Codex sessions while mobile was especially compelling to me.

With the bridge, the agents still run locally on my machine, exactly as they would in a terminal.

What the bridge adds is:

  • a way to start and manage sessions from Slack
  • a way to receive final outputs remotely
  • a way to continue a session from a Slack thread

In practice, that means I can:

  • start a new session with /codex new
  • list and attach to existing sessions
  • resume a session from Slack
  • receive the final output of a turn without watching the terminal

Each session is mapped to a single Slack thread, which becomes its control surface.

The project is available here.


Slack as an Additional UI

Slack serves as a control and notification layer, complimenting the terminal.

The terminal remains the best place for:

  • live execution
  • intermediate reasoning
  • detailed tool activity
  • approvals during a turn

Slack becomes useful for:

  • initiating work
  • receiving final results
  • continuing a conversation later
  • checking in without being at the machine

That separation keeps the system understandable.


One Thread per Session

Each Codex session is represented by a single Slack thread.

This was a deliberate choice.

Alternatives like:

  • one shared channel
  • multiple threads per session
  • or stateless commands

all made it harder to track what was happening.

With a single thread:

  • prompts
  • responses
  • attachments
  • and state

stay aligned.

Even repeated “attach” actions are idempotent — they reuse the same thread instead of creating competing control surfaces.


Final Output Only

One of the first decisions I made was to send only the final output of each turn to Slack.

Not:

  • intermediate reasoning
  • tool-by-tool execution
  • or incremental progress

Slack is not a great interface for high-volume output.

By sending only the final result:

  • threads stay readable
  • signal remains high
  • the terminal remains the source of detailed execution

This constraint simplifies the UX considerably.


Attach vs Resume

The bridge distinguishes between two concepts:

  • Attach: bind Slack to an existing session (including one already running in a terminal)
  • Resume: start a new turn in an existing session from Slack

If a session is already running in the terminal, Slack can attach to it and receive the final output when the turn completes.

But that turn is still “owned” by the terminal until it finishes.

After that, Slack can take over subsequent interactions.


Mirroring In-Flight Work

To support this, the bridge watches Codex rollout/session files locally.

When a task completes, it extracts the final output and sends it to Slack.

If I attach to a session after a turn has already started, the bridge scans the tail of the rollout file so it can usually include the original prompt alongside the final result.

It’s not perfect, but it’s good enough to preserve context most of the time.

Approval prompts during a terminal-owned turn are handled differently.

Slack can notify me that something requires approval, but the actual approval still happens in the terminal.

Again, that separation keeps the system predictable.


Small Constraints That Matter

A few constraints make the bridge more usable:

  • It’s restricted to a single authorized Slack user
  • It only operates in configured private channels or DMs
  • It’s disabled by default and must be explicitly enabled
  • enable/disable state persists across restarts

None of these are complex, but they prevent accidental usage and keep control local.


Durability and Reality

The bridge can run under macOS launchd, which keeps it alive across restarts.

But it doesn’t change the underlying reality:

  • the laptop must remain awake
  • network connectivity still matters
  • long-running sessions are bounded by the machine

I experimented with caffeinate to prevent sleep, which works well for active sessions, but it’s an explicit tradeoff — especially on battery.


So Why Not Use a Platform?

I considered using something like OpenClaw.

In the end, I decided not to.

Not because it’s a bad tool, but for this use case:

  • I wanted direct control over local sessions
  • I needed tight integration with the Codex CLI and rollout files
  • I wanted minimal abstractions and moving parts
  • and I wanted the Slack interaction model to stay simple

A purpose-built bridge ended up being easier to reason about.


Slack API Realities

Some of the design choices were shaped by Slack itself:

  • Slash commands don’t work inside threads
  • So detaching required a button and plain text commands like detach
  • Threads turned out to be a natural fit for session-scoped interaction
  • Ephemeral responses are useful for status messages and errors

These constraints helped shape the interface.


What This Is (and Isn’t)

This bridge isn’t an agent platform.

It doesn’t orchestrate workflows or automate entire development pipelines.

It’s a thin layer that:

  • keeps local execution local
  • adds a remote control surface
  • and preserves continuity across contexts

That’s honestly all I needed.


What Became Clear

One of the ancillary benefits in creating and using the bridge is what it exposes.

When you interact with an agent through Slack, you lose a lot of the implicit context you usually rely on in a terminal. You don’t see everything that led up to a response. You don’t have the same sense of what the system is “thinking.”

That makes small gaps more obvious:

  • prompts that weren’t as clear as they seemed
  • assumptions that were never stated
  • differences in how people describe the same thing

The bridge makes those issues easier to see.


What I’d Do Next

There’s plenty of room to extend this:

  • better multi-user support
  • richer Slack UI via Block Kit
  • improved approval handling
  • stronger observability and logging
  • support for other agent CLIs

But for now, the core goal is met:

I can step away from my desk, and the work doesn’t stop.

Top comments (0)