A cron job that fetches your WhatsApp messages via Unipile, uses Cerebras Inference (gpt-oss-120b) to extract real, actionable todos from the chatter, and organizes them on a kanban board — grouped by whatever project you map each client/chat to.
Rendering mermaid diagram...
sync.ts(interval cron) — runs every 6 hours, fetches new WhatsApp messages from Unipile, groups unprocessed messages per chat, and sends each batch to Cerebras (gpt-oss-120b) with a strict JSON schema (response_format: json_schema) to pull out real tasks — ignoring small talk. Extracted todos are tagged with the project mapped to that chat (if any) and stored in the "Inbox" column.lib/cerebras.ts— Cerebras Inference client (OpenAI-compatible API) doing structured-output extraction: title, summary, priority, due date, and whether a message is actually actionable.lib/db.ts— SQLite schema: todos (inbox → todo → doing → done), aproject_mappingstable (chat → project), and aprocessed_messagestable so chats without actionable content aren't re-sent to the LLM every sync.index.ts(HTTP) — serves the React kanban UI, todo CRUD routes, and project-mapping routes.- Settings panel (⚙️ in the UI) — lists your WhatsApp chats/clients and lets you assign each one a project name.
Follow the Unipile WhatsApp guide to connect your WhatsApp account. Note your account ID from the Unipile dashboard.
Sign up at the Cerebras Cloud Console and create an API key. Todos are extracted using the gpt-oss-120b model via Cerebras's OpenAI-compatible API.
| Env var | Description |
|---|---|
UNIPILE_DSN | Your Unipile data source URL (e.g. https://xxx.unipile.com) |
UNIPILE_API_KEY | Your Unipile access token |
UNIPILE_ACCOUNT_ID | The WhatsApp account ID linked in Unipile |
CEREBRAS_API_KEY | Your Cerebras Cloud API key (used for todo extraction) |
BOARD_PASSPHRASE | A passphrase to protect your kanban board (since the val is public on free tier) |
👉 Add UNIPILE_DSN here: https://www.val.town/x/pc_style/whatsapp-kanban/environment-variables?key=UNIPILE_DSN 👉 Add UNIPILE_API_KEY here: https://www.val.town/x/pc_style/whatsapp-kanban/environment-variables?key=UNIPILE_API_KEY 👉 Add UNIPILE_ACCOUNT_ID here: https://www.val.town/x/pc_style/whatsapp-kanban/environment-variables?key=UNIPILE_ACCOUNT_ID 👉 Add CEREBRAS_API_KEY here: https://www.val.town/x/pc_style/whatsapp-kanban/environment-variables?key=CEREBRAS_API_KEY 👉 Add BOARD_PASSPHRASE here: https://www.val.town/x/pc_style/whatsapp-kanban/environment-variables?key=BOARD_PASSPHRASE
Open the board, click ⚙️ Settings, and give each WhatsApp chat a project name. Any todos extracted from that chat going forward will be tagged with that project. Use the project filter dropdown on the board to focus on one project at a time.
Run sync.ts manually from the Val Town editor to pull your first batch of messages and extract todos.
sync.ts ← Cron job (every 6h) — fetches messages, runs LLM extraction
index.ts ← Hono server — serves UI + API routes
lib/
db.ts ← SQLite schema + todo/project-mapping CRUD helpers
unipile.ts ← Unipile API client (messages + chats)
cerebras.ts ← Cerebras (gpt-oss-120b) structured-output extraction
frontend/
index.html ← HTML shell
index.tsx ← React entrypoint
components/
App.tsx ← Kanban board UI (project badges, filter, settings launcher)
Settings.tsx ← Client → project mapping panel
| Method | Path | Description |
|---|---|---|
GET | /api/todos | List all todos |
PATCH | /api/todos/:id | Move a card ({ status: "inbox|todo|doing|done" }) |
DELETE | /api/todos/:id | Delete a card |
GET | /api/chats | List WhatsApp chats from Unipile (for the mapping UI) |
GET | /api/project-mappings | List chat → project mappings |
PUT | /api/project-mappings/:chatId | Set/update a mapping ({ project_name, chat_name }) |
DELETE | /api/project-mappings/:chatId | Remove a mapping |