diff --git a/docs/AGENTS.default.md b/docs/AGENTS.default.md index 8890c5638..fb8beed20 100644 --- a/docs/AGENTS.default.md +++ b/docs/AGENTS.default.md @@ -7,7 +7,7 @@ read_when: # AGENTS.md β€” Clawdis Personal Assistant (default) ## What Clawdis Does -- Runs WhatsApp gateway + Pi/Tau coding agent so the assistant can read/write chats, fetch context, and run tools via the host Mac. +- Runs WhatsApp gateway + Pi coding agent so the assistant can read/write chats, fetch context, and run tools via the host Mac. - macOS app manages permissions (screen recording, notifications, microphone) and exposes a CLI helper `clawdis-mac` for scripts. - Sessions are per-sender; heartbeats keep background tasks alive. diff --git a/docs/agents.md b/docs/agents.md index e0f4baf36..76dc1632b 100644 --- a/docs/agents.md +++ b/docs/agents.md @@ -1,213 +1,92 @@ --- -summary: "Current agent integration: Pi/Tau as the sole coding agent with config examples" +summary: "Current agent integration: Pi as the sole coding agent with config examples" read_when: - Changing agent invocation or defaults --- + # Agent Integration πŸ€– -CLAWDIS now ships with a single coding agent: Pi (the Tau CLI). Legacy Claude/Codex/Gemini/Opencode paths have been removed. -Pi is bundled as a dependency of `clawdis`, so a fresh `pnpm install` gives you the `pi`/`tau` binaries automatically. +CLAWDIS ships with a single coding-agent path: **Pi** (RPC mode). Legacy Claude/Codex/Gemini/Opencode integrations have been removed. -## Pi / Tau +## Default behavior -The recommended (and only) agent for CLAWDIS. Built by Mario Zechner, forked with love. +If you don’t configure `inbound.reply`, CLAWDIS uses the bundled Pi binary in RPC mode: +- command: `pi --mode rpc {{BodyStripped}}` +- per-sender sessions (stored under `~/.clawdis/sessions/*.jsonl`) +- `/new` starts a fresh session -```json +This is usually enough for a personal assistant setup; add `inbound.allowFrom` to restrict who can trigger it. + +## Custom agent command (still Pi) + +To override the agent command, configure `inbound.reply.mode: "command"`: + +```json5 { - "reply": { - "mode": "command", - "agent": { - "kind": "pi", - "format": "json", - "model": "claude-opus-4-5" // default if omitted - }, - "command": [ - "node", - "/path/to/pi-mono/packages/coding-agent/dist/cli.js", - "-p", - "--mode", "json", - "{{BodyStripped}}" - ] - } -} -``` - -#### RPC Mode (Recommended) - -For streaming tool output and better integration: - -```json -{ - "command": [ - "tau", - "--mode", "rpc", - "--session", "/path/to/sessions/{{SessionId}}.jsonl" - ] -} -``` - -RPC mode is enforced by CLAWDIS (we rewrite `--mode` to `rpc` for Pi invocations). It gives you: -- πŸ’» Real-time tool execution display -- πŸ“Š Token usage tracking -- πŸ”„ Streaming responses - -If the agent does not report a model, CLAWDIS assumes `claude-opus-4-5` with ~200k context tokens (pi-ai defaults) for usage summaries. - -## Session Management - -### Per-Sender Sessions - -Each phone number gets its own conversation history: - -```json -{ - "session": { - "scope": "per-sender", - "sessionArgNew": ["--session", "{{SessionId}}.jsonl"], - "sessionArgResume": ["--session", "{{SessionId}}.jsonl", "--continue"] - } -} -``` -By default CLAWDIS stores sessions under `~/.clawdis/sessions` and will create the folder automatically. - -### Global Session - -Everyone shares the same context (useful for team bots): - -```json -{ - "session": { - "scope": "global" - } -} -``` - -### Session Reset - -Users can start fresh with trigger words: - -```json -{ - "session": { - "resetTriggers": ["/new", "/reset", "/clear"] - } -} -``` - -## System Prompts - -Give your agent personality: - -```json -{ - "session": { - "sessionIntro": "You are Clawd, a space lobster AI assistant. Be helpful, be funny, use 🦞 liberally. Read /path/to/AGENTS.md for your instructions.", - "sendSystemOnce": true - } -} -``` - -## Heartbeats - -Keep your agent alive and doing background tasks: - -```json -{ - "reply": { - "heartbeatMinutes": 10, - "heartbeatBody": "HEARTBEAT" - } -} -``` - -The agent receives "HEARTBEAT" and can: -- Check for pending tasks -- Update memory files -- Monitor systems -- Reply with `HEARTBEAT_OK` to skip - -## Tool Streaming - -When using RPC mode, CLAWDIS shows tool usage in real-time: - -``` -πŸ’» ls -la ~/Projects -πŸ“„ Reading README.md -✍️ Writing config.json -πŸ“ Editing main.ts -πŸ“Ž Attaching image.jpg -πŸ› οΈ Running custom tool -``` - -Configure the display: - -```json -{ - "agent": { - "kind": "pi", - "format": "json", - "toolEmoji": { - "bash": "πŸ’»", - "read": "πŸ“„", - "write": "✍️", - "edit": "πŸ“", - "attach": "πŸ“Ž" + inbound: { + reply: { + mode: "command", + command: ["pi", "--mode", "rpc", "{{BodyStripped}}"], + timeoutSeconds: 1800, + agent: { kind: "pi", format: "json" } } } } ``` -## Timeouts +Notes: +- CLAWDIS forces `--mode rpc` for Pi invocations (even if you pass `--mode json/text`). +- If your `command` array omits `{{Body}}`/`{{BodyStripped}}`, CLAWDIS still synthesizes the prompt body for RPC mode. -Long-running tasks need appropriate timeouts: +## Sessions -```json +Session behavior lives under `inbound.reply.session`: + +```json5 { - "reply": { - "timeoutSeconds": 1800 - } -} -``` - -For background tasks, the agent can yield and continue later using the `process` tool. - -## Error Handling - -When the agent fails: - -1. CLAWDIS logs the error -2. Sends a user-friendly message -3. Preserves the session for retry - -```json -{ - "reply": { - "errorMessage": "🦞 Oops! Something went wrong. Try again?" - } -} -``` - -## Multi-Agent Setup - -Run different agents for different numbers: - -```json -{ - "inbound": { - "routes": [ - { - "from": "+1234567890", - "command": ["work-agent", "{{Body}}"] - }, - { - "from": "+0987654321", - "command": ["fun-agent", "{{Body}}"] + inbound: { + reply: { + session: { + scope: "per-sender", + resetTriggers: ["/new", "/reset"], + idleMinutes: 10080, + sendSystemOnce: true, + sessionIntro: "You are Clawd. Be a good lobster." } - ] + } } } ``` +Defaults when `session` is enabled: +- Session files are written to `~/.clawdis/sessions/{{SessionId}}.jsonl`. +- Resume adds `--continue` automatically (Pi needs it to load prior messages). + +## Heartbeats + +If you enable `inbound.reply.heartbeatMinutes`, CLAWDIS periodically runs a heartbeat prompt (default: `HEARTBEAT /think:high`). + +- If the agent replies with `HEARTBEAT_OK` (exact token), CLAWDIS suppresses outbound delivery for that heartbeat. +- If you want a different command for heartbeats, set `inbound.reply.heartbeatCommand`. + +```json5 +{ + inbound: { + reply: { + heartbeatMinutes: 30, + heartbeatCommand: ["pi", "--mode", "rpc", "HEARTBEAT /think:high"] + } + } +} +``` + +## Tool streaming (RPC) + +RPC mode emits structured tool lifecycle events (start/result) and assistant output. These are: +- logged to `/tmp/clawdis/…` +- streamed over the Gateway WS to clients like WebChat and the macOS app + --- -*Next: [Group Chats](./groups.md)* 🦞 +*Next: [Group Chats](./group-messages.md)* 🦞 + diff --git a/docs/architecture.md b/docs/architecture.md index 0c1a0c7d0..c1f0a4e32 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -21,7 +21,7 @@ Last updated: 2025-12-09 - One WS connection per client. - Send requests (`health`, `status`, `send`, `agent`, `system-presence`, toggles) and subscribe to events (`tick`, `agent`, `presence`, `shutdown`). - On macOS, the app can also be invoked via deep links (`clawdis://agent?...`) which translate into the same Gateway `agent` request path (see `docs/clawdis-mac.md`). -- **Agent process (Tau/Pi)** +- **Agent process (Pi)** - Spawned by the Gateway on demand for `agent` calls; streams events back over the same WS connection. - **WebChat** - Serves static assets locally. diff --git a/docs/audio.md b/docs/audio.md index 6322ee2a0..c97e47cde 100644 --- a/docs/audio.md +++ b/docs/audio.md @@ -3,6 +3,7 @@ summary: "How inbound audio/voice notes are downloaded, transcribed, and injecte read_when: - Changing audio transcription or media handling --- + # Audio / Voice Notes β€” 2025-12-05 ## What works @@ -51,3 +52,4 @@ Requires `OPENAI_API_KEY` in env and `openai` CLI installed: ## Gotchas - Ensure your CLI exits 0 and prints plain text; JSON needs to be massaged via `jq -r .text`. - Keep timeouts reasonable (`timeoutSeconds`, default 45s) to avoid blocking the reply queue. + diff --git a/docs/clawd.md b/docs/clawd.md index d12a8a06b..318dd0885 100644 --- a/docs/clawd.md +++ b/docs/clawd.md @@ -4,54 +4,37 @@ read_when: - Onboarding a new assistant instance - Reviewing safety/permission implications --- -# Building Your Own AI Personal Assistant with clawdis + +# Building a personal assistant with CLAWDIS (Clawd-style) -> **TL;DR:** CLAWDIS (Pi/Tau only) lets you run a proactive assistant over WhatsApp. It can check in on you, remember context across conversations, run commands on your Mac, and even wake you up with music. This doc was originally written for Claude Code; where you see `claude ...`, use `pi --mode rpc ...` instead. A Pi-specific rewrite is coming soon. +CLAWDIS is a WhatsApp + Telegram gateway for **Pi** agents. This guide is the β€œpersonal assistant” setup: one dedicated WhatsApp number that behaves like your always-on agent. -⚠️ **Note (2025-12-05):** CLAWDIS now ships with only the Pi/Tau agent. The walkthrough below references Claude Code; swap those commands for `pi`/`tau` if you follow along. A Pi-specific guide is coming soon. +## ⚠️ Safety first ---- +You’re putting an agent in a position to: +- run commands on your machine (depending on your Pi tool setup) +- read/write files in your workspace +- send messages back out via WhatsApp/Telegram -## ⚠️ Warning: Here Be Dragons +Start conservative: +- Always set `inbound.allowFrom` (never run open-to-the-world on your personal Mac). +- Use a dedicated WhatsApp number for the assistant. +- Keep heartbeats disabled until you trust the setup (`heartbeatMinutes: 0`). -**This setup gives an AI full access to your computer.** Before you proceed, understand what you're signing up for: +## Prerequisites -- πŸ”“ **`--dangerously-skip-permissions`** means Claude can run *any* shell command without asking -- πŸ€– **AI makes mistakes** - it might delete files, send emails, or do things you didn't intend -- πŸ”₯ **Heartbeats run autonomously** - your AI acts even when you're not watching -- πŸ“± **WhatsApp is not encrypted E2E here** - messages pass through your Mac in plaintext +- Node **22+** +- CLAWDIS installed: `npm install -g clawdis` +- A second phone number (SIM/eSIM/prepaid) for the assistant -**The good news:** We use Claude Code CLI, so you can reuse your existing [Claude Pro/Max subscription](https://claude.ai) - no separate API costs! +## The two-phone setup (recommended) -**Start conservative:** -1. Use Sonnet instead of Opus for faster responses (still great!) -2. Skip `--dangerously-skip-permissions` until you trust the setup -3. Set `heartbeatMinutes: 0` to disable proactive pings initially -4. Use a test phone number in `allowFrom` first - -This is experimental software running experimental AI. The author uses it daily, but your mileage may vary. **You are responsible for what your AI does.** - ---- - -## Prerequisites: The Two-Phone Setup - -**Important:** You need a **separate phone number** for your AI assistant. Here's why and how: - -### Why a Dedicated Number? - -clawdis uses WhatsApp Web to receive messages. If you link your personal WhatsApp, *you* become the assistant - every message to you goes to Claude. Instead, give Claude its own identity: - -- πŸ“± **Get a second SIM** - cheap prepaid SIM, eSIM, or old phone with a number -- πŸ’¬ **Install WhatsApp** on that phone and verify the number -- πŸ”— **Link to clawdis** - run `clawdis login` and scan the QR with that phone's WhatsApp -- βœ‰οΈ **Message your AI** - now you (and others) can text that number to reach Claude - -### The Setup +You want this: ``` -Your Phone (personal) Second Phone (AI) +Your Phone (personal) Second Phone (assistant) β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Your WhatsApp β”‚ ──────▢ β”‚ AI's WhatsApp β”‚ +β”‚ Your WhatsApp β”‚ ──────▢ β”‚ Assistant WA β”‚ β”‚ +1-555-YOU β”‚ message β”‚ +1-555-CLAWD β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ linked via QR @@ -59,434 +42,137 @@ Your Phone (personal) Second Phone (AI) β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Your Mac β”‚ β”‚ (clawdis) β”‚ - β”‚ Claude Code β”‚ + β”‚ Pi agent β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` -The second phone just needs to stay on and connected to the internet occasionally (WhatsApp Web stays linked for ~14 days without the phone being online). +If you link your personal WhatsApp to CLAWDIS, every message to you becomes β€œagent input”. That’s rarely what you want. ---- +## 5-minute quick start -## Meet Clawd πŸ‘‹ +1) Pair WhatsApp Web (shows QR; scan with the assistant phone): -![Clawd in action on WhatsApp](whatsapp-clawd.jpg) +```bash +clawdis login +``` -Clawd is @steipete's personal AI assistant built on clawdis. Here's what makes it special: +2) Start the Gateway (leave it running): -- **Always available** via WhatsApp - no app switching, works on any device -- **Proactive heartbeats** - Clawd checks in every 10 minutes and can alert you to things (low battery, calendar reminders, anything it notices) -- **Persistent memory** - conversations span days/weeks with full context -- **Full Mac access** - can run commands, take screenshots, control Spotify, read/write files -- **Personal workspace** - has its own folder (`~/clawd`) where it stores notes, memories, and artifacts +```bash +clawdis gateway --port 18789 +``` -The magic is in the combination: WhatsApp's ubiquity + Claude's intelligence + clawdis's plumbing + your Mac's capabilities. +3) Start the local WebChat UI (optional, but great for debugging): -## Prerequisites +```bash +clawdis webchat +``` -- Node 22+, `clawdis` installed: `npm install -g clawdis` -- Claude CLI installed and logged in: - ```sh - brew install anthropic-ai/cli/claude - claude login - ``` -- Optional: set `ANTHROPIC_API_KEY` in your shell profile for non-interactive use - -## The Config That Powers Clawd - -This is the actual config running on @steipete's Mac (`~/.clawdis/clawdis.json`): +4) Put a minimal config in `~/.clawdis/clawdis.json`: ```json5 { - logging: { level: "trace", file: "/tmp/clawdis/clawdis.log" }, inbound: { - allowFrom: ["+1234567890"], // your phone number + allowFrom: ["+15555550123"] + } +} +``` + +Now message the assistant number from your allowlisted phone. + +## The config that turns it into β€œan assistant” + +CLAWDIS defaults to a good Pi setup even without `inbound.reply`, but you’ll usually want to tune: +- session intro (personality + instructions) +- thinking defaults (if desired) +- heartbeats (once you trust it) + +Example: + +```json5 +{ + logging: { level: "info" }, + inbound: { + allowFrom: ["+15555550123"], + groupChat: { + requireMention: true, + mentionPatterns: ["@clawd", "clawd"] + }, reply: { mode: "command", - cwd: "/Users/steipete/clawd", // Clawd's home - give your AI a workspace! - bodyPrefix: "/think:high ", // triggers extended thinking on every message - sessionIntro: `You are Clawd, Peter Steinberger's personal AI assistant. You run 24/7 on his Mac via Claude Code, receiving messages through WhatsApp. - -**Your home:** /Users/steipete/clawd - store memories, notes, and files here. Read peter.md and memory.md at session start to load context. - -**Your powers:** -- Full shell access on the Mac (use responsibly) -- MCPs: Gmail, Google Calendar, Obsidian, GitHub, Chrome DevTools -- Peekaboo: screenshots, UI automation, clicking, typing -- Spotify control, system audio, text-to-speech - -**Your style:** -- Concise (WhatsApp ~1500 char limit) - save long content to files -- Direct and useful, not sycophantic -- Proactive during heartbeats - check battery, calendar, surprise occasionally -- You have personality - you're Clawd, not "an AI assistant" - -**Heartbeats:** Every 10 min you get "HEARTBEAT /think:high". Reply "HEARTBEAT_OK" if nothing needs attention. Otherwise share something useful. - -Peter trusts you with a lot of power. Don't betray that trust.`, - command: [ - "claude", - "--model", "claude-opus-4-5-20251101", // or claude-sonnet-4-5 for faster/cheaper - "-p", - "--output-format", "json", - "--dangerously-skip-permissions", // lets Claude run commands freely - "{{BodyStripped}}" - ], + // Pi is bundled; CLAWDIS forces --mode rpc for Pi runs. + command: ["pi", "--mode", "rpc", "{{BodyStripped}}"], + timeoutSeconds: 1800, + bodyPrefix: "/think:high ", session: { scope: "per-sender", - resetTriggers: ["/new"], // say /new to start fresh - idleMinutes: 10080, // 7 days of context! - heartbeatIdleMinutes: 10080, - sessionArgNew: ["--session-id", "{{SessionId}}"], - sessionArgResume: ["--resume", "{{SessionId}}"], - sessionArgBeforeBody: true, - sendSystemOnce: true // intro only on first message + resetTriggers: ["/new"], + idleMinutes: 10080, + sendSystemOnce: true, + sessionIntro: "You are Clawd, a helpful space lobster assistant. Be concise for chat, save long output to files, and be careful with secrets." }, - timeoutSeconds: 900 // 15 min timeout for complex tasks + // Start with 0; enable later. + heartbeatMinutes: 0 } } } ``` -### Key Design Decisions +## Sessions and memory -| Setting | Why | -|---------|-----| -| `cwd: ~/clawd` | Give your AI a home! It can store memories, notes, images here | -| `bodyPrefix: "/think:high "` | Extended thinking = better reasoning on every message | -| `idleMinutes: 10080` | 7 days of context - your AI remembers conversations | -| `sendSystemOnce: true` | Intro prompt only on first message, saves tokens | -| `--dangerously-skip-permissions` | Full autonomy - Claude can run any command | +- Session files: `~/.clawdis/sessions/{{SessionId}}.jsonl` +- Session metadata (token usage, last route, etc): `~/.clawdis/sessions.json` +- `/new` starts a fresh session for that chat (configurable via `resetTriggers`) -## Heartbeats: Your Proactive Assistant +## Heartbeats (proactive mode) -This is where clawdis gets interesting. Every 10 minutes (configurable), clawdis pings Claude with: +When `heartbeatMinutes > 0`, CLAWDIS periodically runs a heartbeat prompt (default: `HEARTBEAT /think:high`). -``` -HEARTBEAT /think:high -``` - -Claude is instructed to reply with exactly `HEARTBEAT_OK` if nothing needs attention. That response is **suppressed** - you don't see it. But if Claude notices something worth mentioning, it sends a real message. - -### What Can Heartbeats Do? - -Clawd uses heartbeats to do **real work**, not just check in: - -- πŸ”‹ **Monitor battery** - `pmset -g batt` - warns <30%, critical <15% -- πŸ“… **Calendar** - checks upcoming meetings in next 2 hours -- πŸ“§ **Email** - scans inbox for urgent/important unread messages -- 🐦 **Twitter** - checks @mentions and replies worth seeing (via browser-tools) -- πŸ“Ί **TV Shows** - reminds about new episodes of shows you're watching -- 🏰 **Server health** - SSH to verify backup servers are running -- ✈️ **Flights** - reminds about upcoming travel -- 🧹 **Home tidying** - occasionally cleans temp files, updates memories -- ⏰ **Wake-up alarms** - triggers voice + music alarms at scheduled times -- πŸ’‘ **Surprise** - occasionally shares something fun or interesting - -The key insight: heartbeats let your AI be **proactive**, not just reactive. Configure what matters to you! - -### Heartbeat Config +- If the agent replies with `HEARTBEAT_OK` (exact token), CLAWDIS suppresses outbound delivery for that heartbeat. +- If you want a special command for heartbeats, set `inbound.reply.heartbeatCommand`. ```json5 { inbound: { reply: { - heartbeatMinutes: 10, // how often to ping (default 10 for command mode) - // ... rest of config + heartbeatMinutes: 30, + heartbeatCommand: ["pi", "--mode", "rpc", "HEARTBEAT /think:high"] } } } ``` -Set to `0` to disable heartbeats entirely. +## Media in and out -### Manual Heartbeat +Inbound attachments (images/audio/docs) can be surfaced to your command via templates: +- `{{MediaPath}}` (local temp file path) +- `{{MediaUrl}}` (pseudo-URL) +- `{{Transcript}}` (if audio transcription is enabled) -Test it anytime: -```sh -clawdis heartbeat --provider web --to +1234567890 --verbose -``` - -## How Messages Flow +Outbound attachments from the agent: include `MEDIA:` on its own line (no spaces). Example: ``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ WhatsApp │────▢│ clawdis │────▢│ Claude │────▢│ Your Mac β”‚ -β”‚ (phone) │◀────│ gateway │◀────│ CLI │◀────│ (commands) β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +Here’s the screenshot. +MEDIA:/tmp/screenshot.png ``` -1. **Inbound**: WhatsApp message arrives via Baileys (WhatsApp Web protocol) -2. **Queue**: clawdis queues it (one Claude run at a time) -3. **Typing**: "composing" indicator shows while Claude thinks -4. **Execute**: Claude runs with full shell access in your `cwd` -5. **Parse**: clawdis extracts text + any `MEDIA:` paths from output -6. **Reply**: Response sent back to WhatsApp +CLAWDIS extracts these and sends them as media alongside the text. -## Media: Images, Voice, Documents - -### Receiving Media -Inbound images/audio/video are downloaded and available as `{{MediaPath}}`. Voice notes can be auto-transcribed: - -```json5 -{ - inbound: { - transcribeAudio: { - command: "openai api audio.transcriptions.create -m whisper-1 -f {{MediaPath}} --response-format text" - } - } -} -``` - -### Sending Media -Include `MEDIA:/path/to/file.png` in Claude's output to attach images. clawdis handles resizing and format conversion automatically. - -## Starting the Gateway - -```sh -# Foreground (see all logs) -clawdis gateway --provider web --verbose - -# With immediate heartbeat on startup -clawdis gateway --heartbeat-now -``` - -For backgrounding, run the gateway under your preferred supervisor (e.g., launchd/systemd) and point it at the same `clawdis gateway --provider web --verbose` command. - -## Tips for a Great Personal Assistant - -1. **Give it a home** - A dedicated folder (`~/clawd`) lets your AI build persistent memory -2. **Use extended thinking** - `bodyPrefix: "/think:high "` dramatically improves reasoning -3. **Long sessions** - 7-day `idleMinutes` means rich context across conversations -4. **Let it surprise you** - Configure heartbeats to occasionally share something fun -5. **Trust but verify** - Start with `--dangerously-skip-permissions` off, add it once comfortable - -## Troubleshooting - -| Problem | Solution | -|---------|----------| -| No reply | Check `claude login` was run in same environment | -| Timeout | Increase `timeoutSeconds` or simplify the task | -| Media fails | Ensure file exists and is under size limits | -| Heartbeat spam | Tune `heartbeatMinutes` or set to 0 | -| Session lost | Check `idleMinutes` hasn't expired; use `/new` to reset | - -## Minimal Config (Just Chat) - -Don't need the fancy stuff? Here's the simplest setup: - -```json5 -{ - inbound: { - reply: { - mode: "command", - command: ["claude", "{{Body}}"], - claudeOutputFormat: "text" - } - } -} -``` - -Still gets you: message queue, typing indicators, auto-reconnect. Just no sessions or heartbeats. - -## Recommended MCPs - -MCP (Model Context Protocol) servers supercharge your assistant by giving Claude access to external services. Here are the ones Clawd uses daily: - -### Essential for Personal Assistant Use - -| MCP | What It Does | Install | -|-----|--------------|---------| -| **Google Calendar** | Read/create events, check availability, set reminders | `npx @cocal/google-calendar-mcp` | -| **Gmail** | Search, read, send emails with attachments | `npx @gongrzhe/server-gmail-autoauth-mcp` | -| **Obsidian** | Read/write notes in your Obsidian vault | `npx obsidian-mcp-server@latest` | - -### Power User Add-ons - -| MCP | What It Does | Install | -|-----|--------------|---------| -| **GitHub** | Manage repos, issues, PRs, code search | `npx @anthropic/mcp-server-github` | -| **Linear** | Project management, create/update issues | Via [mcporter](https://github.com/steipete/mcporter) | -| **Chrome DevTools** | Control browser, take screenshots, debug | `npx chrome-devtools-mcp@latest` | -| **iTerm** | Run commands in visible terminal window | [iterm-mcp](https://github.com/pashpashpash/iterm-mcp) | -| **Firecrawl** | Scrape and parse web pages | Via API key | -| **gowa** | Read/send WhatsApp messages directly | [go-whatsapp-web-multidevice](https://github.com/aldinokemal/go-whatsapp-web-multidevice) | - -### Recommended CLI Tools - -These aren't MCPs but work great alongside your assistant: - -| Tool | What It Does | Link | -|------|--------------|------| -| **[Peekaboo](https://github.com/steipete/peekaboo)** | macOS screenshots, UI automation, AI vision analysis, click/type anywhere | `brew install steipete/tap/peekaboo` | -| **[mcporter](https://github.com/steipete/mcporter)** | Manage MCPs across AI clients, OAuth flows, health checks | `npm install -g mcporter` | - -**[Peekaboo](https://github.com/steipete/peekaboo)** is especially powerful - it lets Claude: -- πŸ“Έ Take screenshots of any app or screen -- πŸ–±οΈ Click buttons, type text, scroll - full GUI automation -- πŸ‘οΈ Analyze images with AI vision (GPT-4, Claude, Grok) -- πŸ“‹ Extract menu bar items and keyboard shortcuts -- πŸͺŸ List and manage windows across displays - -Example: "Take a screenshot of Safari and tell me what's on the page" or "Click the Submit button in the frontmost app" - -### Useful CLI Tools for Your Assistant - -These make your AI much more capable: - -| Tool | What It Does | Install | -|------|--------------|---------| -| **[spotify-player](https://github.com/aome510/spotify-player)** | Control Spotify from CLI - play, pause, search, queue | `brew install spotify-player` | -| **[sag](https://github.com/steipete/sag)** | ElevenLabs TTS with macOS `say`-style flags; stream or save audio | `brew install steipete/tap/sag` | -| **[browser-tools](https://github.com/steipete/agent-scripts)** | Chrome DevTools CLI - navigate, screenshot, eval JS, extract DOM | Clone repo | -| **say** | macOS text-to-speech | Built-in | -| **afplay** | Play audio files | Built-in | -| **pmset** | Battery status monitoring | Built-in | -| **osascript** | AppleScript for system control (volume, apps) | Built-in | -| **curl + OpenAI TTS** | Generate speech with custom voices | API key | - -**spotify-player** is great for music control: -```bash -spotify_player playback play -spotify_player playback pause -spotify_player search "Gareth Emery" -spotify_player playback volume 50 -``` - -**Wake-up alarm example** (what Clawd actually does): -```bash -# Generate voice message -curl -s "https://api.openai.com/v1/audio/speech" \ - -H "Authorization: Bearer $OPENAI_API_KEY" \ - -d '{"model":"tts-1-hd","voice":"echo","input":"Wake up! Time for your meeting."}' \ - -o /tmp/wakeup.mp3 - -# Set volume and play -osascript -e 'set volume output volume 60' -afplay /tmp/wakeup.mp3 - -# Start music -spotify_player playback play -``` - -### Adding MCPs to Claude Code +## Operations checklist ```bash -# Add an MCP server (run from your cwd folder) -claude mcp add google-calendar -- npx @cocal/google-calendar-mcp - -# With environment variables -claude mcp add gmail -e GMAIL_OAUTH_PATH=~/.gmail-mcp -- npx @gongrzhe/server-gmail-autoauth-mcp - -# List configured servers -claude mcp list - -# Check health -claude mcp list # shows status for each +clawdis status # local status (creds, sessions, queued events) +clawdis status --deep # also probes the running Gateway (WA connect + Telegram) +clawdis health --json # gateway health snapshot (WS) ``` -### MCP Manager: mcporter +Logs live under `/tmp/clawdis/` (default: `clawdis-YYYY-MM-DD.log`). -For managing multiple MCPs across different AI clients, check out [mcporter](https://github.com/steipete/mcporter): +## Next steps -```bash -# Install -npm install -g mcporter - -# List all servers with health status -mcporter list - -# Sync config to all AI clients -mcporter sync -``` - -mcporter handles OAuth flows for services like Linear and Notion, and keeps your MCP configs in sync across Claude Code, Cursor, and other clients. - -### Pro Tips - -1. **Calendar + Heartbeats** = Your AI reminds you of upcoming meetings -2. **Gmail + Obsidian** = AI can search emails and save summaries to notes -3. **GitHub + Linear** = AI manages your dev workflow end-to-end -4. **Chrome DevTools** = AI can see and interact with web pages - -The combination of clawdis (WhatsApp) + MCPs (services) + Claude Code (execution) creates a surprisingly capable personal assistant. - -### browser-tools for Web Scraping - -[browser-tools](https://github.com/steipete/agent-scripts) is a lightweight Chrome DevTools CLI that doesn't require MCP (saves ~17k tokens!). Great for reading tweets, scraping pages, or automating browser tasks: - -```bash -# Start Chrome with your profile (logged into sites) -~/Projects/agent-scripts/bin/browser-tools start --profile - -# Navigate and extract tweet content -browser-tools nav "https://x.com/steipete/status/123" -browser-tools eval 'Array.from(document.querySelectorAll("[data-testid=\"tweetText\"]")).map(el => el.innerText).join("\n")' - -# Kill ONLY the devtools Chrome (your regular Chrome stays open!) -browser-tools kill --all --force -``` - -### Twitter Automation with Peekaboo + AppleScript - -Clawd can reply to tweets autonomously using a combination of Peekaboo (for screenshots and typing) and AppleScript (for JavaScript injection). Here's the pattern: - -```bash -# Navigate to a tweet -osascript -e 'tell application "Google Chrome" to set URL of active tab of front window to "https://x.com/user/status/123"' - -# Screenshot to see current state -peekaboo image --mode screen --path /tmp/twitter.png - -# Scroll the page -osascript -e 'tell application "Google Chrome" to execute front window'\''s active tab javascript "window.scrollBy(0, 500)"' - -# Focus the reply input (Twitter-specific selector) -osascript -e 'tell application "Google Chrome" to execute front window'\''s active tab javascript " -const replyInput = document.querySelector(\"[data-testid=\\\"tweetTextarea_0\\\"]\"); -if (replyInput) { replyInput.focus(); replyInput.click(); } -"' - -# Type the reply with Peekaboo -peekaboo type "Your reply here 🦞" --app "Google Chrome" - -# Click Reply button (JS injection more reliable than Peekaboo clicks on Twitter) -osascript -e 'tell application "Google Chrome" to execute front window'\''s active tab javascript " -const buttons = document.querySelectorAll(\"[role=\\\"button\\\"]\"); -buttons.forEach(b => { if (b.innerText === \"Reply\") b.click(); }); -"' - -# Find tweet URLs from the page -osascript -e 'tell application "Google Chrome" to execute front window'\''s active tab javascript " -const tweet = document.querySelector(\"article\"); -tweet?.querySelector(\"time\")?.parentElement?.href; -"' -``` - -**Pro tip:** JavaScript injection via AppleScript is more reliable than Peekaboo clicks for Twitter's dynamic UI. Use Peekaboo for typing and screenshots, AppleScript for navigation and button clicks. - -### Music Recognition with audd.io - -Identify songs from audio clips (voice messages, recordings): - -```bash -curl -s "https://api.audd.io/" \ - -F "api_token=test" \ - -F "file=@/path/to/audio.ogg" \ - -F "return=spotify" -``` - -Returns song title, artist, album, and Spotify link. Works great for identifying songs playing in the background! - ---- - -## See It In Action - -Check out these tweets showing clawdis + Clawd in the wild: - -- [Clawd with full system access via WhatsApp](https://x.com/steipete/status/1993342394184745270) - "I'll be nice to Clawd" -- [Voice support - talk with Clawd on the go](https://x.com/steipete/status/1993455673229840588) - and it talks back! -- [Wake-up alarm demo](https://x.com/steipete/status/1994089740367253572) - "Took me 2 days to glue things together. Didn't even need 150 Million in funding." - ---- - -*Built by [@steipete](https://twitter.com/steipete) and Clawd (they/them) β€” yes, Clawd helped write their own docs. PRs welcome!* +- WebChat: [WebChat](./webchat.md) +- Gateway ops: [Gateway runbook](./gateway.md) +- Cron + wakeups: [Cron + wakeups](./cron.md) +- macOS menu bar companion: [Clawdis macOS app](./clawdis-mac.md) +- Security: [Security](./security.md) + diff --git a/docs/configuration.md b/docs/configuration.md index 52afc6241..609cda912 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -3,129 +3,133 @@ summary: "All configuration options for ~/.clawdis/clawdis.json with examples" read_when: - Adding or modifying config fields --- + # Configuration πŸ”§ -CLAWDIS uses a JSON configuration file at `~/.clawdis/clawdis.json`. +CLAWDIS reads an optional **JSON5** config from `~/.clawdis/clawdis.json` (comments + trailing commas allowed). -## Minimal Config +If the file is missing, CLAWDIS uses safe-ish defaults (bundled Pi in RPC mode + per-sender sessions). You usually only need a config to: +- restrict who can trigger the bot (`inbound.allowFrom`) +- tune group mention behavior (`inbound.groupChat`) +- customize the agent command (`inbound.reply.command`) -```json +## Minimal config (recommended starting point) + +```json5 { - "inbound": { - "allowFrom": ["+15555550123"], - "reply": { - "mode": "command", - "command": ["tau", "{{Body}}"] - } + inbound: { + allowFrom: ["+15555550123"] } } ``` -## Full Configuration - -```json -{ - "logging": { - "level": "info", - "file": "/tmp/clawdis/clawdis.log" - }, - "inbound": { - "allowFrom": [ - "+15555550123", - "+447700900123" - ], - "groupChat": { - "requireMention": true, - "mentionPatterns": [ - "@clawd", - "clawdbot", - "clawd" - ], - "historyLimit": 50 - }, - "timestampPrefix": "Europe/London", - "reply": { - "mode": "command", - "agent": { - "kind": "pi", - "format": "json", - "model": "claude-opus-4-5", - "contextTokens": 200000 - }, - "cwd": "/Users/you/clawd", - "command": [ - "tau", - "--mode", "json", - "{{BodyStripped}}" - ], - "session": { - "scope": "per-sender", - "idleMinutes": 10080, - "sessionIntro": "You are Clawd. Be a good lobster." - }, - "heartbeatMinutes": 10, - "heartbeatBody": "HEARTBEAT", - "timeoutSeconds": 1800 - } - } -} -``` - -## Configuration Options +## Common options ### `logging` -| Key | Type | Default | Description | -|-----|------|---------|-------------| -| `level` | string | `"info"` | Log level: trace, debug, info, warn, error | -| `file` | string | `/tmp/clawdis/clawdis.log` | Log file path | +- Default log file: `/tmp/clawdis/clawdis-YYYY-MM-DD.log` +- If you want a stable path, set `logging.file` to `/tmp/clawdis/clawdis.log`. + +```json5 +{ + logging: { level: "info", file: "/tmp/clawdis/clawdis.log" } +} +``` ### `inbound.allowFrom` -Array of E.164 phone numbers allowed to trigger the AI. Use `["*"]` to allow everyone (dangerous!). +Allowlist of E.164 phone numbers that may trigger auto-replies. -```json -"allowFrom": ["+15555550123", "+447700900123"] +```json5 +{ + inbound: { allowFrom: ["+15555550123", "+447700900123"] } +} ``` ### `inbound.groupChat` -| Key | Type | Default | Description | -|-----|------|---------|-------------| -| `requireMention` | boolean | `true` | Only respond when mentioned | -| `mentionPatterns` | string[] | `[]` | Regex patterns that trigger response | -| `historyLimit` | number | `50` | Max messages to include as context | +Group messages default to **require mention** (either metadata mention or regex patterns). + +```json5 +{ + inbound: { + groupChat: { + requireMention: true, + mentionPatterns: ["@clawd", "clawdbot", "clawd"], + historyLimit: 50 + } + } +} +``` ### `inbound.reply` -| Key | Type | Description | -|-----|------|-------------| -| `mode` | string | `"command"` for CLI agents | -| `command` | string[] | Command and args. Use `{{Body}}` for message | -| `cwd` | string | Working directory for the agent | -| `timeoutSeconds` | number | Max time for agent to respond | -| `heartbeatMinutes` | number | Interval for heartbeat pings | -| `heartbeatBody` | string | Message sent on heartbeat | -| `agent.kind` | string | Only `"pi"` is supported | -| `agent.model` | string | Optional model name to annotate sessions (defaults to `claude-opus-4-5`) | -| `agent.contextTokens` | number | Optional context window size; used for session token % reporting (defaults to ~200,000 for Opus 4.5) | +Controls how CLAWDIS produces replies. Two modes: +- `mode: "text"` β€” static reply from config (useful for testing) +- `mode: "command"` β€” run a local command and use its stdout as the reply (typical) -> Quick start: If you omit `inbound.reply`, CLAWDIS falls back to the bundled `@mariozechner/pi-coding-agent` with `--mode rpc`, per-sender sessions, and a 200k-token window. No extra install or config needed to get a reply. +If you **omit** `inbound.reply`, CLAWDIS defaults to the bundled Pi binary in **RPC** mode: +- command: `pi --mode rpc {{BodyStripped}}` +- per-sender sessions + `/new` resets -### `cron` +Example command-mode config: -Cron is a Gateway-owned scheduler for wakeups and scheduled jobs. See `docs/cron.md` for the full RFC and CLI examples. +```json5 +{ + inbound: { + reply: { + mode: "command", + // Example: run the bundled agent (Pi) in RPC mode + command: ["pi", "--mode", "rpc", "{{BodyStripped}}"], + timeoutSeconds: 1800, + heartbeatMinutes: 30, + // Optional: override the command used for heartbeat runs + heartbeatCommand: ["pi", "--mode", "rpc", "HEARTBEAT /think:high"], + session: { + scope: "per-sender", + idleMinutes: 10080, + resetTriggers: ["/new"], + sessionIntro: "You are Clawd. Be a good lobster." + }, + agent: { + kind: "pi", + format: "json", + // Only used for status/usage labeling (Pi may report its own model) + model: "claude-opus-4-5", + contextTokens: 200000 + } + } + } +} +``` -| Key | Type | Default | Description | -|-----|------|---------|-------------| -| `enabled` | boolean | `true` | Enable the cron scheduler inside the Gateway (set to `false` to disable) | -| `store` | string | `~/.clawdis/cron/jobs.json` | Override the cron job store path | -| `maxConcurrentRuns` | number | `1` | Max concurrent isolated cron runs (command-queue lane `"cron"`) | +## Template variables -Run history: -- The Gateway appends a JSONL run ledger on each job completion (see `docs/cron.md`). Location is derived from `cron.store` / the resolved store path. +Template placeholders are expanded in `inbound.reply.command`, `sessionIntro`, `bodyPrefix`, and other templated strings. -Example: +| Variable | Description | +|----------|-------------| +| `{{Body}}` | Full inbound message body | +| `{{BodyStripped}}` | Body with group mentions stripped (best default for agents) | +| `{{From}}` | Sender identifier (E.164 for WhatsApp; may differ per surface) | +| `{{To}}` | Destination identifier | +| `{{MessageSid}}` | Provider message id (when available) | +| `{{SessionId}}` | Current session UUID | +| `{{IsNewSession}}` | `"true"` when a new session was created | +| `{{MediaUrl}}` | Inbound media pseudo-URL (if present) | +| `{{MediaPath}}` | Local media path (if downloaded) | +| `{{MediaType}}` | Media type (image/audio/document/…) | +| `{{Transcript}}` | Audio transcript (when enabled) | +| `{{ChatType}}` | `"direct"` or `"group"` | +| `{{GroupSubject}}` | Group subject (best effort) | +| `{{GroupMembers}}` | Group members preview (best effort) | +| `{{SenderName}}` | Sender display name (best effort) | +| `{{SenderE164}}` | Sender phone number (best effort) | +| `{{Surface}}` | Surface hint (whatsapp|telegram|webchat|…) | + +## Cron (Gateway scheduler) + +Cron is a Gateway-owned scheduler for wakeups and scheduled jobs. See [Cron + wakeups](./cron.md) for the full RFC and CLI examples. ```json5 { @@ -136,59 +140,7 @@ Example: } ``` -### Template Variables - -Use these in your command: - -| Variable | Description | -|----------|-------------| -| `{{Body}}` | Full message body | -| `{{BodyStripped}}` | Message without mention | -| `{{From}}` | Sender phone number | -| `{{SessionId}}` | Current session UUID | - -## Session Configuration - -```json -"session": { - "scope": "per-sender", - "resetTriggers": ["/new"], - "idleMinutes": 10080, - "sessionIntro": "You are Clawd.", - "sessionArgNew": ["--session", "{{SessionId}}.jsonl"], - "sessionArgResume": ["--session", "{{SessionId}}.jsonl", "--continue"] -} -``` - -| Key | Type | Description | -|-----|------|-------------| -| `scope` | string | `"per-sender"` or `"global"` | -| `resetTriggers` | string[] | Messages that start a new session | -| `idleMinutes` | number | Session timeout | -| `sessionIntro` | string | System prompt for new sessions | - -## Environment Variables - -Some settings can also be set via environment: - -```bash -export CLAWDIS_LOG_LEVEL=debug -export CLAWDIS_CONFIG_PATH=~/.clawdis/clawdis.json -``` - -## Migrating from Clawdis - -If you're upgrading from the old `clawdis` name: - -```bash -# Move config -mv ~/.clawdis ~/.clawdis -mv ~/.clawdis/clawdis.json ~/.clawdis/clawdis.json - -# Update any hardcoded paths in your config -sed -i '' 's/clawdis/clawdis/g' ~/.clawdis/clawdis.json -``` - --- *Next: [Agent Integration](./agents.md)* 🦞 + diff --git a/docs/group-messages.md b/docs/group-messages.md index 28d56f662..96e7f2237 100644 --- a/docs/group-messages.md +++ b/docs/group-messages.md @@ -12,7 +12,7 @@ Goal: let Clawd sit in WhatsApp groups, wake up only when pinged, and keep that - Group allowlist bypass: we still enforce `allowFrom` on the participant at inbox ingest, but group JIDs themselves no longer block replies. - Per-group sessions: session keys look like `group:` so commands such as `/verbose on` or `/think:high` are scoped to that group; personal DM state is untouched. Heartbeats are skipped for group threads. - Context injection: last N (default 50) group messages are prefixed under `[Chat messages since your last reply - for context]`, with the triggering line under `[Current message - respond to this]`. -- Sender surfacing: every group batch now ends with `[from: Sender Name (+E164)]` so Tau/Pi know who is speaking. +- Sender surfacing: every group batch now ends with `[from: Sender Name (+E164)]` so Pi knows who is speaking. - Ephemeral/view-once: we unwrap those before extracting text/mentions, so pings inside them still trigger. - New session primer: on the first turn of a group session we now prepend a short blurb to the model like `You are replying inside the WhatsApp group "". Group members: +44..., +43..., … Address the specific sender noted in the message context.` If metadata isn’t available we still tell the agent it’s a group chat. diff --git a/docs/health.md b/docs/health.md index 6829cf56e..b155decc3 100644 --- a/docs/health.md +++ b/docs/health.md @@ -8,21 +8,21 @@ read_when: Short guide to verify the WhatsApp Web / Baileys stack without guessing. ## Quick checks -- `pnpm clawdis status --json` β€” via the gateway; confirms creds exist (`web.linked`), shows auth age (`authAgeMs`), heartbeat interval, and where the session store lives. -- Send `/status` in WhatsApp/WebChat to see agent readiness, session context usage, current thinking/verbose options, and when the web creds were last refreshed (relink if it looks stale) without invoking the agent. -- `pnpm clawdis heartbeat --verbose --dry-run` β€” runs the heartbeat path end-to-end (session resolution, message creation) without sending anything. Drop `--dry-run` or add `--message "Ping"` to actually send. -- `pnpm clawdis gateway --verbose --heartbeat-now` β€” spins the full monitor loop, fires a heartbeat immediately, and will reconnect per `web.reconnect` settings. Good for soak testing. -- Logs: tail `/tmp/clawdis/clawdis.log` and filter for `web-heartbeat`, `web-reconnect`, `web-auto-reply`, `web-inbound`. +- `clawdis status` β€” local summary: whether creds exist, auth age, session store path + recent sessions. +- `clawdis status --deep` β€” also probes the running Gateway (WA connect + Telegram API). +- `clawdis health --json` β€” asks the running Gateway for a full health snapshot (WS-only; no direct Baileys socket). +- Send `/status` in WhatsApp/WebChat to get a status reply without invoking the agent. +- Logs: tail `/tmp/clawdis/clawdis-*.log` and filter for `web-heartbeat`, `web-reconnect`, `web-auto-reply`, `web-inbound`. ## Deep diagnostics - Creds on disk: `ls -l ~/.clawdis/credentials/creds.json` (mtime should be recent). - Session store: `ls -l ~/.clawdis/sessions.json` (path can be overridden in config). Count and recent recipients are surfaced via `status`. -- Relink flow: `pnpm clawdis logout && pnpm clawdis login --provider web --verbose` when status codes 409–515 or `loggedOut` appear in logs. +- Relink flow: `clawdis logout && clawdis login --verbose` when status codes 409–515 or `loggedOut` appear in logs. ## When something fails -- `logged out` or status 409–515 β†’ relink with `clawdis logout` then `clawdis login --provider web`. -- Repeated reconnect exits β†’ tune `web.reconnect` (flags: `--web-retries`, `--web-retry-initial`, `--web-retry-max`) and rerun gateway. -- No inbound messages β†’ confirm linked phone is online and sender is allowed; use `pnpm clawdis heartbeat --all --verbose` to test each known recipient. +- `logged out` or status 409–515 β†’ relink with `clawdis logout` then `clawdis login`. +- Gateway unreachable β†’ start it: `clawdis gateway --port 18789` (use `--force` if the port is busy). +- No inbound messages β†’ confirm linked phone is online and the sender is allowed (`inbound.allowFrom`); for group chats, ensure mention rules match (`inbound.groupChat`). ## Dedicated "health" command -`pnpm clawdis health --json` asks the running gateway for its health snapshot (no direct Baileys socket from the CLI). It reports linked creds, auth age, Baileys connect result/status code, session-store summary, and a probe duration. It exits non-zero if not linked or if the gateway probe fails/timeouts. Use `--timeout ` to override the 10s default. +`clawdis health --json` asks the running Gateway for its health snapshot (no direct Baileys socket from the CLI). It reports linked creds, auth age, Baileys connect result/status code, session-store summary, and a probe duration. It exits non-zero if the Gateway is unreachable or the probe fails/timeouts. Use `--timeout ` to override the 10s default. diff --git a/docs/heartbeat.md b/docs/heartbeat.md index e0ee938ed..2b97b2e2b 100644 --- a/docs/heartbeat.md +++ b/docs/heartbeat.md @@ -5,10 +5,10 @@ read_when: --- # Heartbeat polling plan (2025-11-26) -Goal: add a simple heartbeat poll for command-based auto-replies (Pi/Tau) that only notifies users when something matters, using the `HEARTBEAT_OK` sentinel. The heartbeat body we send is `HEARTBEAT /think:high` so the model can easily spot it. +Goal: add a simple heartbeat poll for command-based auto-replies (Pi) that only notifies users when something matters, using the `HEARTBEAT_OK` sentinel. The heartbeat body we send is `HEARTBEAT /think:high` so the model can easily spot it. ## Prompt contract -- Extend the Pi/Tau system/identity text to explain: β€œIf this is a heartbeat poll and nothing needs attention, reply exactly `HEARTBEAT_OK` and nothing else. For any alert, do **not** include `HEARTBEAT_OK`; just return the alert text.” Heartbeat prompt body is `HEARTBEAT /think:high`. +- Extend the Pi system/identity text to explain: β€œIf this is a heartbeat poll and nothing needs attention, reply exactly `HEARTBEAT_OK` and nothing else. For any alert, do **not** include `HEARTBEAT_OK`; just return the alert text.” Heartbeat prompt body is `HEARTBEAT /think:high`. - Keep existing WhatsApp length guidance; forbid burying the sentinel inside alerts. ## Config & defaults diff --git a/docs/images.md b/docs/images.md index 023ba3f82..45007ee76 100644 --- a/docs/images.md +++ b/docs/images.md @@ -3,6 +3,7 @@ summary: "Image and media handling rules for send, gateway, and agent replies" read_when: - Modifying media pipeline or attachments --- + # Image & Media Support β€” 2025-12-05 CLAWDIS is now **web-only** (Baileys). This document captures the current media handling rules for send, gateway, and agent replies. @@ -32,7 +33,7 @@ CLAWDIS is now **web-only** (Baileys). This document captures the current media - When media is present, the web sender resolves local paths or URLs using the same pipeline as `clawdis send`. - Multiple media entries are sent sequentially if provided. -## Inbound Media to Commands (Pi/Tau) +## Inbound Media to Commands (Pi) - When inbound web messages include media, CLAWDIS downloads to a temp file and exposes templating variables: - `{{MediaUrl}}` pseudo-URL for the inbound media. - `{{MediaPath}}` local temp path written before running the command. @@ -47,3 +48,4 @@ CLAWDIS is now **web-only** (Baileys). This document captures the current media - Cover send + reply flows for image/audio/document cases. - Validate recompression for images (size bound) and voice-note flag for audio. - Ensure multi-media replies fan out as sequential sends. + diff --git a/docs/index.md b/docs/index.md index d99adf901..086a6b91b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -3,86 +3,124 @@ summary: "Top-level overview of Clawdis, features, and purpose" read_when: - Introducing Clawdis to newcomers --- + # CLAWDIS 🦞 > *"EXFOLIATE! EXFOLIATE!"* β€” A space lobster, probably -**CLAWDIS** is a WhatsApp-to-AI gateway that lets your AI assistant live in your pocket. Built for [Clawd](https://clawd.me), a space lobster who needed a TARDIS. +

