wabox
v0.1.11
Published
A bridge between WhatsApp and the filesystem — incoming messages/files land in an inbox folder, an outbox folder is watched and sent back. Built on Baileys.
Maintainers
Readme
wabox
A bridge between WhatsApp and your filesystem. It connects to WhatsApp via
Baileys, drops every incoming
message (text + media) into an inbox/ folder, and watches an outbox/ folder
for messages to send back.
The idea: point any process at these two folders. It reads new messages from
inbox/, and replies by writing job files to outbox/ — no API to learn, just
files.
Install
npm install -g wabox
wabox configWorks on Linux, macOS and Windows. wabox config is an interactive
setup that:
- asks whether you want the defaults or to customize the folders,
- writes
config.jsonand creates the data folders (locations below), - installs a background service for your OS (systemd / launchd / Task Scheduler),
- pairs with WhatsApp — scan the QR with WhatsApp → Linked Devices,
- offers to enable + start the service.
That's it — it runs in the background and starts on login/boot.
Per-OS locations
Each OS uses its native convention. Setting XDG_CONFIG_HOME / XDG_DATA_HOME
overrides them on any platform.
| OS | Config | Data (inbox/outbox/auth) | Service |
| ------- | --------------------------------------- | ----------------------------------------- | ------------------------------------------------ |
| Linux | ~/.config/wabox/ | ~/.local/share/wabox/ | ~/.config/systemd/user/wabox.service |
| macOS | ~/Library/Application Support/wabox/ | (same as config) | ~/Library/LaunchAgents/wabox.plist |
| Windows | %APPDATA%\wabox\ | %LOCALAPPDATA%\wabox\ | Task Scheduler task wabox (runs at logon) |
Run wabox status any time to print the resolved paths and service state.
Commands
wabox config # interactive setup (config + service + pairing)
wabox run # run the gateway in the foreground (what the service runs)
wabox pair # (re)pair with WhatsApp via QR
wabox allow # manage who can reach the inbox (by phone number)
wabox update # update the npm package + restart the service
wabox status # show resolved paths + service state
wabox uninstall # remove the service (--purge: also config + data)Restricting who can reach the inbox
By default wabox accepts messages from everyone. To limit it to specific people,
manage an allow list by phone number (country code + number, no +):
wabox allow add 5511999998888 # accepts "+55 (11) 99999-8888" too
wabox allow add 5511999998888 5511888887777
wabox allow list
wabox allow remove 5511999998888
wabox allow clear # back to accepting everyoneChanges are written to config.json and the service is restarted automatically
so they take effect. You only need the phone number — not the WhatsApp JID;
wabox matches incoming senders by number.
Managing the service directly
# Linux (systemd)
systemctl --user status|restart wabox.service
journalctl --user -u wabox.service -f
# keep running while logged out:
sudo loginctl enable-linger $USER
# macOS (launchd)
launchctl kickstart -k gui/$(id -u)/wabox # restart
tail -f "~/Library/Application Support/wabox/wabox.log"
# Windows (Task Scheduler)
schtasks /Run /TN wabox # start now
type "%LOCALAPPDATA%\wabox\wabox.log" # logsNo systemd on Linux (e.g. minimal/container distros)? Setup still writes the config and pairs; run the gateway yourself with
wabox run(under your own supervisor of choice).
Running from a checkout (no global install)
npm install
npm run config # same interactive setup
npm start # = wabox runPutting the inbox/outbox somewhere else
Edit your config.json (see the table above for its location) and point the
folders anywhere:
{
"inboxDir": "~/whatsapp/inbox",
"outboxDir": "~/whatsapp/outbox"
}Relative paths resolve against the data dir; ~ is expanded. Then restart the
service (see "Managing the service directly").
How it works
Building the process/agent that consumes the boxes? See INTEGRATION.md for the full contract — message format, how to reply, react, send media, format text, and the read-receipt lifecycle. Or install the skill so your agent already knows it:
npx skills add wabox-app/wabox(seeskills/wabox).
Inbox (incoming)
Each incoming message produces a JSON file in inbox/, e.g.
20260603-031200_5511999998888_3EB0ABCD.json:
{
"id": "3EB0ABCD...",
"from": "[email protected]",
"pushName": "Alice",
"fromMe": false,
"timestamp": "2026-06-03T03:12:00.000Z",
"text": "check out this photo",
"media": {
"type": "image",
"file": "20260603-031200_5511999998888_3EB0ABCD.jpg",
"originalName": null,
"mimetype": "image/jpeg"
}
}Media (images, video, audio, documents, stickers) is downloaded next to the
JSON, with media.file pointing at it. Text-only messages just have
"media": null.
Inbox lifecycle & read receipts
Your consumer owns cleanup. wabox never deletes inbox files — the process
that reads them is responsible for removing each .json (and any media) once it
has handled the message.
That removal is also the "message read" signal: when a .json leaves the
inbox/ folder, wabox sends a native WhatsApp read receipt for that message, so
the sender sees the blue checkmarks. The recommended flow is read → remove →
respond:
- message arrives →
<stem>.json(+ media) written toinbox/, delivered to the sender as usual (grey ticks); - your consumer reads the file (and any media) into memory, or moves it to a working folder;
- your consumer removes
<stem>.jsonfrominbox/right away → wabox marks it read and the sender sees blue checkmarks; - your consumer processes the message and writes its reply to
outbox/.
Removing on pickup (before processing) means the sender is acknowledged immediately, not only once a slow reply is ready. A message stays "unread" until you remove it. Blue ticks only appear if both accounts have read receipts enabled in WhatsApp. See INTEGRATION.md for the full consumer guide.
Outbox (outgoing)
To send a message, write a .json file into outbox/:
{
"to": "5511999998888",
"text": "Hello from Claude!",
"files": ["reply.pdf", "/abs/path/photo.jpg"]
}to— a bare phone number (country code + number, no+) or a full JID ([email protected]for people,[email protected]for groups).text— optional. Sent on its own if there are no files, otherwise used as the caption of the first file.files— optional list. Relative paths resolve againstoutbox/. File type (image / video / audio / document) is inferred from the extension.replyTo— optional. Quote-reply to an incoming message. Either a bare message id string, or an object{ "id", "participant", "text" }. Copyid(andparticipantfor groups) straight from the inbox JSON;textis just the preview shown in the quote bubble.react— optional. Add an emoji reaction to a message:{ "emoji": "👍", "messageId": "3EB0...", "participant": null }. An emptyemojiremoves a previously sent reaction. A reaction can be the whole job or ride along withtext/files.
Reply + reaction example:
{
"to": "5511999998888",
"text": "claro, segue o arquivo",
"replyTo": { "id": "3EB0ABCD...", "participant": null },
"react": { "emoji": "👍", "messageId": "3EB0ABCD..." },
"files": ["doc.pdf"]
}Once processed, the job file is moved to outbox/sent/. If it fails, it goes to
outbox/failed/ with a .error.txt sidecar explaining why.
Tip: write the file to a temp name first and rename it into
outbox/(atomic), so the watcher never reads a half-written file. The watcher also waits for writes to settle, but rename is safest.
Configuration
Settings come from (highest priority first): environment variable →
~/.config/wabox/config.json → built-in default.
| config.json key | Env var | Default | Purpose |
| --------------- | ---------------- | --------------------- | ------------------------------------------------- |
| inboxDir | INBOX_DIR | <data>/inbox | Where incoming messages/media are written. |
| outboxDir | OUTBOX_DIR | <data>/outbox | Watched for outgoing job files. |
| authDir | AUTH_DIR | <data>/auth | WhatsApp session storage. |
| allowFrom | ALLOW_FROM | [] (all) | Numbers/JIDs to accept (array, or CSV in env). |
| ignoreFromMe | IGNORE_FROM_ME | true | Skip messages the bot itself sent. |
| logLevel | LOG_LEVEL | info | pino log level for wabox's own logs. |
| baileysLogLevel | BAILEYS_LOG_LEVEL | warn | Log level for Baileys' (chatty) internal logs. |
<data> is the per-OS data dir from the locations table above. Relative paths
in config.json resolve against <data>; ~ is expanded.
Notes
- This uses the unofficial WhatsApp Web protocol via Baileys. Use a number you control and don't abuse it.
- Deleting
auth/forces a fresh QR pairing.
Contributing
Contributions are welcome — see CONTRIBUTING.md for setup, how to verify changes, and the AI-assistance policy. Working with an AI coding agent? Point it at AGENTS.md for the architecture and key invariants.
AI assistance
wabox was built with the help of an AI coding assistant (Anthropic's Claude, via
Claude Code). The assistant contributed to code generation, refactoring, and
documentation. Every change was reviewed, tested, and is maintained by a human
(@rodgco), who remains responsible for the project.
AI-assisted commits carry a Co-Authored-By: trailer.
Contributions made with AI tools are welcome — please make sure you understand and test your changes, and mention any significant AI assistance in your pull request.
License
MIT © Rodrigo Couto
