Proposal · Internal · v3

Zask Hub — every client channel in one inbox, Claude does the work

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.

Prepared for Salman · July 2026 · v3: channel layer via self-hosted Chatwoot instead of custom build

Architecture

WhatsApp
Salman's existing Business App number, connected to the Cloud API in coexistence mode (via Twilio/360dialog) — his phone app keeps working, the hub listens in parallel. Clients notice nothing.
Email
A dedicated address (e.g. requests@zask.it) clients write to or we forward into.
Slack
A bot in shared client channels or DMs. Not a native Chatwoot channel — bridged through Chatwoot's API channel by a small module in the Brain (~50 lines); history and read/unread work the same.
Chatwoot — inbox & channels (self-hosted, ionos 4)
Open-source omnichannel inbox. Owns the channel connections, media handling, per-client conversation history, read/unread with badges, and contact records. This is also where Salman answers escalations — one inbox for all channels, works like WhatsApp Web.
webhook per incoming message ↓  ·  ↑ replies via API, back through the original channel
Zask Brain — our app (Node + SQLite, ionos 4)
Client Registry (contact → client → site → server → policy) · Claude triage (question or change?) · job queue for the runners · escalation logic · billing log (every job: message, work done, diff, cost).
runners poll outward over HTTPS — no inbound SSH, no open ports, one shared Claude account token ↓
Runner · ionos 1
Snapshot → claude -p in the site's directory → diff back.
Runner · ionos 2
Same small agent. Only touches sites on its own server.
Runner · ionos 3
Install once, register its sites, done.
Runner · ionos 4
Claude CLI already installed — pilot server.

How a message flows

1
Client writes like always.

WhatsApp voice note: "the phone number on the contact page is old, the new one is 0176…". Voice is transcribed on arrival.

2
Chatwoot ingests, Brain identifies.

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.

3
Claude triages and acts.

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.

4
Reply lands in the same thread.

"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."

5
Escalation only when a human is needed.

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.

Why Chatwoot instead of building the channel layer

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.

History = the invoice

Billing per work done

  • Every request logged with the work performed, the diff, and its cost — permanently, per client.
  • Filter by client + month → itemized work list → charge per work, or count against a plan ("X requests included").
  • Disputes settled by evidence: each line links to the conversation, the diff, the timestamp.

Read / unread — like WhatsApp

  • Unread badges per client and channel — nothing slips through, even when Claude already handled it.
  • Per-request status: received → seen → done, mirrored to the client's thread.
  • Comes with Chatwoot out of the box — not something we build.

Safety

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.

Runs on its own
Text, colours, CSS, images, sections, factual replies. Snapshot first, undo always, transcript logged.
Asks first
Ambiguous requests, forms/checkout, plugin installs, replies committing a price or deadline.
Never automated
Payments data, user accounts, DNS/email, permanent deletions, anything off-site.

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.

Rollout

Phase 1 ~2–3 days
Pilot on ionos 4. Chatwoot up + email channel + Brain (registry, triage, escalation, billing log) + runner. End-to-end on our sandbox site. WhatsApp API application starts now (verification takes days).
Phase 2 ~1–2 days
WhatsApp + Slack live. Coexistence on Salman's existing number (fallback: full migration — same number for clients, Salman chats via Chatwoot). Voice transcription, undo button, billing export.
Phase 3
All servers. Runners on ionos 1–3, registry filled, clients onboarded one by one — for them nothing changes except response speed.

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.

What we need to start

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.