Clients keep writing where they already write — WhatsApp, email, Slack. Claude identifies the client and the site, answers or makes the change on the hosting server, and reports back in the same thread. It escalates to us only when it needs a human. Everything is snapshotted, undoable, and logged for billing.
WhatsApp voice note: "the phone number on the contact page is old, the new one is 0176…". Voice is transcribed on arrival.
Webhook fires to the Brain. Registry lookup: this number = client X, site on ionos 2, these rules. Unknown senders can only ever create an unassigned inbox item — never trigger anything.
Question → answers directly (it can inspect the live site through the runner). Change → job for the runner on that site's server: git/DB snapshot first, then Claude Code works in the site's directory with real power — theme files, wp-cli, database.
"Done — the contact page now shows 0176…" via Chatwoot API, out through the original channel. Work logged with diff and cost. Client can refine: "perfect, but a bit darker."
Ambiguous request, risk line, or a reply that commits us to a price/deadline → the Brain attaches a private note with context and assigns the conversation to Salman in Chatwoot. He answers like a normal chat; Claude continues after.
Channel plumbing is the biggest, least valuable part of the build: Meta API quirks, media downloads, 24-hour session windows, email MIME parsing, threading, bounce handling — weeks of work, permanent maintenance, zero differentiation. Chatwoot has all of it debugged in production for years, plus exactly what we want anyway: per-client history, read/unread, one inbox.
The integration seam is deliberately thin: one webhook into the Brain, two API calls back (send message, assign conversation). ~200 lines of glue. Everything that matters — triage, registry, runners, billing — is ours; Chatwoot is replaceable behind that seam if it ever disappoints. And since this is an internal tool, the free community edition covers everything we need, permanently: channels, webhooks, API, history, read/unread all live in the open-source core. $0.
Autonomy with an undo, not a gate. Tier caps are enforced by the runner, not left to the model — a client message can't talk itself into a higher tier.
Scope jail: each job is confined to that one site's directory and containers — client A physically cannot touch client B's site. Snapshot before every change (git + DB), one-click undo. Untrusted input: turn and spend limits per request, full transcript logged. Email identity is weaker than WhatsApp/Slack, so email-originated changes default to confirm-first until the thread is established.
This is an internal tool for our own clients — no productizing planned. If we ever want more precision for "this exact button" requests, the on-site element-pin widget from the earlier draft can be added as a fourth entry point into the same queue.
1. Claude account token for the runners (claude setup-token) — CLI already installed and verified on ionos 4.
2. A requests mailbox (e.g. requests@zask.it) — the Phase 1 channel.
3. A Meta Business account, to connect Salman's existing WhatsApp number to the API.
4. A go. Nothing touches a real client until it has run clean on the sandbox.