Skip to content

CuiYuXi/CodeRelay

Repository files navigation

CodeRelay

English | 简体中文

CodeRelay is a local-first bridge for controlling Codex from messaging channels first, and over time from a mobile web console.

It is designed for workflows where Codex should keep running on your machine while approved actions, thread control, and status updates can be reached from external clients such as Discord, Telegram, or Feishu.

Status

CodeRelay is an early-stage open-source project.

The current focus is:

  • a shared bridge core for sessions, approvals, and event flow
  • Codex integration through codex app-server
  • IM-based control through channel adapters

The web control surface is a later expansion on top of the same runtime.

Core Principles

  • Local-first execution: Codex stays on the machine you control
  • Clear adapter boundaries: one bridge core, multiple channel integrations
  • Security by default: secrets and runtime state stay out of the repository
  • Thread-oriented workflows: conversations can be resumed and handed off across devices

Current Scope

Today the repository includes:

  • a shared bridge runtime for sessions, approvals, event publishing, and workspace bindings
  • a Codex adapter layer built around codex app-server
  • channel adapters for Discord, Telegram, and Feishu
  • an IM bridge server application that composes the runtime and adapters

Architecture

Telegram / Discord / Feishu / Web
              |
       Channel Adapters
              |
         Bridge Core
  - session registry
  - approval broker
  - event bus
  - workspace bindings
              |
        Codex Adapter
              |
      codex app-server

Repository Layout

apps/
  im-bridge-server/      # Bootstrap app for the IM bridge daemon
packages/
  shared/                # Shared types and contracts
  bridge-core/           # Session, approvals, event bus
  codex-adapter/         # Codex integration layer
  channel-telegram/      # Telegram adapter
  channel-discord/       # Discord adapter
  channel-feishu/        # Feishu adapter

Requirements

  • macOS, with the Codex desktop app installed
  • Node.js 20+
  • npm
  • a Discord server for testing
  • a Discord application with a bot user

Quick Start

  1. Clone the repository and install dependencies.
git clone <your-repo-url>
cd CodeRelay
npm install
  1. Create a local environment file.
cp apps/im-bridge-server/.env.example apps/im-bridge-server/.env.local
  1. Fill in the required values in apps/im-bridge-server/.env.local.

  2. Start the bridge server.

npm run dev
  1. In Discord, test the bot with:
  • /coderelay help
  • /coderelay ask prompt:hello
  • @CodexBot hello if DISCORD_MESSAGE_MODE is enabled
  • /coderelay-doctor

Discord Setup

Create the Discord application

In the Discord Developer Portal:

  1. Create a new application
  2. Open the Bot section
  3. Add a bot user
  4. Copy or regenerate the bot token
  5. If you want ordinary @CodexBot ... or reply-to-bot prompts, enable MESSAGE CONTENT INTENT

Use that value as:

DISCORD_BOT_TOKEN=your-bot-token

Invite the bot

Install the bot into your Discord server with these scopes:

  • bot
  • applications.commands

Recommended permissions:

  • View Channels
  • Send Messages
  • Use Slash Commands
  • Read Message History

Get the server and channel IDs

Enable Discord Developer Mode, then:

  • right-click the server and copy Server ID
  • right-click the channel and copy Channel ID

Use those values as:

DISCORD_GUILD_ID=your-server-id
DISCORD_ALLOWED_CHANNEL_IDS=your-channel-id

If you want to allow more than one channel:

DISCORD_ALLOWED_CHANNEL_IDS=channel-id-1,channel-id-2

Configuration

The quickest way to configure the project is to start from:

cp apps/im-bridge-server/.env.example apps/im-bridge-server/.env.local

For a Discord-first setup, these values are the important ones:

CODERELAY_BOT_NAME=CodeRelay
CODERELAY_PORT=4317
CODERELAY_CODEX_COMMAND=/Applications/Codex.app/Contents/Resources/codex
CODERELAY_DEFAULT_WORKSPACE=/absolute/path/to/your/workspace
CODERELAY_CODEX_MODE=app-server
CODERELAY_CODEX_APPROVAL_POLICY=on-request

