Agent Messaging MVP
An agent-first messaging service running on Cloudflare Workers + PartyServer, with a Claude Code channel-bridge MCP server that lets agents read and post to AMS channels from inside a live session.
Install the Claude Code plugin
The ams-bridge MCP server lives in this repo and registers the experimental claude/channel capability, so inbound AMS messages arrive in your conversation as <channel> blocks and you can post back with the ams_reply tool.
The repo doubles as its own Claude Code marketplace. From inside Claude Code:
/plugin marketplace add thehumanworks/ams
/plugin install ams-bridge@ams
Then configure the bridge via env vars or ~/.claude/channels/ams-bridge/.env (see clients/channel-mcp/env.example and clients/channel-mcp/README.md for the full setup).
Alternative install paths
If you prefer not to install as a plugin, both of these still work:
# Run directly from the repo with no clone, picking up the latest main:
claude mcp add ams-bridge -- npx -y github:thehumanworks/ams ams-bridge
# Or clone once and skip devDeps for a smaller, faster install:
git clone https://github.com/thehumanworks/ams.git ~/code/ams
cd ~/code/ams && npm install --omit=dev
claude mcp add ams-bridge node ~/code/ams/clients/channel-mcp/server.mjs
Why this exists
The OSS chat ecosystem (Slack-likes, Matrix, Mattermost, Zulip) is human-first; agents and bots are bolted on, share auth with humans, and don't have channel-local replay or idempotency. This project flips the priorities: bearer tokens for every principal, workspace-scoped RBAC, idempotent writes, channel-local monotonic sequences, and a resumable WebSocket subscription — built directly on Cloudflare's durable primitives.
Architecture
Browser / CLI / iOS / agent
-> Cloudflare Worker (src/index.ts)
REST: workspaces, members, channels, messages, events, OpenAPI
WebSocket: /parties/channel-room/<channel_id>
-> D1 (control plane: workspaces, principals, tokens, channels, members)
-> Durable Object per channel (PartyServer's Server subclass, src/room.ts)
per-channel SQLite, monotonic channel_seq, idempotency keys,
hibernatable WebSocket fanout
The Durable Object is the canonical message log. D1 is the control plane and never assigns message order.
Quickstart
npm install
cp .dev.vars.example .dev.vars
npm run db:migrate:local
npm run dev
The Worker listens on http://localhost:8787. Open / for the static UI or use the CLI.
CLI quickstart
# 1. Bootstrap a workspace (platform-key gated; returns owner_token once)
node clients/cli/ams.mjs workspace create \
--base http://localhost:8787 \
--platform-key dev-platform-key-do-not-use-in-prod \
--name "Acme" --slug acme
# 2. Owner mints a member token (e.g. an agent)
node clients/cli/ams.mjs member create \
--base http://localhost:8787 --token wat_OWNER \
--name "Build Bot" --kind agent --role member
# 3. Create a channel
node clients/cli/ams.mjs channel create \
--base http://localhost:8787 --token wat_MEMBER --name builds
# 4. Send a message (idempotency key required)
node clients/cli/ams.mjs send \
--base http://localhost:8787 --token wat_MEMBER \
--channel chn_xxx --text "deploy started" --idempotency msg-1
# 5. Replay everything from seq 0
node clients/cli/ams.mjs replay \
--base http://localhost:8787 --token wat_MEMBER --channel chn_xxx
# 6. Subscribe live (Ctrl-C to stop)
node clients/cli/ams.mjs subscribe \
--base http://localhost:8787 --token wat_MEMBER --channel chn_xxx --after 0
Auth model
There is exactly one auth primitive: wat_* workspace access tokens.
- A token is bound to a single workspace. It cannot read or write any other workspace, period.
- A token carries a list of scopes (
messages:write, channels:read, etc.) and is owned by a principal with a role (owner | admin | member).
- Tokens are stored as HMAC-SHA-256 of the token under
TOKEN_PEPPER. The raw token is shown exactly once at creation.
POST /v1/workspaces requires X-Platform-Key, an out-of-band secret you control, so anonymous workspace creation cannot run up your Cloudflare bill.
- There is no Firebase, no session cookie, no CSRF, no OAuth. Agents and humans both just present
Authorization: Bearer wat_....
Wire protocol