Files
openwork/apps/opencode-router

opencode-router

Simple Slack + Telegram bridge + directory router for a running opencode server.

Runtime requirement: Bun 1.3+ (bun --version).

Install + Run

One-command install (recommended):

curl -fsSL https://raw.githubusercontent.com/different-ai/openwork/dev/apps/opencode-router/install.sh | bash

Install from npm:

npm install -g opencode-router

Quick run without global install:

npx --yes opencode-router --help

Then configure identities and start.

  1. One-command setup (installs deps, builds, creates .env if missing):
pnpm -C apps/opencode-router setup
  1. (Optional) Fill in apps/opencode-router/.env (see .env.example).

Required:

  • OPENCODE_URL
  • OPENCODE_DIRECTORY

Recommended:

  • OPENCODE_SERVER_USERNAME
  • OPENCODE_SERVER_PASSWORD
  1. Run the router:
opencode-router start

Telegram

Telegram support is configured via identities. You can either:

  • Use env vars for a single bot: TELEGRAM_BOT_TOKEN=...
    • Or add multiple bots to the config file (opencode-router.json) using the CLI:
opencode-router telegram add <token> --id default
opencode-router telegram list

Important for direct sends and bindings:

  • Telegram targets must use numeric chat_id values.
  • @username values are not valid direct peerId targets for router sends.
  • If a user has not started a chat with the bot yet, Telegram may return chat not found.
  • Private Telegram identities can require first-chat pairing with /pair <code> before commands are accepted.

Slack (Socket Mode)

Slack support uses Socket Mode and replies in threads when @mentioned in channels.

  1. Create a Slack app.
  2. Enable Socket Mode and generate an app token (xapp-...).
  3. Add bot token scopes:
    • chat:write
    • app_mentions:read
    • im:history
    • files:read
    • files:write
  4. Subscribe to events (bot events):
    • app_mention
    • message.im
  5. Set env vars (or save via opencode-router slack add ...):
    • SLACK_BOT_TOKEN=xoxb-...
    • SLACK_APP_TOKEN=xapp-...
    • SLACK_ENABLED=true

To add multiple Slack apps:

opencode-router slack add <xoxb> <xapp> --id default
opencode-router slack list

Identity-Scoped Routing

The router routes messages based on (channel, identityId, peerId) -> directory bindings.

opencode-router bindings set --channel telegram --identity default --peer <chatId> --dir /path/to/workdir
opencode-router bindings list

Health Server (Local HTTP)

The router can expose a small local HTTP server for health/config and simple message dispatch.

  • OPENCODE_ROUTER_HEALTH_PORT controls the port (OpenWork defaults to a random free port when using openwork).
  • PORT is also accepted as a convenience if the above are unset.
  • OPENCODE_ROUTER_HEALTH_HOST controls bind host (default: 127.0.0.1).

Send a message to all peers bound to a directory:

curl -sS "http://127.0.0.1:${OPENCODE_ROUTER_HEALTH_PORT:-3005}/send" \
  -H 'Content-Type: application/json' \
  -d '{"channel":"telegram","directory":"/path/to/workdir","text":"hello"}'

Send text + media in one request:

curl -sS "http://127.0.0.1:${OPENCODE_ROUTER_HEALTH_PORT:-3005}/send" \
  -H 'Content-Type: application/json' \
  -d '{
    "channel":"slack",
    "peerId":"D12345678",
    "text":"Here is the export",
    "parts":[
      {"type":"file","filePath":"./artifacts/report.pdf"},
      {"type":"image","filePath":"./artifacts/plot.png","caption":"latest trend"}
    ]
  }'

Supported media part types:

  • image
  • audio
  • file

Each media part accepts:

  • filePath (absolute path, or relative to the send directory/workspace root)
  • optional caption
  • optional filename
  • optional mimeType

Commands

opencode-router start
opencode-router status

opencode-router telegram list
opencode-router telegram add <token> --id default

opencode-router slack list
opencode-router slack add <xoxb> <xapp> --id default

opencode-router bindings list
opencode-router bindings set --channel telegram --identity default --peer <chatId> --dir /path/to/workdir

opencode-router send --channel telegram --identity default --to <chatId> --message "hello"
opencode-router send --channel telegram --identity default --to <chatId> --image ./plot.png --caption "plot"
opencode-router send --channel slack --identity default --to D123 --file ./report.pdf

Defaults

  • SQLite at ~/.openwork/opencode-router/opencode-router.db unless overridden.
  • Config stored at ~/.openwork/opencode-router/opencode-router.json (created by opencode-router or pnpm -C apps/opencode-router setup).
  • Group chats are disabled unless GROUPS_ENABLED=true.

Tests

test:smoke requires a running opencode server (default: http://127.0.0.1:4096).

opencode serve --port 4096 --hostname 127.0.0.1
pnpm -C apps/opencode-router test:smoke

Other test suites:

pnpm -C apps/opencode-router test:unit
pnpm -C apps/opencode-router test:cli
pnpm -C apps/opencode-router test:npx