TELEGRAM_ENABLED=false

DISCORD_ENABLED=true
DISCORD_BOT_TOKEN=your-bot-token
DISCORD_GUILD_ID=your-server-id
DISCORD_ALLOWED_CHANNEL_IDS=your-channel-id
DISCORD_MESSAGE_MODE=off
DISCORD_UI_LANGUAGE=en-US

Notes:

  • CODERELAY_DEFAULT_WORKSPACE must be an absolute path to the workspace you want Codex to operate in
  • on macOS, the default Codex binary path is usually /Applications/Codex.app/Contents/Resources/codex
  • on Windows, prefer pointing CODERELAY_CODEX_COMMAND to the runnable Codex CLI copy under %USERPROFILE%\\.codex\\.sandbox-bin\\codex.exe, for example C:\\Users\\<you>\\.codex\\.sandbox-bin\\codex.exe
  • on Windows, avoid C:\\Program Files\\WindowsApps\\...\\codex.exe if it fails with EPERM or Access is denied when CodeRelay tries to spawn codex app-server
  • for most local single-user setups, CODERELAY_CODEX_APPROVAL_POLICY=on-request is the best balance between safety and fewer interruptions
  • DISCORD_MESSAGE_MODE=off keeps Discord in slash-command-only mode
  • DISCORD_MESSAGE_MODE=mention allows prompts only when you explicitly mention @CodexBot
  • DISCORD_MESSAGE_MODE=mention-or-reply also allows prompts when you reply to a bot message in an allowed channel
  • set DISCORD_UI_LANGUAGE=zh-CN if you want Discord command descriptions and fixed system replies in Chinese
  • if port 4317 is already in use, choose another value such as 4318

Running The Server

Start the bridge with:

npm run dev

On a healthy startup, you should see logs indicating:

  • the IM bridge server is ready
  • Discord is enabled
  • Codex mode is app-server
  • persisted session bindings were restored, if any were found
  • the bot logged in successfully
  • slash commands were registered for your guild

Startup Notes

  • CodeRelay now binds the local HTTP port before starting channel adapters. If the configured port is already in use, the process exits before a second Discord bot instance can start handling interactions.
  • Discord login and slash command registration automatically retry a few transient network failures such as ECONNRESET.
  • The bridge runtime keeps lightweight per-session progress metadata so future clients can surface recent agent output and approval-wait state more cleanly.

Troubleshooting

If Discord shows Unknown interaction or Interaction has already been acknowledged, the most common cause is that more than one local CodeRelay process is connected to the same bot at the same time.

Recommended checks:

  • keep only one local CodeRelay instance running per Discord bot
  • if the configured port is already in use, stop the old process before starting a new one
  • on macOS, you can inspect the listening process with lsof -nP -iTCP:4318 -sTCP:LISTEN and stop it with kill <PID>

Current Discord Commands

  • /coderelay help
  • /coderelay ask prompt:<text> [attachment]
  • @CodexBot <text> when DISCORD_MESSAGE_MODE is enabled
  • /coderelay continue
  • /coderelay current
  • /coderelay handoff
  • /coderelay health
  • /coderelay-doctor
  • /coderelay approvals
  • /coderelay approve [id]
  • /coderelay deny [id]
  • /coderelay progress
  • /coderelay policy
  • /coderelay set-policy policy:<mode>
  • /coderelay projects [limit]
  • /coderelay recent [limit]
  • /coderelay threads [limit]
  • /coderelay new [title]
  • /coderelay rename title:<text>
  • /coderelay resume id:<query>
  • /coderelay hide id:<query>
  • /coderelay archive id:<query>
  • /coderelay unhide id:<query>
  • /coderelay pin target:<query>
  • /coderelay unpin target:<query>
  • /coderelay use-project query:<name-or-path>
  • /coderelay interrupt

Thread Behavior

CodeRelay does not create a new thread for every Discord message.

The current behavior is:

  • one Discord session is keyed by channelId + userId
  • repeated /coderelay ask calls continue on the same current thread
  • a new thread is created only when:
    • the session has not talked to Codex before
    • /coderelay new is used
    • /coderelay resume is used to switch to another thread

