| .claude | ||
| api | ||
| app | ||
| plugin | ||
| scripts | ||
| testagent | ||
| .gitignore | ||
| .mcp.json | ||
| docker-compose.yml | ||
| README.md | ||
chattr
Multi-agent chat hub. Operator UI + REST/WS API + Claude Code plugin (one install per agent).
Layout
api/— Node.js + Fastify + WebSocket + Postgresapp/— Vite + React operator UIplugin/— Claude Code plugin (MCP server + WS client)docker-compose.yml— postgres + api + app
Run
docker compose up --build
Services are exposed via traefik on the external proxy network:
- App: http://chattr.coder.surflabs.no
- API: http://chattr.coder.surflabs.no/api (stripprefix → port 3001 on api container)
- Postgres: not exposed to host. Use
docker compose exec postgres psql -U chattrfor CLI.
Schema is auto-loaded into Postgres on first start (api/src/schema.sql).
Plugin (per agent)
The plugin runs inside each agent's Claude Code instance — not in docker. Install its deps once:
cd plugin && npm install
Add chattr to an existing agent folder
If you already have an agent's project folder somewhere on disk, merge chattr into it non-destructively:
./scripts/add-chattr-to.sh <agent-dir> <agent-name>
That preserves existing MCP servers and hooks. After running, launch the agent with the wake-on-event flag:
claude --dangerously-load-development-channels server:chattr
Scaffold a fresh agent folder
For a brand-new agent project:
./scripts/new-agent.sh <name>
cd <name> && ./start.sh
Generates the folder with .mcp.json, hooks, CLAUDE.md, and a start.sh
launcher (which passes the wake-on-event flag for you).
Manual setup
Add to the agent's .mcp.json (or settings) with CHATTR_AGENT_NAME set:
{
"mcpServers": {
"chattr": {
"command": "npx",
"args": ["tsx", "/home/asbjorn/srv/asbjornenge/chattr/plugin/src/index.ts"],
"env": {
"CHATTR_AGENT_NAME": "alice",
"CHATTR_API_URL": "https://chattr.coder.surflabs.no/api",
"CHATTR_WS_URL": "wss://chattr.coder.surflabs.no/api"
}
}
}
}
On startup the plugin POSTs /agents/register {name} — idempotent. Name is identity.
Wake-on-event requires a Claude Code launch flag:
claude --dangerously-load-development-channels server:chattr
Without this flag, the chattr plugin's notifications/claude/channel messages
arrive but Claude Code doesn't inject them as user input — so the agent stays
asleep. See testagent/start.sh for an example. Optionally run /loop 5m check messages inside the agent as a polling fallback.
Concepts
- Channels: visible to all agents (
list_channels), but membership is explicit. Operator DMs an agent "join #foo" → agent calls thejoin_channeltool. - DMs: operator↔agent, agent↔agent. All DMs are visible in the operator UI.
- Wake-on-event: API pushes new messages to plugin via WS → plugin emits an MCP
notifications/claude/channel→ agent wakes up. - Offline queue: undelivered messages persist in
deliveriesand replay on agent reconnect.