{"id":48217491,"url":"https://github.com/ractive/claw-socket","last_synced_at":"2026-04-04T19:01:01.411Z","repository":{"id":348946538,"uuid":"1199265500","full_name":"ractive/claw-socket","owner":"ractive","description":"A websocket server streaming Claude Code activity","archived":false,"fork":false,"pushed_at":"2026-04-03T15:37:53.000Z","size":296,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-03T17:45:58.917Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ractive.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-02T07:27:28.000Z","updated_at":"2026-04-03T15:38:01.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ractive/claw-socket","commit_stats":null,"previous_names":["ractive/claw-socket"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/ractive/claw-socket","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ractive%2Fclaw-socket","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ractive%2Fclaw-socket/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ractive%2Fclaw-socket/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ractive%2Fclaw-socket/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ractive","download_url":"https://codeload.github.com/ractive/claw-socket/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ractive%2Fclaw-socket/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31409471,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T10:20:44.708Z","status":"ssl_error","status_checked_at":"2026-04-04T10:20:06.846Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-04T19:00:45.253Z","updated_at":"2026-04-04T19:01:01.398Z","avatar_url":"https://github.com/ractive.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# claw-socket\n\nReal-time WebSocket bridge that streams Claude Code agent events to any connected client.\n\nclaw-socket watches your Claude Code sessions and forwards tool calls, agent state changes, usage stats, and lifecycle events over a WebSocket connection. Connect a dashboard, build automations, or stream events to your own tooling.\n\n## Quick start\n\n```bash\n# Install globally with Bun\nbun install -g claw-socket\n\n# Start the server (installs Claude Code hooks automatically)\nclaw-socket\n```\n\nThe server starts on `ws://localhost:3838` by default.\n\n## CLI flags\n\n```\nUsage: claw-socket [options]\n\nOptions:\n  --port \u003cnumber\u003e      WebSocket server port (default: 3838, env: CLAW_SOCKET_PORT)\n  --host \u003cstring\u003e      Hostname to bind (default: localhost, env: CLAW_SOCKET_HOST)\n  --verbose            Enable verbose logging\n  --no-hooks           Skip hook installation\n  --no-auth            Disable token authentication\n  --rotate-token       Regenerate auth token and exit\n  --install-hooks      Install hooks and exit\n  --uninstall-hooks    Remove claw-socket hooks from Claude settings and exit\n  --help               Show help\n  --version            Show version\n```\n\n## Authentication\n\nclaw-socket uses file-based token authentication. On first startup, a 32-byte random hex token is generated and written to `~/.claw-socket/token` (mode 600, directory mode 700). The token is reused across restarts.\n\n- **WebSocket upgrade** requires `?token=\u003ctoken\u003e` query parameter\n- **POST /hook** requires `Authorization: Bearer \u003ctoken\u003e` header\n- **GET /health**, **GET /docs**, **GET /asyncapi.json** are unauthenticated\n\nUse `--no-auth` to disable authentication (development/testing). Use `--rotate-token` to regenerate the token and exit (requires server restart).\n\n### Connecting from other projects\n\nRead the token from `~/.claw-socket/token` and pass it as described above:\n\n**Shell / curl:**\n```bash\nTOKEN=$(cat ~/.claw-socket/token)\n# WebSocket (via websocat)\nwebsocat \"ws://localhost:3838?token=$TOKEN\"\n# POST /hook\ncurl -X POST http://localhost:3838/hook \\\n  -H 'Content-Type: application/json' \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -d '{\"event\": \"...\"}'\n```\n\n**TypeScript / JavaScript:**\n```ts\nimport { readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\nconst token = readFileSync(join(homedir(), \".claw-socket\", \"token\"), \"utf-8\").trim();\nconst ws = new WebSocket(`ws://localhost:3838?token=${token}`);\n```\n\n**Python:**\n```python\nfrom pathlib import Path\ntoken = (Path.home() / \".claw-socket\" / \"token\").read_text().strip()\n```\n\n## WebSocket protocol\n\nConnect to `ws://localhost:3838?token=\u003ctoken\u003e`. The server immediately sends a snapshot of all active sessions and agents.\n\n### Client messages\n\n**Subscribe to event topics**\n\n```json\n{ \"type\": \"subscribe\", \"topics\": [\"tool.*\", \"session.*\"] }\n```\n\nGlob patterns are supported (`*` matches within a segment). An optional `sessionId` field scopes events to a single session.\n\n**Unsubscribe**\n\n```json\n{ \"type\": \"unsubscribe\", \"topics\": [\"tool.*\"] }\n```\n\n**Request snapshot**\n\n```json\n{ \"type\": \"get_snapshot\" }\n```\n\n**Get session history**\n\n```json\n{ \"type\": \"get_session_history\", \"sessionId\": \"abc123\", \"limit\": 100 }\n```\n\n**Request replay from a sequence number**\n\nEach broadcast event carries a `seq` integer. Use this to reconnect without missing events:\n\n```json\n{ \"type\": \"replay\", \"lastSeq\": 42 }\n```\n\nThe server replays all buffered events with `seq \u003e lastSeq` that match your current subscriptions.\n\n**Get usage stats**\n\n```json\n{ \"type\": \"get_usage\", \"sessionId\": \"abc123\" }\n```\n\n### Event envelope\n\nAll server-to-client events share this structure:\n\n```json\n{\n  \"type\": \"tool.use\",\n  \"timestamp\": 1712345678000,\n  \"sessionId\": \"abc123\",\n  \"seq\": 17,\n  \"data\": { }\n}\n```\n\n### Common event types\n\n| Type | Description |\n|------|-------------|\n| `session.discovered` | New Claude session started |\n| `session.removed` | Session ended |\n| `tool.use` | Tool invoked |\n| `tool.result` | Tool completed |\n| `agent.state_changed` | Agent state updated |\n| `usage.updated` | Token/cost usage updated |\n| `system.error` | Recoverable server error |\n\n## Example client (JavaScript)\n\n```javascript\nconst ws = new WebSocket(\"ws://localhost:3838\");\nlet lastSeq = -1;\n\nws.onopen = () =\u003e {\n  ws.send(JSON.stringify({\n    type: \"subscribe\",\n    topics: [\"tool.*\", \"session.*\"]\n  }));\n};\n\nws.onmessage = (e) =\u003e {\n  const msg = JSON.parse(e.data);\n  if (msg.seq != null) lastSeq = msg.seq;\n\n  if (msg.type === \"snapshot\") {\n    console.log(\"Active sessions:\", msg.sessions.length);\n  } else if (msg.type === \"tool.use\") {\n    console.log(\"Tool used:\", msg.data.toolName);\n  }\n};\n\n// On reconnect, replay missed events\nfunction reconnect(ws) {\n  ws.send(JSON.stringify({ type: \"subscribe\", topics: [\"tool.*\", \"session.*\"] }));\n  if (lastSeq \u003e= 0) {\n    ws.send(JSON.stringify({ type: \"replay\", lastSeq }));\n  }\n}\n```\n\n## HTTP endpoints\n\n| Path | Method | Description |\n|------|--------|-------------|\n| `/health` | GET | Server health check |\n| `/hook` | POST | Claude Code hook receiver — returns `202 {status:\"accepted\"}` |\n| `/asyncapi.json` | GET | AsyncAPI spec (JSON) |\n| `/docs` | GET | AsyncAPI browser UI (requires generated docs, see below) |\n\n## Docs generation\n\n`/docs` serves pre-generated static HTML. Run the following after cloning or whenever the spec changes:\n\n```bash\n# 1. Export the AsyncAPI spec\nbun run export-spec\n\n# 2. Generate the HTML docs page (served at /docs)\nasyncapi generate fromTemplate asyncapi.json @asyncapi/html-template@3.5.4 \\\n  --param singleFile=true -o public --force-write\n\n# 3. Generate the markdown reference (written to kb/docs/api-reference.md)\nasyncapi generate fromTemplate asyncapi.json @asyncapi/markdown-template@2.0.0 \\\n  --param outFilename=api-reference.md -o kb/docs --force-write\n\n# 4. Patch sidebar layout bug in html-template output\nbun run patch-docs\n```\n\nInstall the AsyncAPI CLI if needed: `npm install -g @asyncapi/cli` (or substitute `asyncapi` with `bunx @asyncapi/cli`).\n\n\u003e **Note:** Step 4 patches a layout bug in `@asyncapi/html-template` where the fixed sidebar overflows its container. It's idempotent — safe to run multiple times.\n\n## Security Scanning\n\n[Gitleaks](https://github.com/gitleaks/gitleaks) is used to detect secrets accidentally committed to the repository. CI runs this automatically on every push and pull request.\n\nTo run locally:\n\n```bash\ngitleaks detect\n```\n\nConfiguration lives in `.gitleaks.toml` at the project root.\n\n## Development\n\n```bash\n# Run tests\nbun test\n\n# Type check\nbun run typecheck\n\n# Format + lint + typecheck + test\nbun run check\n\n# Build standalone binary\nbun run build\n\n# Run in watch mode\nbun run dev\n\n# Install / uninstall Claude Code hooks manually\nbun run hooks:install\nbun run hooks:uninstall\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fractive%2Fclaw-socket","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fractive%2Fclaw-socket","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fractive%2Fclaw-socket/lists"}