| title | Quickstart |
|---|---|
| description | From a fresh clone to a running ClickClack instance with a real owner, a workspace, a channel, and a bot — in about five minutes. |
The smallest useful ClickClack: a real owner account, one workspace, one channel, a session token in your shell, a bot that posts a message. About five minutes.
pnpm install
pnpm build
go run ./apps/api/cmd/clickclack serveOpen http://localhost:8080 for the product website. Open
http://localhost:8080/app for the chat app with a Local Captain user
already signed in via the dev fallback. That's the empty-dev path — useful for
poking around, not what you want long-term.
go run ./apps/api/cmd/clickclack admin bootstrap \
--name "Peter" --email steipete@gmail.com
# prints usr_...If the DB already has a user (the dev fallback created one),
bootstrap returns that user's ID instead of making a new one. Reset
by deleting data/clickclack.db if you want a clean slate.
Magic-link tokens are mintable from the CLI. Generate one and exchange it for a session token:
TOKEN=$(go run ./apps/api/cmd/clickclack admin magic-link create \
--email steipete@gmail.com --name "Peter")
SESSION=$(go run ./apps/api/cmd/clickclack login \
--magic-token "$TOKEN" --plain --no-store)
# prints ses_...That ses_... is what bots and CLIs put in Authorization: Bearer. The
browser already has it as the default cc_session cookie if you ran consume
from the SPA. Production deployments can select a stable namespaced cookie.
To store the session for future CLI commands, omit --no-store.
You can use the SPA, or hit the API directly:
WORKSPACE=$(curl -s -X POST http://localhost:8080/api/workspaces \
-H "authorization: Bearer $SESSION" \
-H 'content-type: application/json' \
-d '{"name":"Tide Pool"}' | jq -r .workspace.id)
CHANNEL=$(curl -s -X POST "http://localhost:8080/api/workspaces/$WORKSPACE/channels" \
-H "authorization: Bearer $SESSION" \
-H 'content-type: application/json' \
-d '{"name":"general"}' | jq -r .channel.id)
echo "workspace=$WORKSPACE channel=$CHANNEL"go run ./apps/api/cmd/clickclack \
--server http://localhost:8080 \
--token "$SESSION" \
send --channel "$CHANNEL" "click. clack."
curl -s -X POST "http://localhost:8080/api/channels/$CHANNEL/messages" \
-H "authorization: Bearer $SESSION" \
-H 'content-type: application/json' \
-d '{"body":"click. clack."}' | jq .message.bodyRefresh the SPA — the message is there. Now hover it and click the thread icon to start a thread; replies stream live over the WebSocket.
CLICKCLACK_URL=http://localhost:8080 \
CLICKCLACK_TOKEN="$SESSION" \
CLICKCLACK_CHANNEL_ID="$CHANNEL" \
CLICKCLACK_TEXT="clack from a bot" \
pnpm --filter @clickclack/example-bot startIt posts a single message via the TypeScript SDK. Use it as a template — the SDK is framework-neutral, so the same code runs in Node, Bun, Deno, browsers, or Cloudflare Workers.
- Architecture — how the parts fit.
- Realtime — cursor recovery and event types.
- Auth — the four ways to identify a caller.
- Deployment — running this for real, not just on a laptop.