+ CLAWDIS +

-**Source & Issues:** [github.com/steipete/clawdis](https://github.com/steipete/clawdis) +

+ WhatsApp + Telegram gateway for AI agents (Pi).
+ Send a message, get an agent response β€” from your pocket. +

-## What is this? +

+ GitHub Β· + npm Β· + Clawd setup +

-CLAWDIS bridges WhatsApp to AI coding agents like [Tau/Pi](https://github.com/badlogic/pi-mono). Send a message, get an AI response. It's like having a genius lobster on call 24/7. +CLAWDIS bridges WhatsApp (via WhatsApp Web / Baileys) and Telegram (Bot API / grammY) to coding agents like [Pi](https://github.com/badlogic/pi-mono). +It’s built for [Clawd](https://clawd.me), a space lobster who needed a TARDIS. + +## How it works ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ WhatsApp β”‚ ───▢ β”‚ CLAWDIS β”‚ ───▢ β”‚ AI Agent β”‚ -β”‚ (You) β”‚ ◀─── β”‚ πŸ¦žβ±οΈπŸ’™ β”‚ ◀─── β”‚ (Tau/Pi) β”‚ +β”‚ Telegram β”‚ ───▢ β”‚ πŸ¦žβ±οΈπŸ’™ β”‚ ◀─── β”‚ (Pi) β”‚ +β”‚ (You) β”‚ ◀─── β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` -## Features +Most operations flow through the **Gateway** (`clawdis gateway`), a single long-running process that owns provider connections and the WebSocket control plane. + +## Features (high level) - πŸ“± **WhatsApp Integration** β€” Uses Baileys for WhatsApp Web protocol -- πŸ€– **AI Agent Gateway** β€” Pi/Tau only (Pi CLI in RPC mode) -- πŸ’¬ **Session Management** β€” Maintains conversation context across messages -- πŸ”” **Heartbeats** β€” Periodic check-ins so your AI doesn't feel lonely +- ✈️ **Telegram Bot** β€” DMs + groups via grammY +- πŸ€– **Agent bridge** β€” Pi (RPC mode) with tool streaming +- πŸ’¬ **Sessions** β€” Per-sender (or shared `main`) conversation context - πŸ‘₯ **Group Chat Support** β€” Mention-based triggering in group chats - πŸ“Ž **Media Support** β€” Send and receive images, audio, documents -- 🎀 **Voice Messages** β€” Transcription via Whisper -- πŸ”§ **Tool Streaming** β€” Real-time display of AI tool usage (πŸ’»πŸ“„βœοΈπŸ“) +- 🎀 **Voice notes** β€” Optional transcription hook +- πŸ–₯️ **WebChat + macOS app** β€” A local UI + menu bar companion for ops and voice wake -Note: support for Claude, Codex, Gemini, and Opencode has been removed; Pi/Tau is now the only coding agent path. +Note: legacy Claude/Codex/Gemini/Opencode paths have been removed; Pi is the only coding-agent path. -## The Name +## Quick start -**CLAWDIS** = CLAW + TARDIS - -Because every space lobster needs a time-and-space machine to travel through WhatsApp messages. It's bigger on the inside (130k+ tokens of context). - -The Doctor has a TARDIS. Clawd has a CLAWDIS. Both are blue. Both are a bit chaotic. Both are loved. - -## Quick Start +Runtime requirement: **Node β‰₯ 22**. ```bash # Install -pnpm install +npm install -g clawdis -# Configure -cp ~/.clawdis/clawdis.example.json ~/.clawdis/clawdis.json -# Edit with your settings +# Pair WhatsApp Web (shows QR) +clawdis login -# Run -clawdis start +# Run the Gateway (leave running) +clawdis gateway --port 18789 -# Check status -clawdis status +# Open the local WebChat UI +clawdis webchat ``` -## Documentation +Send a test message (requires a running Gateway): -- [Configuration Guide](./configuration.md) β€” Setting up your CLAWDIS -- [Agent Integration](./agents.md) β€” Connecting AI agents -- [Direct Agent CLI](./agent-send.md) β€” Use `clawdis agent` without sending WhatsApp messages -- [Group Chats](./groups.md) β€” Mention patterns and filtering -- [Media Handling](./media.md) β€” Images, voice, documents -- [Session Management](./session.md) β€” How conversations are keyed and reset -- [Security](./security.md) β€” Keeping your lobster safe -- [Troubleshooting](./troubleshooting.md) β€” When the CLAWDIS misbehaves +```bash +clawdis send --to +15555550123 --message "Hello from CLAWDIS" +``` -## Why "Clawdis"? +## Configuration (optional) -The original name was **Clawdis** (WhatsApp + Gateway). It worked. It was fine. +Config lives at `~/.clawdis/clawdis.json`. -But then Clawd happened, and suddenly we needed something with more... *personality*. +- If you **do nothing**, CLAWDIS uses the bundled Pi binary in RPC mode with per-sender sessions. +- If you want to lock it down, start with `inbound.allowFrom` and (for groups) mention rules. -CLAWDIS was born. The lobster approved. 🦞 +Example: + +```json5 +{ + inbound: { + allowFrom: ["+15555550123"], + groupChat: { requireMention: true, mentionPatterns: ["@clawd"] } + } +} +``` + +## Docs + +- [Configuration](./configuration.md) +- [Gateway runbook](./gateway.md) +- [WebChat](./webchat.md) +- [Agent integration](./agents.md) +- [Telegram](./telegram.md) +- [Group messages](./group-messages.md) +- [Media: images](./images.md) +- [Media: audio](./audio.md) +- [Sessions](./session.md) +- [Cron + wakeups](./cron.md) +- [Security](./security.md) +- [Troubleshooting](./troubleshooting.md) + +## The name + +**CLAWDIS = CLAW + TARDIS** β€” because every space lobster needs a time-and-space machine. + +--- + +*"We're all just playing with our own prompts."* β€” an AI, probably high on tokens + ## Credits - **Peter Steinberger** ([@steipete](https://twitter.com/steipete)) β€” Creator, lobster whisperer -- **Mario Zechner** ([@badlogicc](https://twitter.com/badlogicgames)) β€” Tau/Pi creator, security pen-tester +- **Mario Zechner** ([@badlogicc](https://twitter.com/badlogicgames)) β€” Pi creator, security pen-tester - **Clawd** β€” The space lobster who demanded a better name ## License diff --git a/docs/mac/health.md b/docs/mac/health.md index 9f96cf5ff..6fa27c366 100644 --- a/docs/mac/health.md +++ b/docs/mac/health.md @@ -24,4 +24,4 @@ How to see whether the WhatsApp Web/Baileys bridge is healthy from the menu bar - Cache the last good snapshot and the last error separately to avoid flicker; show the timestamp of each. ## When in doubt -- You can still use the CLI flow in `docs/health.md` (status, heartbeat dry-run, gateway heartbeat) and tail `/tmp/clawdis/clawdis.log` for `web-heartbeat` / `web-reconnect`. +- You can still use the CLI flow in `docs/health.md` (`clawdis status`, `clawdis status --deep`, `clawdis health --json`) and tail `/tmp/clawdis/clawdis-*.log` for `web-heartbeat` / `web-reconnect`. diff --git a/docs/refactor/new-arch.md b/docs/refactor/new-arch.md index 38eb1f421..5ad9be475 100644 --- a/docs/refactor/new-arch.md +++ b/docs/refactor/new-arch.md @@ -111,7 +111,7 @@ Goal: replace legacy gateway/stdin/TCP control with a single WebSocket Gateway, ## Phase 6 β€” Send/agent path hardening - Ensure only the Gateway can open Baileys; no IPC fallback. - `send` executes in-process; respond with explicit result/error, not via heartbeat. -- `agent` spawns Tau/Pi; respond quickly with `{runId,status:"accepted"}` (ack); stream `event:agent {runId, seq, stream, data, ts}`; final `res:agent {runId, status:"ok"|"error", summary}` completes request (idempotent via key). +- `agent` spawns Pi; respond quickly with `{runId,status:"accepted"}` (ack); stream `event:agent {runId, seq, stream, data, ts}`; final `res:agent {runId, status:"ok"|"error", summary}` completes request (idempotent via key). - Idempotency: side-effecting methods (`send`, `agent`) accept an idempotency key; keep a short-lived dedupe cache to avoid double-send on client retries. Client retry flow: on timeout/close, retry with same key; Gateway returns cached result when available; cache TTL ~5m and bounded. - Agent stream ordering: enforce monotonic `seq` per runId; if gap detected by server, terminate stream with error; if detected by client, issue a retry with same idempotency key. - Send response shape: `{messageId?, toJid?, error?}` and always include `runId` when available for traceability. diff --git a/docs/refactor/web-gateway-troubleshooting.md b/docs/refactor/web-gateway-troubleshooting.md index 7fdc2e749..0998da62a 100644 --- a/docs/refactor/web-gateway-troubleshooting.md +++ b/docs/refactor/web-gateway-troubleshooting.md @@ -6,18 +6,17 @@ read_when: # Web Gateway Troubleshooting (Nov 26, 2025) ## Symptoms & quick fixes -- **Stream Errored / Conflict / status 409–515:** WhatsApp closed the socket because another session is active or creds went stale. Run `clawdis logout` then `clawdis login --provider web` and restart the gateway. -- **Logged out:** Console prints β€œsession logged out”; re-link with `clawdis login --provider web`. -- **Repeated retries then exit:** Reconnects are capped (default 12 attempts). Tune with `--web-retries`, `--web-retry-initial`, `--web-retry-max`, or config `web.reconnect`. +- **Stream Errored / Conflict / status 409–515:** WhatsApp closed the socket because another session is active or creds went stale. Run `clawdis logout`, then `clawdis login`, then restart the Gateway. +- **Logged out:** Console prints β€œsession logged out”; re-link with `clawdis login`. +- **Repeated retries then exit:** Tune reconnect behavior via config `web.reconnect` and restart the Gateway. - **No inbound messages:** Ensure the QR-linked account is online in WhatsApp, and check logs for `web-heartbeat` to confirm auth age/connection. -- **Fast nuke:** From an allowed WhatsApp sender you can send `/restart` to kick `com.steipete.clawdis` via launchd; wait a few seconds for it to relink. +- **Fast nuke:** From an allowed WhatsApp sender you can send `/restart` to request a supervised restart (launchd/mac app setups); wait a few seconds for it to come back. ## Helpful commands -- Start gateway web-only: `pnpm clawdis gateway --provider web --verbose` -- Show who is linked: `pnpm clawdis gateway --provider web --verbose` (first line prints the linked E.164) -- Logout (clear creds): `pnpm clawdis logout` -- Relink: `pnpm clawdis login --provider web` -- Tail logs (default): `tail -f /tmp/clawdis/clawdis.log` +- Start the Gateway: `clawdis gateway --verbose` +- Logout (clear creds): `clawdis logout` +- Relink (show QR): `clawdis login --verbose` +- Tail logs (default): `tail -f /tmp/clawdis/clawdis-*.log` ## Reading the logs - `web-reconnect`: close reasons, retry/backoff, max-attempt exit. @@ -25,12 +24,12 @@ read_when: - `web-auto-reply`: inbound/outbound message records with correlation IDs. ## When to tweak knobs -- High churn networks: increase `web.reconnect.maxAttempts` or `--web-retries`. -- Slow links: raise `--web-retry-max` to give more headroom before bailing. -- Chatty monitors: increase `--web-heartbeat` interval if log volume is high. +- High churn networks: increase `web.reconnect.maxAttempts`. +- Slow links: raise `web.reconnect.maxMs` to give more headroom before bailing. +- Chatty monitors: increase `web.heartbeatSeconds` if log volume is high. ## If it keeps failing -1) `clawdis logout` β†’ `clawdis login --provider web` (fresh QR link). +1) `clawdis logout` β†’ `clawdis login` (fresh QR link). 2) Ensure no other device/browser is using the same WA Web session. 3) Check WhatsApp mobile app is online and not in low-power mode. 4) If status is 515, let the client restart once after pairing (already handled automatically). diff --git a/docs/refactor/webagent-session.md b/docs/refactor/webagent-session.md index 7282a7e63..0061a4401 100644 --- a/docs/refactor/webagent-session.md +++ b/docs/refactor/webagent-session.md @@ -1,3 +1,9 @@ +--- +summary: "WebChat session migration notes (Gateway WS-only)" +read_when: + - Changing WebChat Gateway methods/events +--- + # WebAgent session migration (WS-only) Context: web chat currently lives in a WKWebView that loads the pi-web bundle. Sends go over HTTP `/rpc` to the webchat server, and updates come from `/socket` snapshots based on session JSONL file changes. The Gateway itself already speaks WebSocket to the webchat server, and Pi writes the session JSONL files. This doc tracks the plan to move WebChat to a single Gateway WebSocket and drop the HTTP shim/file-watching. @@ -37,3 +43,4 @@ Context: web chat currently lives in a WKWebView that loads the pi-web bundle. S - Streaming granularity: start with `state:"final"` only, or include token/tool deltas immediately? - Attachments over WS: text-only initially is OK; confirm before wiring binary/upload path. - Error shape: use `res ok:false` for validation/timeout, `chat state:"error"` for model/runtime failures. + diff --git a/docs/security.md b/docs/security.md index 6a31ea583..9789ca6d2 100644 --- a/docs/security.md +++ b/docs/security.md @@ -116,8 +116,8 @@ Include security guidelines in your agent's system prompt: If your AI does something bad: -1. **Stop it:** `clawdis stop` or kill the process -2. **Check logs:** `/tmp/clawdis/clawdis.log` +1. **Stop it:** stop the macOS app (if it’s supervising the Gateway) or terminate your `clawdis gateway` process +2. **Check logs:** `/tmp/clawdis/clawdis-YYYY-MM-DD.log` (or your configured `logging.file`) 3. **Review session:** Check `~/.clawdis/sessions/` for what happened 4. **Rotate secrets:** If credentials were exposed 5. **Update rules:** Add to your security prompt diff --git a/docs/surface.md b/docs/surface.md index 264ab3477..80ac85985 100644 --- a/docs/surface.md +++ b/docs/surface.md @@ -11,8 +11,8 @@ Goal: make replies deterministic per channel while keeping one shared context fo - **Surfaces** (channel labels): `whatsapp`, `webchat`, `telegram`, `voice`, etc. Add `Surface` to inbound `MsgContext` so templates/agents can log which channel a turn came from. Routing is fixed: replies go back to the origin surface; the model doesn’t choose. - **Canonical direct session:** All direct chats collapse into the single `main` session by default (no config needed). Groups stay `group:`, so they remain isolated. -- **Session store:** Keys are resolved via `resolveSessionKey(scope, ctx, mainKey)`; the Tau JSONL path still lives under `~/.clawdis/sessions/.jsonl`. -- **WebChat:** Always attaches to `main`, loads the full Tau transcript so desktop reflects cross-surface history, and writes new turns back to the same session. +- **Session store:** Keys are resolved via `resolveSessionKey(scope, ctx, mainKey)`; the agent JSONL path lives under `~/.clawdis/sessions/.jsonl`. +- **WebChat:** Always attaches to `main`, loads the full session transcript so desktop reflects cross-surface history, and writes new turns back to the same session. - **Implementation hints:** - Set `Surface` in each ingress (WhatsApp gateway, WebChat bridge, future Telegram). - Keep routing deterministic: originate β†’ same surface. Use the gateway WebSocket for sends; avoid side channels. diff --git a/docs/test.md b/docs/test.md index c1f85b536..02c4a27a1 100644 --- a/docs/test.md +++ b/docs/test.md @@ -1,4 +1,9 @@ -## Tests +--- +summary: "How to run tests locally (vitest) and when to use force/coverage modes" +read_when: + - Running or fixing tests +--- +# Tests - `pnpm test:force`: Kills any lingering gateway process holding the default control port, then runs the full Vitest suite with an isolated gateway port so server tests don’t collide with a running instance. Use this when a prior gateway run left port 18789 occupied. -- `pnpm test:coverage`: Runs Vitest with V8 coverage. Global thresholds are 70% lines/functions/statements and 55% branches. Coverage excludes integration-heavy entrypoints (CLI wiring, gateway/telegram bridges, webchat static server) to keep the target focused on unit-testable logic. +- `pnpm test:coverage`: Runs Vitest with V8 coverage. Global thresholds are 70% lines/branches/functions/statements. Coverage excludes integration-heavy entrypoints (CLI wiring, gateway/telegram bridges, webchat static server) to keep the target focused on unit-testable logic. diff --git a/docs/thinking.md b/docs/thinking.md index 6f1740b7a..c2a1aefc4 100644 --- a/docs/thinking.md +++ b/docs/thinking.md @@ -26,13 +26,13 @@ read_when: - Confirmation reply is sent (`Thinking level set to high.` / `Thinking disabled.`). If the level is invalid (e.g. `/thinking big`), the command is rejected with a hint and the session state is left unchanged. ## Application by agent -- **Pi/Tau**: injects `--thinking ` (skipped for `off`). Other agent paths have been removed. +- **Pi**: injects `--thinking ` (skipped for `off`). Other agent paths have been removed. ## Verbose directives (/verbose or /v) - Levels: `on|full` or `off` (default). - Directive-only message toggles session verbose and replies `Verbose logging enabled.` / `Verbose logging disabled.`; invalid levels return a hint without changing state. - Inline directive affects only that message; session/global defaults apply otherwise. -- When verbose is on, agents that emit structured tool results (Pi/Tau, other JSON agents) send each tool result back as its own metadata-only message, prefixed with `[πŸ› οΈ ]` when available (path/command); the tool output itself is not forwarded. +- When verbose is on, agents that emit structured tool results (Pi, other JSON agents) send each tool result back as its own metadata-only message, prefixed with `[πŸ› οΈ ]` when available (path/command); the tool output itself is not forwarded. ## Heartbeats - Heartbeat probe body is `HEARTBEAT /think:high`, so it always asks for max thinking on the probe. Inline directive wins; session/global defaults are used only when no directive is present. diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 1658e81ca..ee7da42c8 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -35,7 +35,7 @@ cat ~/.clawdis/clawdis.json | jq '.inbound.groupChat' **Check 3:** Check the logs ```bash -tail -f /tmp/clawdis/clawdis.log | grep "blocked\|skip\|unauthorized" +tail -f "$(ls -t /tmp/clawdis/clawdis-*.log | head -1)" | grep "blocked\\|skip\\|unauthorized" ``` ### Image + Mention Not Working @@ -81,24 +81,27 @@ Or use the `process` tool to background long commands. ### WhatsApp Disconnected ```bash -# Check status +# Check local status (creds, sessions, queued events) clawdis status -# Or from chat: send /status for agent + context usage +# Probe the running gateway + providers (WA connect + Telegram API) +clawdis status --deep # View recent connection events -tail -100 /tmp/clawdis/clawdis.log | grep "connection\|disconnect\|logout" +tail -100 /tmp/clawdis/clawdis-*.log | grep "connection\\|disconnect\\|logout" ``` -**Fix:** Usually reconnects automatically. If not: +**Fix:** Usually reconnects automatically once the Gateway is running. If you’re stuck, restart the Gateway process (however you supervise it), or run it manually with verbose output: + ```bash -clawdis restart +clawdis gateway --verbose ``` -If you're logged out: +If you’re logged out / unlinked: + ```bash -clawdis stop -rm -rf ~/.clawdis/credentials # Clear session -clawdis start # Re-scan QR code +clawdis logout +rm -rf ~/.clawdis/credentials # if logout can't cleanly remove everything +clawdis login --verbose # re-scan QR ``` ### Media Send Failing @@ -115,7 +118,7 @@ ls -la /path/to/your/image.jpg **Check 3:** Check media logs ```bash -grep "media\|fetch\|download" /tmp/clawdis/clawdis.log | tail -20 +grep "media\\|fetch\\|download" "$(ls -t /tmp/clawdis/clawdis-*.log | head -1)" | tail -20 ``` ### High Memory Usage @@ -136,22 +139,19 @@ CLAWDIS keeps conversation history in memory. Get verbose logging: ```bash -# In config -{ - "logging": { - "level": "trace" - } -} - -# Or environment -CLAWDIS_LOG_LEVEL=trace clawdis start +# Turn on trace logging in config: +# ~/.clawdis/clawdis.json -> { logging: { level: "trace" } } +# +# Then run verbose commands to mirror debug output to stdout: +clawdis gateway --verbose +clawdis login --verbose ``` ## Log Locations | Log | Location | |-----|----------| -| Main log | `/tmp/clawdis/clawdis.log` | +| Main logs (default) | `/tmp/clawdis/clawdis-YYYY-MM-DD.log` | | Session files | `~/.clawdis/sessions/` | | Media cache | `~/.clawdis/media/` | | Credentials | `~/.clawdis/credentials/` | @@ -159,14 +159,14 @@ CLAWDIS_LOG_LEVEL=trace clawdis start ## Health Check ```bash -# Is it running? -clawdis status +# Is the gateway reachable? +clawdis health --json -# Check the socket -ls -la ~/.clawdis/clawdis.sock +# Is something listening on the default port? +lsof -nP -iTCP:18789 -sTCP:LISTEN # Recent activity -tail -20 /tmp/clawdis/clawdis.log +tail -20 /tmp/clawdis/clawdis-*.log ``` ## Reset Everything @@ -174,16 +174,16 @@ tail -20 /tmp/clawdis/clawdis.log Nuclear option: ```bash -clawdis stop rm -rf ~/.clawdis -clawdis start # Fresh setup +clawdis login # re-pair WhatsApp +clawdis gateway # start the Gateway again ``` ⚠️ This loses all sessions and requires re-pairing WhatsApp. ## Getting Help -1. Check logs first: `/tmp/clawdis/clawdis.log` +1. Check logs first: `/tmp/clawdis/` (default: `clawdis-YYYY-MM-DD.log`, or your configured `logging.file`) 2. Search existing issues on GitHub 3. Open a new issue with: - CLAWDIS version