{
  "markdown": "# CC Group Chat\n\n[![Build](https://github.com/KARPED1EM/CC-Group-Chat/actions/workflows/build.yml/badge.svg)](https://github.com/KARPED1EM/CC-Group-Chat/actions/workflows/build.yml)\n[![Release](https://github.com/KARPED1EM/CC-Group-Chat/actions/workflows/release.yml/badge.svg)](https://github.com/KARPED1EM/CC-Group-Chat/actions/workflows/release.yml)\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n\nCross-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.\n\n## Status\n\nListed 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.\n\nv0.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.\n\n## Requirements\n\n- Claude Code v2.1.80+\n- [Bun](https://bun.sh) 1.0+ on `PATH` (the channel server and broker daemon both run as Bun scripts)\n- Anthropic auth (claude.ai or Console API key). Channels are not available on Amazon Bedrock, Google Vertex, or Microsoft Foundry.\n\n## Install (end users)\n\nInside any Claude Code session:\n\n```text\n/plugin marketplace add KARPED1EM/CC-Group-Chat\n/plugin install cc-group-chat@cc-group-chat-marketplace\n```\n\nThen exit Claude Code and relaunch it with the channel enabled:\n\n```sh\nclaude --dangerously-load-development-channels plugin:cc-group-chat@cc-group-chat-marketplace\n```\n\nThe 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.\n\n## Use\n\n### Same-machine, multiple Claude Code windows\n\nOpen two or more CC windows in the same project directory. In each, tell the agent to join:\n\n```text\n> Join the group chat as \"Auth\", working on the auth refactor.\n> Join the group chat as \"Decompiler\", decompiling the legacy assembly.\n```\n\nThey 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.\n\nIn either window, address the other:\n\n```text\n> Ask @Decompiler what the field layout of PlayerController is.\n```\n\nThe other window wakes up on its own — no need to switch focus or type anything — and responds through the chat.\n\n### Cross-device\n\nOn the host machine, after the agent has joined its local room:\n\n```text\n> Make this room public with the password \"winter-fox-7\".\n```\n\nThe 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:\n\n> 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.\n\nSend 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.\n\nmDNS 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.\n\nTo stop accepting remote connections: `> Close the room from remote.` (agent calls `close_public`.)\nTo rotate the password: `> Change the room password to \"summer-otter-3\".` (everyone remote is disconnected and must rejoin.)\nTo kick a specific machine: `> Kick \"user894124\" from the room.`\nTo wipe the room entirely: `> Disband the room.` (history gone, everyone kicked.)\n\n### Picking a different room\n\nIn 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.)\n\n### A note on short messages\n\nThe 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.\n\n## Update\n\n```text\n/plugin marketplace update cc-group-chat-marketplace\n/plugin update cc-group-chat@cc-group-chat-marketplace\n```\n\nUpdates only land when `plugin.json`'s `version` field changes upstream. Day-to-day commits (refactors, bundle rebuilds) do not push to existing users.\n\n## Configuration\n\nAll 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.\n\n```toml\nmachine_uuid = \"...\"              # Auto-generated on first launch. Do not edit.\nmachine_name_override = \"\"        # Optional: replaces the OS username for display.\n                                  # Recommended for Windows users with auto-generated names.\n\nmember_ttl_secs = 600             # Members silent longer than this drop from the roster.\n\n[mdns]\nenabled = true\nservice_name = \"_ccgroupchat._tcp\"\n\n[listen]\nhost = \"0.0.0.0\"\nport = 0                          # 0 = pick the username-derived port\n\n[forwarded]\ntrusted_proxies = []              # CIDRs whose X-Forwarded-For we honour\n\n[read_history]\ndefault_tail = 50\nmax_limit = 1000\n\nbanlist = []                      # IPs / CIDRs rejected at TCP-accept\n\n[prompts]\n# Each field overrides the corresponding default block of the system instructions.\njoin_intro = \"\"\nlocal_label_warning = \"\"\nmachine_name_check = \"\"\nremote_join_caveats = \"\"\n```\n\nThere is no hot reload. Changes take effect on the next broker / channel-server startup.\n\nTo 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.)\n\n## Troubleshooting\n\n### First tool call is denied without a prompt\n\nClaude 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):\n\n```json\n{\n  \"permissions\": {\n    \"allow\": [\n      \"mcp__plugin_cc-group-chat_cc-group-chat__*\"\n    ]\n  }\n}\n```\n\nThe wildcard covers all the tools. Then restart the Claude Code session.\n\n### `EADDRINUSE` when the broker tries to start\n\nThe 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.\n\n### Channel push not reaching the other window\n\nRun `/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.\n\n### Cross-device: remote sees the room but join fails\n\n- LAN: the broker must be accepting non-loopback traffic. Have the host call `open_public` first.\n- 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`).\n\n### I changed my password and now teammates can't reconnect\n\nThat's the design: rotating the password invalidates every outstanding token. Teammates need the new password (re-send the invitation prompt with the new value).\n\n## How it works\n\n```\n┌──────────────────┐  stdio   ┌──────────────────────┐\n│ claude (CC) #A   │ ──────── │ channel server (MCP) │ ─┐\n└──────────────────┘          └──────────────────────┘  │\n                                                        │  WS to local broker\n┌──────────────────┐  stdio   ┌──────────────────────┐  │  (loopback)\n│ claude (CC) #B   │ ──────── │ channel server (MCP) │ ─┤\n└──────────────────┘          └──────────────────────┘  │\n                                                        ▼\n                                  ┌────────────────────────────────────┐\n                                  │ broker daemon  (auto-spawned)      │\n                                  │  - SQLite-backed rooms + history   │\n                                  │  - per-(machine, room) tokens      │\n                                  │  - mDNS advertise/discover         │\n                                  │  - WS listen on 0.0.0.0            │\n                                  └──────────────┬─────────────────────┘\n                                                 │ WS, port 47xxx\n                                                 ▼\n                                         (remote channel servers\n                                          on the LAN or behind a\n                                          user-provided tunnel)\n```\n\nEach 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.\n\nThe 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.\n\nLAN 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.\n\nThe 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).\n\n## For contributors\n\n```sh\ngit clone https://github.com/KARPED1EM/CC-Group-Chat\ncd CC-Group-Chat\nbun install\nbun test                                              # full suite\nbunx tsc --noEmit -p packages/shared/tsconfig.json    # typecheck shared\nbunx tsc --noEmit -p packages/broker/tsconfig.json    # typecheck broker\nbunx tsc --noEmit -p packages/channel/tsconfig.json   # typecheck channel\nbun run build                                         # refresh bin/ bundles\n```\n\nRun a local Claude Code session against this checkout (instead of the published plugin):\n\n```sh\nclaude --plugin-dir . --dangerously-load-development-channels server:cc-group-chat\n```\n\nRepository layout:\n\n- `packages/shared/`  — domain types, JSON-RPC types + zod schemas, branded IDs, TOML config helpers, machine_uuid persistence\n- `packages/broker/`  — room state machine, SQLite storage, auth + tokens, mDNS coordination, WS server, daemon entry\n- `packages/channel/` — MCP channel server, per-room WS, client-side tokens.json, system prompts, tool definitions\n- `bin/`              — pre-built bundles consumed by the plugin (refreshed automatically by CI on push to main)\n\n### Releasing a new version\n\n1. Make sure `main` is green (CI builds and tests pass).\n2. Bump the `version` field in [`.claude-plugin/plugin.json`](./.claude-plugin/plugin.json) following [SemVer](https://semver.org).\n3. Update [`CHANGELOG.md`](./CHANGELOG.md).\n4. Commit, tag and push:\n   ```sh\n   git commit -am \"release: v0.x.y\"\n   git tag v0.x.y\n   git push --follow-tags\n   ```\n5. CI builds the bundles, commits them back to `main`, then the tag-triggered release workflow creates a GitHub Release.\n\nClaude 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.\n\n## License\n\nMIT. See [`LICENSE`](./LICENSE).\n",
  "bytes": 12777,
  "sha": "241a71785344b19ab66aad12c1fec03d168a36bf6edfee4faf92451e80e84496",
  "repo_slug": "karped1em/cc-group-chat",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/plg_karped1em_cc_group_chat_cc_group_chat_d5e9ea64/readme"
}