The current session-to-thread binding is persisted under .coderelay/session-bindings.json in the configured workspace, so the same Discord session can continue on the same thread after a server restart. Startup logs now report how many bindings were restored from that file. If a restored binding points to a thread that no longer exists in the local Codex app-server, CodeRelay now reports that mismatch explicitly instead of silently creating a replacement thread.

Use /coderelay recent to view recent user and Codex messages from the current thread directly in Discord.

Use /coderelay health to check the Discord channel, current workspace, current thread, message mode, approval policy, pending approvals, and whether Codex thread listing is reachable.

Use /coderelay-doctor for a deeper diagnosis view that adds mention/reply intake readiness, current channel permission checks, Codex executable discovery, app-server reachability, default workspace status, bridge-side approval smoothing mode, the current session binding state, binding reachability on this machine, restore source, last restore time, and the latest pending approval summary.

Use /coderelay progress to view the current thread status, active turn start time, last tracked bridge event, latest pending approval summary, last user message, last agent output time, latest tracked agent output snippet, and approval wait state.

Use /coderelay resume id:<query> to resume a thread by list index, thread ID or prefix, title keyword, or workspace keyword. Discord also offers autocomplete suggestions while you type the id field.

Use /coderelay hide id:<query> or /coderelay archive id:<query> to remove old threads from /coderelay threads and /coderelay resume candidates. Use /coderelay unhide id:<query> to show a hidden thread again.

Use /coderelay pin target:<query> to pin a frequently used thread or project. Use /coderelay unpin target:<query> to remove that preference. Thread and project preferences are stored locally under .coderelay/thread-preferences.json.

If DISCORD_MESSAGE_MODE=mention, CodeRelay also accepts prompts from ordinary channel messages that mention @CodexBot. If DISCORD_MESSAGE_MODE=mention-or-reply, replying to a bot message in an allowed channel also sends a prompt. Other channel messages are ignored. In these ordinary-message flows, Discord attachments are downloaded into .coderelay/inbox/... inside the active workspace before the prompt is forwarded. Images are passed to Codex as local image inputs, while ordinary files are passed as local file paths in the prompt text.

Use /coderelay continue after interruptions or long pauses to ask Codex to report the current status and continue the current thread. Use /coderelay rename title:<text> to rename the current thread for easier thread lists and resume searches.

Use /coderelay approvals to list pending approvals. If a button is no longer convenient, use /coderelay approve [id] or /coderelay deny [id]. When id is omitted, CodeRelay applies the latest pending request for the current Discord session. If you do provide id, it can be an approval list index or approval ID prefix.

When CODERELAY_CODEX_APPROVAL_POLICY=on-request, the bridge now auto-approves a conservative set of low-risk read-only actions such as common rg, find, git status, git diff, npm test, and local read permission requests. More sensitive commands, file writes, network access, and broad permission escalations still require approval.

Recent thread progress is now persisted locally under .coderelay/session-progress.json, so /coderelay progress, /coderelay health, and /coderelay continue recover more context after a restart. If no cached progress exists yet, CodeRelay falls back to recent thread history to rebuild the latest user/assistant summary.

Long Discord answers are now split into multiple messages instead of being hard-truncated, and CodeRelay tries to keep fenced code blocks valid across chunk boundaries.

Use /coderelay projects to list project/workspace paths discovered from recent threads, and /coderelay use-project to switch the current Discord session to another project. Switching projects clears the current thread binding for that session so the next /coderelay ask starts in the selected workspace.

Use /coderelay policy to inspect the current approval mode and /coderelay set-policy to reduce or increase approval prompts at runtime. The runtime change applies to future turns, while the env value remains the startup default.

Security

CodeRelay is intended to be run as a local service, not as a shared public relay.

Repository rules:

  • keep secrets in local env files only
  • commit example configuration only
  • do not commit tokens, logs, pairing state, or machine-specific runtime data

License

MIT. See LICENSE.

About

No description, website, or topics provided.

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors