Personal WhatsApp (experimental)
Control ccr-cloud through Message Yourself in personal WhatsApp. Every input must start with /ccr ; ordinary personal notes are ignored. No business account, public webhook or LLM dispatcher is required.
This uses the unofficial Baileys WhatsApp Web adapter. Use a spare number. Protocol changes can break it and unofficial clients can lead to account restrictions. It is off by default. This is not affiliated with Meta or WhatsApp. Check the WhatsApp Terms of Service before use. Real phone pairing/delivery has not been verified; tests use fake transport. Keep the PWA as your recovery path.
In host mode, coding tasks run as the service user and can read DATA_DIR/whatsapp/auth. These files grant a linked-device session to the WhatsApp account, including its messages. A compromised/prompt-injected task could take over that linked session. Use a spare account and a dedicated Unix user; file permissions do not isolate the agent from credentials of its own user.
#Install and pair
First complete Getting started and use a scratch task in the PWA. The optional Baileys npm dependency is installed by normal npm ci; use npm ci --omit=optional if you do not want WhatsApp support. Normal host installation adds Baileys and its transitive packages and may run their install scripts. Session containers omit optional packages entirely.
Install the local qrencode executable using your operating system package manager. Pairing QR codes are displayed locally, never through a QR image service. Stop the API before changing pairing:
tmux kill-session -t =ccr-cloud
npm run whatsapp -- login
npm run setup -- --start
npm run whatsapp -- statusOn your spare-number phone, open WhatsApp Settings → Linked devices → Link a device and scan the terminal QR. Login saves private auth state and writes WHATSAPP_ENABLED=1 in server.env. It times out after five minutes; retry when ready. Status checks only local files and worker lock, not live delivery.
#Send commands
Open Message Yourself on the paired account:
/ccr help
/ccr new Reply OK
/ccr sessions
/ccr use SESSION_ID
/ccr say Please explain the change briefly
/ccr status SESSION_ID
/ccr allow SESSION_ID FULL_REQUEST_ID
/ccr deny SESSION_ID FULL_REQUEST_ID
/ccr stop SESSION_ID
/ccr resume SESSION_ID
New tasks use model access. /ccr new --project PROJECT_ID PROMPT selects an existing saved project. Prefix all commands, including follow-ups, with /ccr. Only messages sent by the linked owner to their own self-chat are accepted. Groups, incoming messages from others, media and history-sync batches are ignored. Replies start with [ccr-cloud] and cannot execute commands. Full open approval request IDs are required; there is no approve-all command.
#Notifications and privacy
Notifications are off by default. To send selected task replies and tool inputs to your WhatsApp self-chat, set WHATSAPP_NOTIFICATIONS=1 in server.env and restart. Events that occur while notifications are disabled are consumed without later replay. Command replies still work. All enabled chat content goes through WhatsApp; avoid using it for material you do not want in that account.
Credentials, the selected task and message receipt journal live in DATA_DIR/whatsapp/. The auth directory is private; these files are credentials and private task data, not material for GitHub issues. One worker may use the pairing at a time. A normal stop releases the lock; dead-PID locks recover at startup. Corrupt locks need an explicit offline npm run whatsapp -- unlock.
The journal records message IDs before executing commands. A crash may leave an outcome uncertain, or lose the reply, but the command is not automatically repeated. Inspect task status in the PWA before retrying. The journal prunes older receipts at 5,000 entries while retaining a timestamp floor: replayed/older messages cannot execute after their IDs are pruned. Messages without a valid wire timestamp and messages at/before that floor are ignored. Notifications can repeat after uncertain sends. This prototype does not guarantee exactly-once delivery or task execution. Transient disconnects attempt reconnection; expired pairing requires an explicit login. A failed reconnect may require a service restart.
#Disconnect
Stop the API, run npm run whatsapp -- logout, and restart. This disables the channel and removes its local pairing/runtime state, preserving coding tasks. Also unlink the device in WhatsApp Linked devices to revoke it there. Logout is local and does not claim to revoke WhatsApp-side sessions over the network.
To temporarily disable it without removing credentials, set WHATSAPP_ENABLED=0 and restart. The PWA and Discord/WeChat continue independently.
Commands sent while ccr-cloud is offline may arrive as history rather than notify batches and be ignored. Inspect status and resend explicitly after reconnecting; this behavior has not been verified on a real phone.
Commands need a clear message timestamp from the past 24 hours, with at most five minutes of clock skew into the future. Older commands and commands at or below the receipt journal floor are ignored. The bot explains rejected timestamps at most once per minute; check the task before sending a fresh command. Brief reconnects retain exponential backoff; a connection must remain open for 60 seconds before the next reconnect delay resets.
Keep the host clock synchronized: if it runs more than five minutes behind WhatsApp server time, commands are rejected.