Employee App (Claway App)
The Claway employee app gives every rostered employee a first-class chat client — mobile (iOS/Android), desktop (macOS/Windows), and web, one Flutter codebase — alongside the WhatsApp channel. An employee's 1:1 conversation with the agent is one unified thread across WhatsApp and the app: history, context, and memory are shared, and the agent replies on whichever channel the employee last spoke on.
Enabling the employee plane
-
Set a signing secret in
.env(a credential — never config.yaml):EMPLOYEE_JWT_SECRET=$(openssl rand -hex 32) -
Enable the plane in
config.yaml:employee_auth:
enabled: true
workspace_name: "Acme Ltd"
otp:
channel: whatsapp # login codes are sent via your own WhatsApp connector
unified_dm_platform: whatsapp # whatsapp_cloud for Meta Cloud API tenants
host: 127.0.0.1 # 0.0.0.0 for direct LAN/VPN access (behind TLS)
port: 8643 -
Restart the gateway. The plane refuses to start without a strong
EMPLOYEE_JWT_SECRETand warns loudly whenunified_dm_platformmismatches the enabled WhatsApp adapter, or when the roster has no active admin.
Rostering employees
Enrollment is fail-closed: only phones an admin has rostered can ever receive a login code. The first admin is added:
- on a Claway Box, by the activation page (required "Admin mobile");
- in OPS → Users ("No App admin yet — add one");
- on the box, as the service user:
claway employees add --phone '+852 9123 4567' --role admin --name Alice; - by HQ, through the panel's
employees.add_admin(only while the roster has no active admin).
Active rostered employees with a phone may also message the bot on
WhatsApp: the DM allowlist the bridge enforces is the operator's own list
plus the roster ($CLAWAY_HOME/whatsapp/roster_allowlist.json, kept in step
automatically, no restart). Disabling someone removes only that roster
entry — numbers the operator allowlisted by hand are never touched.
After that, admins manage the roster from the app's Admin section
(add/disable employees, devices, usage) or via POST /app/v1/admin/employees.
Login flow
Phone number → 6-digit code delivered through the company's own WhatsApp connector (the code arriving at the exact WhatsApp account being linked is itself the identity check; SIM-swap-resistant) → 15-min access token + 30-day rotating refresh token per device.
Connection modes
- Direct — the app connects straight to
http(s)://<instance>:8643. LAN, VPN, or public endpoint; zero intermediaries. - Relay — for instances behind NAT and for store push
notifications, configure
employee_auth.relay.url(andEMPLOYEE_RELAY_TOKENin.env). The instance dials OUT to the Claway App Relay; the relay routes opaque frames by workspace id and holds only push tokens — never rosters, OTPs, or message content. Push bodies are redacted by default (push_redaction: true).
Groups
- App groups: employees + the agent in one shared conversation.
respond_mode: mention(default) makes the agent answer only when @'d, like a WhatsApp group;allanswers every message. - Bridged groups: an admin can link an app group to an existing
WhatsApp group (Admin → group → link, or
POST /app/v1/groups/{id}/linkwith the group JID). Messages flow both ways — app-side messages appear in the WhatsApp group prefixed[Name], agent replies go to the WhatsApp group and mirror into the app. Full context merge across both sides requiresgroup_sessions_per_user: falsein the gateway config (the plane warns at link time otherwise).
Protocol
Client developers: the full REST + WebSocket contract is in
docs/app-client-protocol.md in the repository.