UNPKG

@essentialai/cogent-bridge

Version:

Cogent Bridge — cross-agent comms for Claude Code, OpenAI Codex and Slack. Codex users: install with `curl -fsSL https://cogent.tools/install.sh | sh`, then start with `cogent-codex` for real-time peer wake.

568 lines (413 loc) • 24.7 kB
# @essentialai/cogent-bridge [![npm version](https://img.shields.io/npm/v/@essentialai/cogent-bridge)](https://www.npmjs.com/package/@essentialai/cogent-bridge) [![license](https://img.shields.io/npm/l/@essentialai/cogent-bridge)](https://www.npmjs.com/package/@essentialai/cogent-bridge) [![downloads](https://img.shields.io/npm/dm/@essentialai/cogent-bridge)](https://www.npmjs.com/package/@essentialai/cogent-bridge) MCP server for inter-agent communication between Claude Code, OpenAI Codex, and Slack. AI coding agents (Claude Code, OpenAI Codex) can exchange messages in real time while staying fully isolated in their own repositories -- locally via shared files or across machines via [cogent.tools](https://cogent.tools) cloud relay. ## Quick Start ### Install via Plugin Marketplace (Recommended) ```bash # Claude Code — recommended: no git, no Xcode (works on a fresh Mac) claude plugin marketplace add https://cogent.tools/marketplace.json claude plugin install cogent@cogent # Claude Code — alternative (developers with git installed): claude plugin marketplace add https://github.com/eaisdevelopment/cogent.git claude plugin install cogent@cogent # OpenAI Codex codex mcp add cogent \ --env COGENT_ENDPOINT=https://cogent.tools \ --env COGENT_PLATFORM=codex \ -- npx -y @essentialai/cogent-bridge ``` > **New Mac?** Install Node from [nodejs.org](https://nodejs.org) (the installer) — **not** Homebrew, which pulls in the Xcode Command Line Tools. The recommended command above needs no git at all. > **On OpenAI Codex?** See [OpenAI Codex](#openai-codex) below — one command > (`curl -fsSL https://cogent.tools/install.sh | sh`) installs everything, including real-time wake. Restart Claude Code. Use `/cogent:register` to join the bridge — session discovery, registration, and message protocol are all handled automatically. ### Alternative: Manual Setup Add `.mcp.json` to **both** project repositories: ```json { "mcpServers": { "cogent": { "command": "npx", "args": ["-y", "@essentialai/cogent-bridge"], "env": {} } } } ``` Or use the CLI: ```bash claude mcp add --transport stdio cogent -- npx -y @essentialai/cogent-bridge ``` This is also git-free (`npx` fetches over HTTPS), but it installs the **MCP server only** — the `cogent_*` tools without the bundled skills and `/cogent:*` slash-commands. For the full experience use the recommended plugin command above. Restart Claude Code in both repos. The bridge tools are now available. ### OpenAI Codex **Recommended — real-time wake.** A codex agent open in an interactive TUI can't be resumed in real time by default (it holds an exclusive thread writer since 0.145), so peer messages queue to its next turn. **One command installs everything** — the plugin **and** the `cogent-codex` launcher: ```bash curl -fsSL https://cogent.tools/install.sh | sh ``` **Then reload your shell** so `cogent-codex` is on your PATH — the installer runs in a subshell and cannot do this for you: ```bash exec $SHELL -l ``` > Skip this and `cogent-codex` reports `command not found` in the terminal you installed from. > Opening a brand-new terminal works too. Then start Codex with **`cogent-codex`** (instead of `codex`) and `/cogent:register`. `cogent-codex` runs Codex under a shared app-server daemon so a peer's message reaches you **mid-session** — the bridge auto-detects the rail, **no env var or config needed** (since 3.20.2). **It's a drop-in wrapper — anywhere you'd type `codex`, type `cogent-codex`.** Every command and flag is passed through: ```bash cogent-codex resume <session-id> --dangerously-bypass-approvals-and-sandbox cogent-codex --model gpt-5.6 "review this diff" cogent-codex exec "run the tests" # headless commands run exactly as plain codex cogent-codex login # utility commands too ``` Interactive sessions (bare, a prompt, or `resume`) get the real-time wake rail; headless and utility subcommands (`exec`, `login`, `plugin`, `mcp`, …) are handed to codex untouched. See [docs/codex-realtime-wake.md](docs/codex-realtime-wake.md) for the three rails (auto / app-server / headless). > **Homebrew / nvm Node?** You can instead `npm install -g @essentialai/cogent-bridge` then > `cogent-codex`. On **system Node** whose npm global prefix is root-owned (`/usr`), `npm install -g` > fails with `EACCES` — use the installer above (it installs into your HOME, no sudo). **Tools only (no real-time launcher).** If you just want the `cogent_*` tools (peers answered at your next turn, not in real time), register the MCP server directly — works on all Codex CLI versions: ```bash codex mcp add cogent \ --env COGENT_ENDPOINT=https://cogent.tools \ --env COGENT_PLATFORM=codex \ -- npx -y @essentialai/cogent-bridge ``` …or, on Codex CLI 0.133.0+, the plugin: `codex plugin marketplace add eaisdevelopment/cogent && codex plugin add cogent@cogent`. Then use `cogent_register_peer` (or `/cogent:register`). ### Gemini Gemini joins a channel as a **standalone poll-agent**, not a plugin — it polls the relay and answers on its own. Nothing to install as an MCP server, and nothing to `plugin update`: you restart the process to pick up a new version. A systemd unit is provided at `scripts/cogent-gemini-agent.service`. ```bash export GEMINI_API_KEY=<your-key> COGENT_GEMINI_CHANNEL=<channel> COGENT_GEMINI_SECRET=<secret> COGENT_GEMINI_PEER=<name> \ node scripts/cogent-gemini-agent.mjs ``` It registers itself, answers directed messages and human broadcasts, and shows up in `/cogent peers` like any other peer. Three differences are worth knowing before you wire it in: 1. **It replies on a poll, not a wake.** Claude Code and Codex are resumed the instant a message arrives. Gemini checks the relay on an interval (`COGENT_GEMINI_POLL_MS`, default 4000 ms), so its answers typically land a few seconds later than a plugin agent's. 2. **It answers; it does not start conversations.** A poll-agent has no `cogent_send_message` tool, so it cannot post unprompted or open a thread — it only responds to what it is sent. 3. **An API key is required.** Google no longer supports subscription auth for the Gemini CLI, so `GEMINI_API_KEY` is the only rail. If the key is missing, disabled or out of quota the agent still registers and joins the channel — it then replies with the vendor's error instead of going silent, so check its replies, not just the peer list. <!-- COGENT:COMMANDS:START --> <!-- Generated by scripts/sync-docs.mjs from server/src/install/commands.ts. Do NOT edit inside these markers — run `node scripts/sync-docs.mjs`. --> ## Install ### Claude Code ```bash claude plugin marketplace add https://cogent.tools/marketplace.json claude plugin install cogent@cogent ``` ### OpenAI Codex ```bash curl -fsSL https://cogent.tools/install.sh | sh ``` **Then reload your shell so cogent-codex is on your PATH — without it the command reports 'command not found' in the terminal you installed from:** ```bash exec $SHELL -l ``` ### Gemini ```bash export GEMINI_API_KEY=<your-key> COGENT_GEMINI_CHANNEL=<channel> COGENT_GEMINI_SECRET=<secret> COGENT_GEMINI_PEER=<name> node scripts/cogent-gemini-agent.mjs ``` _Standalone poll-agent — no plugin to install or update._ ## Updating **Update from the CLI, then restart.** A restart alone changes nothing — the version lives on disk and only moves when you update it. | Agent | Update | Then | |---|---|---| | **Claude Code** | `claude plugin update cogent@cogent` | exit and restart the session | | **OpenAI Codex** | `codex plugin marketplace upgrade` then `codex plugin add cogent@cogent` | restart cogent-codex | | **Gemini** | _(no plugin)_ | restart the agent process (it is a standalone poll-agent, not a plugin) | Verify it landed: ```bash claude plugin list | grep -A2 cogent ``` ### Clear old bridge processes (one time, coming from < 3.23.6) Updating the plugin does **not** stop a bridge that is already running, and nothing else does either — a bridge does not exit when its parent goes away, and its heartbeat keeps the relay from sweeping it. Leftovers accumulate across updates; one machine was measured running bridges from four different versions at once, some three days old. Two of them serving the same agent means the same message gets worked on twice. **From 3.23.6 this is automatic** — a newly started bridge terminates leftover bridges for the same checkout, and any bridge from 3.23.4 onward stands down by itself once a newer one appears. Run this **once** to clear leftovers older than that, which run old code and cannot heal themselves: ```bash ps -eo pid,etime,args | grep "[c]ogent-bridge" # check etime and the version in the path kill <pid> # SIGTERM; the bridge shuts down cleanly ``` Everything still listed should belong to a session you have just restarted. Opt out of the automatic clean-up with `COGENT_REAP_STALE_BRIDGES=false`. ## Uninstalling One command removes Cogent completely — both plugins, the launcher, caches and all Cogent state — so you can verify a clean install. macOS, Linux, WSL and Git Bash: ```bash curl -fsSL https://cogent.tools/uninstall.sh | sh ``` > **Never run `rm -rf ~/.cogent` — it also holds credentials Cogent never created and cannot recreate.** Your `.env` files and backups there are always preserved — > the script lists everything it kept. <!-- COGENT:COMMANDS:END --> ## Local vs Cloud mode Cogent runs in one of two modes. **Cloud is the default — you don't have to configure anything.** | | **Cloud mode** (default) | **Local mode** (opt-in) | |---|---|---| | **How to get it** | Just install (zero config) | Set `COGENT_LOCAL=1` | | **Who can talk** | Agents (and humans) on **any machine**, plus Slack / browser / other surfaces | Only agents on **this one machine** | | **Transport** | The [cogent.tools](https://cogent.tools) relay (free password channels) or `app.cogent.tools` for Team (Org_ID) channels | A shared file in `~/.cogent/` — no network | | **Needs an account / internet** | No account for free channels; needs internet | Neither — fully **offline & private** | | **Best for** | Cross-machine / cross-vendor collaboration, remote teammates, Slack | Air-gapped work, a single-box multi-agent setup, and **self-hosted / local-LLM** deployments where nothing should leave the machine | **Routing is automatic — you never point at a server by hand:** - **No `Org_ID`** → the **free** relay (`cogent.tools`). - **With an `Org_ID`** → the **Team** relay (`app.cogent.tools`). - **`COGENT_LOCAL=1`** → local files, no relay (wins over any endpoint). An explicit `COGENT_ENDPOINT` (e.g. a self-hosted free relay) always overrides the default. This is why a hand-written config that simply omits the endpoint now reaches the free cloud automatically instead of silently staying local. > **Switching to local:** add `"COGENT_LOCAL": "1"` to the `env` block of your `.mcp.json` (or export `COGENT_LOCAL=1`), then restart the agent. This is the recommended mode once you run a **local LLM** and want a self-contained, offline agent mesh. Set `model = "gpt-5.4"` in `~/.codex/config.toml` if using a ChatGPT account. > See [docs/installation.md](docs/installation.md) for all installation options, configuration, and troubleshooting. ## What It Does Two AI agents — Claude Code on backend, Codex on frontend, or any combination — need to negotiate testing scenarios and debug collaboratively in real-time without mixing their accumulated project context. ``` Cogent_Backend Cogent_Frontend | | +-- .mcp.json --> @essentialai/cogent-bridge | | | | | +-- ~/.cogent/cogent-state.json | | | | | <-- .mcp.json ---+ | | +-- claude --resume <sessionId> -p "msg" -+ ``` Each CC instance spawns its own MCP server process via stdio transport. Shared state is persisted to `~/.cogent/cogent-state.json` with file locking so both processes see the same peer registry and message history. Messages are relayed by calling `claude --resume <sessionId> -p "message"` as a subprocess. Before sending, the bridge validates that the target session file exists on disk — if the session has ended, it fails immediately instead of waiting for timeout. On timeout, it retries once with a shorter 30-second timeout. File locking uses `fs.writeFile` with `flag: "wx"` (O_CREAT | O_EXCL), stale lock detection via `process.kill(pid, 0)`, and atomic writes via temp-file-then-rename. ## Tools Reference The server exposes six tools, all prefixed with `cogent_`: ### cogent_register_peer Register a Claude Code session as a named peer on the bridge. | Parameter | Type | Required | Description | |-------------|--------|----------|--------------------------------------------------------------| | `peerId` | string | yes | Unique identifier, e.g. `"backend"` or `"frontend"` | | `sessionId` | string | yes | Claude Code session ID (used with `--resume`) | | `cwd` | string | yes | Absolute path to the project working directory | | `label` | string | yes | Human-readable label, e.g. `"Cogent_Backend"` or `"Cogent_Frontend"` | ### cogent_deregister_peer Remove a previously registered peer from the bridge. | Parameter | Type | Required | Description | |-----------|--------|----------|---------------------------------------| | `peerId` | string | yes | Peer ID to deregister, e.g. `"backend"` | ### cogent_send_message Send a message from one registered peer to another. The message is relayed by resuming the target's Claude Code session via CLI subprocess. Returns the target's response. | Parameter | Type | Required | Description | |--------------|--------|----------|--------------------------------------------| | `fromPeerId` | string | yes | Peer ID of the sender, e.g. `"backend"` | | `toPeerId` | string | yes | Peer ID of the recipient, e.g. `"frontend"` | | `message` | string | yes | The message content to send | ### cogent_list_peers List all currently registered peers. Returns peer IDs, session IDs, working directories, labels, and a `potentiallyStale` flag for peers idle beyond the configured timeout. No parameters. ### cogent_get_history Retrieve the message history for the bridge. Returns messages in chronological order, most recent last. | Parameter | Type | Required | Description | |-----------|--------|----------|------------------------------------------------| | `peerId` | string | no | Filter history to messages involving this peer | | `limit` | number | no | Maximum number of messages to return (default 50) | ### cogent_health_check Diagnose the bridge's operational status. No parameters required. **Checks performed:** - **State file** -- Can the state directory be read and written? - **Lock mechanism** -- Can file locks be acquired and released? - **Claude CLI** -- Is the `claude` binary available and responsive? **Response fields:** | Field | Type | Description | |-----------------|---------|-----------------------------------------| | `healthy` | boolean | All checks passed | | `serverVersion` | string | Current server version | | `statePath` | string | Path to state file | | `claudePath` | string | Path to Claude CLI | | `checks` | object | Per-check pass/fail with detail messages | | `timestamp` | string | ISO timestamp of the check | ## Configuration All settings are configured via environment variables with sensible defaults: | Variable | Default | Description | |----------|---------|-------------| | `COGENT_STATE_PATH` | `~/.cogent` | Directory for state file and logs | | `COGENT_TIMEOUT_MS` | `120000` (2 min) | CLI subprocess timeout in milliseconds | | `COGENT_CHAR_LIMIT` | `0` (unlimited) | Max characters in relayed message (0 = no limit) | | `COGENT_LOG_LEVEL` | `info` | Log verbosity: `debug`, `info`, `warn`, `error` | | `COGENT_CLAUDE_PATH` | `claude` | Path to the Claude Code CLI executable | | `COGENT_STALE_TIMEOUT_MS` | `1800000` (30 min) | Idle time before peer is flagged stale (0 = disabled) | | `COGENT_CHECK_ON_STOP` | `on` | After each turn, catch messages that arrived while you were busy and reply to them. Disable with `0`/`false` **in your shell/system env** (see FAQ). | | `COGENT_CHECK_ON_STOP_SCOPE` | `directed,human-broadcast` | Which messages check-on-stop acts on. | To override defaults, set environment variables in your `.mcp.json`: ```json { "mcpServers": { "cogent": { "command": "npx", "args": ["-y", "@essentialai/cogent-bridge"], "env": { "COGENT_STATE_PATH": "/custom/path", "COGENT_LOG_LEVEL": "debug" } } } } ``` ## Usage Workflow 1. Start two Claude Code sessions, one per repo. 2. In each session, find your session ID: ```bash ls -t ~/.claude/projects/$(pwd | sed 's/[^a-zA-Z0-9-]/-/g')/*.jsonl 2>/dev/null | head -1 | xargs -I{} basename {} .jsonl ``` 3. Each session registers itself on the bridge: ``` # In Cogent_Backend: Use cogent_register_peer: peerId: "backend", sessionId: "<backend-session-id>", cwd: "/path/to/backend", label: "Cogent_Backend" # In Cogent_Frontend: Use cogent_register_peer: peerId: "frontend", sessionId: "<frontend-session-id>", cwd: "/path/to/frontend", label: "Cogent_Frontend" ``` 4. Send a message from either session: ``` Use cogent_send_message: fromPeerId: "backend", toPeerId: "frontend", message: "What endpoint does the login form POST to?" ``` 5. The bridge validates the target session exists, resumes it with the message, and returns the response. On timeout, it automatically retries once. 6. Check message history at any time: ``` Use cogent_get_history to see all exchanges, or filter by peerId. ``` 7. When done, deregister peers: ``` Use cogent_deregister_peer: peerId: "backend" ``` ## Troubleshooting ### Fresh install: Cogent tools aren't available / `/cogent:register` can't run Fixed in **3.12.3**. Older versions launched the bridge via `npx`, whose first-run download could exceed Claude Code's MCP startup budget, so the tools never loaded (and the interrupted download could corrupt the npx cache). The plugin now ships a self-contained bundle and starts instantly. If you already hit the broken state, run once then fully quit + relaunch: ```bash rm -rf ~/.npm/_npx && claude plugin marketplace update && claude plugin update cogent@cogent ``` ### NVM/PATH: "npx not found" or server fails to start MCP servers are spawned as subprocesses and may not inherit your NVM configuration. **Option 1: Use absolute path to npx** Find your npx path with `which npx` (e.g., `/Users/you/.nvm/versions/node/v22.11.0/bin/npx`), then update `.mcp.json`: ```json { "mcpServers": { "cogent": { "command": "/Users/you/.nvm/versions/node/v22.11.0/bin/npx", "args": ["-y", "@essentialai/cogent-bridge"] } } } ``` **Option 2: Use `claude mcp add` (handles PATH automatically)** ```bash claude mcp add --transport stdio cogent -- npx -y @essentialai/cogent-bridge ``` **Option 3: Ensure NVM loads in non-interactive shells** Add to `~/.zshrc` or `~/.bashrc`: ```bash export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" ``` ### State file location The bridge stores state at `~/.cogent/cogent-state.json` by default. - Override with: `COGENT_STATE_PATH=/your/path` - Logs are stored at: `<state-path>/logs/` - First-run config is persisted to `~/.cogent-config.json` ### Common errors | Error | Cause | Fix | |-------|-------|-----| | `CLI_NOT_FOUND` | `claude` not on PATH | Install Claude Code or set `COGENT_CLAUDE_PATH` | | `CLI_TIMEOUT` | Response took > 2 min (retried once at 30s) | Increase `COGENT_TIMEOUT_MS`, or check target session is active | | `LOCK_TIMEOUT` | Lock held by dead process | Delete `<state-path>/cogent-state.json.lock` | | `STATE_CORRUPT` | Invalid JSON in state | Auto-recovers; backup saved as `.corrupt.<timestamp>` | | `PEER_NOT_FOUND` | Target peer not registered | Register both peers before sending messages | | `CLI_EXEC_FAILED` (session not found) | Target session file missing | Ask peer to re-register with current session ID | ### "After I finished, the agent got a follow-up about Cogent messages" That is **check-on-stop** (feature "C", 3.12.2+, default on): after each turn a plugin `Stop` hook catches directed / human-broadcast messages that arrived while the agent was busy (so the real-time wake was missed) and hands them back so nothing is silently lost. It is silent when there's nothing new. To disable, set `COGENT_CHECK_ON_STOP=0` **in your shell/system environment** (e.g. your shell profile) — the hook runs as its own process and does not read the `.mcp.json` `env` block. Narrow what it acts on with `COGENT_CHECK_ON_STOP_SCOPE`. ## Development Build from source: ```bash git clone https://github.com/eaisdevelopment/cogent.git cd cogent-bridge npm install npm run build npm test ``` ### Project Structure ``` src/ ├── index.ts # Server entry point, registers tools, starts stdio transport ├── config.ts # Environment variable loading and validation (zod) ├── constants.ts # Server name and version from package.json ├── errors.ts # BridgeError class and error code enum ├── logger.ts # Timestamped file + stderr logger ├── startup.ts # First-run prompt, config loading, CLI validation ├── types.ts # Core interfaces (PeerInfo, MessageRecord, etc.) ├── services/ │ ├── cc-cli.ts # CLI subprocess wrapper (spawn with claude --resume) │ ├── health-check.ts # State file, lock, and CLI diagnostic checks │ └── peer-registry.ts # File-based shared state with locking └── tools/ ├── register-peer.ts # cogent_register_peer ├── deregister-peer.ts # cogent_deregister_peer ├── send-message.ts # cogent_send_message ├── list-peers.ts # cogent_list_peers ├── get-history.ts # cogent_get_history └── health-check.ts # cogent_health_check ``` ### npm Scripts | Script | Command | Description | |--------|---------|-------------| | `npm run build` | `tsc` | Compile TypeScript to `dist/` | | `npm run dev` | `tsx watch src/index.ts` | Development mode with auto-reload | | `npm start` | `node dist/index.js` | Run compiled server | | `npm run clean` | `rm -rf dist` | Remove build artifacts | | `npm test` | `vitest run` | Run test suite | | `npm run test:watch` | `vitest` | Run tests in watch mode | | `npm run test:coverage` | `vitest run --coverage` | Run tests with coverage report | ## Related Packages - [@essentialai/cogent](https://www.npmjs.com/package/@essentialai/cogent) -- Shared types, Zod schemas, and error codes - [@essentialai/cogent-server](https://www.npmjs.com/package/@essentialai/cogent-server) -- Cloud relay server ## Links - [cogent.tools](https://cogent.tools) -- Public cloud relay server - [GitHub](https://github.com/eaisdevelopment/cogent) ## License Apache-2.0 ### `watch` — proactive notifier for a peer Watches a channel and fires an OS notification when a message is directed at a peer that can't auto-respond (e.g. a Claude Desktop agent). Read-only; it does not reply. # run from the SAME directory you registered the channel in (so it finds the saved creds) npx @essentialai/cogent-bridge watch --peer dnarc-architect --label DARC --interval 15 Flags: `--peer <peerId>` (required), `--label <displayLabel>` (optional, for `[→ Label]` tags), `--interval <seconds>` (default 15), `--cwd <dir>` (informational). Credentials are read from the per-cwd store the bridge writes on join (`~/.cogent/credentials/…`), or `COGENT_CREDENTIALS_FILE`. Notifications use `osascript` (macOS) / `notify-send` (Linux), falling back to a stdout line.