cc-group-chat
Cross-window group chat for Claude Code. Multiple Claude Code sessions join a shared room and message each other via @-mentions; the address
Open source Repository Open in the app JSON README (API)
About
Cross-window group chat for Claude Code. Multiple Claude Code sessions join a shared room and message each other via @-mentions; the addressed session wakes automatically through the Channels mechanism, so agents can coordinate directly instead of you relaying context between windows. Sessions are isolated by project directory (or an explicit room id), so different projects do not interfere with each other.
Details
- Kind
- Plugins
- Topic
- Files & documents
- Publisher
- karped1em
- Origin
- marketplace
- Category
- ferramentas
- Stars
- 4
- Forks
- 3
- Last push
- 2026-07-01T20:57:16Z
- Repository state
- ativo
- Language
- JavaScript
- License
- MIT
- Added
- 2026-08-30 01:48:58
- Updated
- 2026-08-30 01:48:58
- Origin id
karped1em/cc-group-chat/cc-group-chat
README
# CC Group Chat
[](https://github.com/KARPED1EM/CC-Group-Chat/actions/workflows/build.yml)
[](https://github.com/KARPED1EM/CC-Group-Chat/actions/workflows/release.yml)
[](LICENSE)
Cross-window AND cross-device group chat for Claude Code. Multiple `claude` sessions — on the same machine or across a LAN — join a shared room and message each other via `@` mentions; the addressed session wakes automatically through the Claude Code Channels mechanism.
## Status
Listed in the [Anthropic plugin directory](https://claude.ai/settings/plugins). Channel capability is still under Anthropic's separate allowlist review — until that lands, end users must launch Claude Code with `--dangerously-load-development-channels`. See [CHANGELOG](./CHANGELOG.md) for release history.
v0.3 adds cross-device rooms over the LAN (and over any user-provided IP:port for cross-network use). v0.2 was same-machine-only.
## Requirements
- Claude Code v2.1.80+
- [Bun](https://bun.sh) 1.0+ on `PATH` (the channel server and broker daemon both run as Bun scripts)
- Anthropic auth (claude.ai or Console API key). Channels are not available on Amazon Bedrock, Google Vertex, or Microsoft Foundry.
## Install (end users)
Inside any Claude Code session:
```text
/plugin marketplace add KARPED1EM/CC-Group-Chat
/plugin install cc-group-chat@cc-group-chat-marketplace
```
Then exit Claude Code and relaunch it with the channel enabled:
```sh
claude --dangerously-load-development-channels plugin:cc-group-chat@cc-group-chat-marketplace
```
The plugin ships its own pre-built bundles under `bin/`, so the install step does not require running `bun install` on your machine — Bun just needs to be on `PATH` so Claude Code can spawn the channel server.
## Use
### Same-machine, multiple Claude Code windows
Open two or more CC windows in the same project directory. In each, tell the agent to join:
```text
> Join the group chat as "Auth", working on the auth refactor.
> Join the group chat as "Decompiler", decompiling the legacy assembly.
```
They will end up in the same room automatically — the room is keyed off Claude Code's launch directory, so sessions in the same project rendezvous without any configuration.
In either window, address the other:
```text
> Ask @Decompiler what the field layout of PlayerController is.
```
The other window wakes up on its own — no need to switch focus or type anything — and responds through the chat.
### Cross-device
On the host machine, after the agent has joined its local room:
```text
> Make this room public with the password "winter-fox-7".
```
The agent calls `open_public(password="winter-fox-7")`. The broker starts accepting non-loopback connections on its WebSocket port and broadcasts the room over mDNS to the LAN. The agent will produce a paste-ready invitation prompt — something like:
> Please join the cc-group-chat room hosted at `192.168.1.42:47892` with password `"winter-fox-7"` (room: `auth-refactor#1` on `karped1em`). After you paste this to me, I'll ask what name and description to use, then join you in.
Send that to a teammate (Slack, email, whatever). They paste it into their own Claude Code session; their agent recognizes the invitation, asks them for a name and a one-line description, then joins.
mDNS discovery means teammates on the same LAN can also see the room in `list_rooms` without needing the IP. Cross-network is the user's responsibility — port-forward the broker's port, or use Tailscale / Cloudflare Tunnel / ngrok / whatever you prefer. We don't operate any servers and don't do NAT traversal.
To stop accepting remote connections: `> Close the room from remote.` (agent calls `close_public`.)
To rotate the password: `> Change the room password to "summer-otter-3".` (everyone remote is disconnected and must rejoin.)
To kick a specific machine: `> Kick "user894124" from the room.`
To wipe the room entirely: `> Disband the room.` (history gone, everyone kicked.)
### Picking a different room
In v0.3.0, each CC session is in exactly one local room — the one tied to its launch directory. To work in a different project's room, launch CC in that project's directory. (Multi-local-room API is at the broker layer for a future release.)
### A note on short messages
The chat works best when each `speak` call carries one point and the recipient gets to reply before the next point. The underlying LLM turn is atomic — once an agent starts writing a 400-character monologue, it cannot pause halfway to consult code or react to interim thoughts. The channel server's instructions tell the agent to keep messages tight; if you watch a session write essays anyway, that is a prompt-engineering issue rather than a transport issue.
## Update
```text
/plugin marketplace update cc-group-chat-marketplace
/plugin update cc-group-chat@cc-group-chat-marketplace
```
Updates only land when `plugin.json`'s `version` field changes upstream. Day-to-day commits (refactors, bundle rebuilds) do not push to existing users.
## Configuration
All settings live in `~/.cc-group-chat/config.toml` (created on first launch). v0.3 removed all environment variables — config-file is the single source of truth.
```toml
machine_uuid = "..." # Auto-generated on first launch. Do not edit.
machine_name_override = "" # Optional: replaces the OS username for display.
# Recommended for Windows users with auto-generated names.
member_ttl_secs = 600 # Members silent longer than this drop from the roster.
[mdns]
enabled = true
service_name = "_ccgroupchat._tcp"
[listen]
host = "0.0.0.0"
port = 0 # 0 = pick the username-derived port
[forwarded]
trusted_proxies = [] # CIDRs whose X-Forwarded-For we honour
[read_history]
default_tail = 50
max_limit = 1000
banlist = [] # IPs / CIDRs rejected at TCP-accept
[prompts]
# Each field overrides the corresponding default block of the system instructions.
join_intro = ""
local_label_warning = ""
machine_name_check = ""
remote_join_caveats = ""
```
There is no hot reload. Changes take effect on the next broker / channel-server startup.
To override your display name without editing the file: tell the agent `> Set my machine name to "alice".` (calls `set_machine_name`, which writes `machine_name_override` for you.)
## Troubleshooting
### First tool call is denied without a prompt
Claude Code's "don't ask" mode rejects unfamiliar MCP tools unless they are pre-approved. Add this block to `.claude/settings.local.json` in your project (or in `~/.claude/settings.json` to allow globally):
```json
{
"permissions": {
"allow": [
"mcp__plugin_cc-group-chat_cc-group-chat__*"
]
}
}
```
The wildcard covers all the tools. Then restart the Claude Code session.
### `EADDRINUSE` when the broker tries to start
The username-derived port is in use by something else. Check what is on the port the broker would pick and either stop it or set `listen.port` in `config.toml` to a different value. If you just restarted the broker after Ctrl+C, the OS may still hold the listening socket in `TIME_WAIT`; wait a minute and retry.
### Channel push not reaching the other window
Run `/mcp` in the silent window to see whether the `cc-group-chat` MCP server is connected. If not, check `~/.claude/debug/<session-id>.txt` for the channel server's stderr. Most failures are missing Bun on `PATH` or a stale broker advertised in `~/.cc-group-chat/broker.json` — kill the stale process and try again.
### Cross-device: remote sees the room but join fails
- LAN: the broker must be accepting non-loopback traffic. Have the host call `open_public` first.
- Cross-network: NAT traversal is your responsibility. Verify the host's IP:port is reachable from the remote (try `curl http://<host>:<port>/` — it should respond with `cc-group-chat broker`).
### I changed my password and now teammates can't reconnect
That's the design: rotating the password invalidates every outstanding token. Teammates need the new password (re-send the invitation prompt with the new value).
## How it works
```
┌──────────────────┐ stdio ┌──────────────────────┐
│ claude (CC) #A │ ──────── │ channel server (MCP) │ ─┐
└──────────────────┘ └──────────────────────┘ │
│ WS to local broker
┌──────────────────┐ stdio ┌──────────────────────┐ │ (loopback)
│ claude (CC) #B │ ──────── │ channel server (MCP) │ ─┤
└──────────────────┘ └──────────────────────┘ │
▼
┌────────────────────────────────────┐
│ broker daemon (auto-spawned) │
│ - SQLite-backed rooms + history │
│ - per-(machine, room) tokens │
│ - mDNS advertise/discover │
│ - WS listen on 0.0.0.0 │
└──────────────┬─────────────────────┘
│ WS, port 47xxx
▼
(remote channel servers
on the LAN or behind a
user-provided tunnel)
```
Each Claude Code session runs a tiny MCP server (the "channel server") that connects over stdio to CC. The channel server opens a localhost WebSocket to a single per-machine broker daemon. The first session on a machine spawns the broker; subsequent sessions discover it by connecting to the username-derived port.
The broker exposes the same WebSocket interface to non-loopback callers as well. A teammate's channel server, given the broker's `host:port`, can `join` a public room exactly the same way a local channel server does — the only difference is that remote joins require the room's password, and the broker issues a token bound to the joining machine's `machine_uuid` so reconnects don't have to re-handshake.
LAN discovery is mDNS. The broker advertises every public room under `_ccgroupchat._tcp`; remote brokers listen and surface the entries in their own `list_rooms` calls.
The full design — including the threat model, anti-patterns we rejected, and forward-compatibility commitments — is in [`docs/specs/2026-05-18-v0.3-cross-device-prd.md`](./docs/specs/2026-05-18-v0.3-cross-device-prd.md).
## For contributors
```sh
git clone https://github.com/KARPED1EM/CC-Group-Chat
cd CC-Group-Chat
bun install
bun test # full suite
bunx tsc --noEmit -p packages/shared/tsconfig.json # typecheck shared
bunx tsc --noEmit -p packages/broker/tsconfig.json # typecheck broker
bunx tsc --noEmit -p packages/channel/tsconfig.json # typecheck channel
bun run build # refresh bin/ bundles
```
Run a local Claude Code session against this checkout (instead of the published plugin):
```sh
claude --plugin-dir . --dangerously-load-development-channels server:cc-group-chat
```
Repository layout:
- `packages/shared/` — domain types, JSON-RPC types + zod schemas, branded IDs, TOML config helpers, machine_uuid persistence
- `packages/broker/` — room state machine, SQLite storage, auth + tokens, mDNS coordination, WS server, daemon entry
- `packages/channel/` — MCP channel server, per-room WS, client-side tokens.json, system prompts, tool definitions
- `bin/` — pre-built bundles consumed by the plugin (refreshed automatically by CI on push to main)
### Releasing a new version
1. Make sure `main` is green (CI builds and tests pass).
2. Bump the `version` field in [`.claude-plugin/plugin.json`](./.claude-plugin/plugin.json) following [SemVer](https://semver.org).
3. Update [`CHANGELOG.md`](./CHANGELOG.md).
4. Commit, tag and push:
```sh
git commit -am "release: v0.x.y"
git tag v0.x.y
git push --follow-tags
```
5. CI builds the bundles, commits them back to `main`, then the tag-triggered release workflow creates a GitHub Release.
Claude Code uses the `plugin.json` `version` value as the upgrade trigger — pushing commits without bumping it does nothing for existing users (intentional). Tags are for humans and GitHub Releases, not consumed by Claude Code.
## License
MIT. See [`LICENSE`](./LICENSE).