No description
  • TypeScript 95.7%
  • JavaScript 4.3%
Find a file
Peter Kramárik 81a652074b liaison prompt: allow customer-facing preview URL on explicit request
Peto asked "ukaz nahlad" expecting a clickable link he could open on his
phone; Mia replied with screenshots only and refused to share a URL. That
was technically correct under rule 1 ("no hosting/URL technicalities") but
operationally wrong — the customer's preview URL (<slug>.preview.pk01.sk)
is a clean, customer-friendly subdomain on Peter's own infrastructure, not
an internal API path. Add an explicit carve-out in rule 1 so Mia can send
both the screenshot AND the URL when the customer asks for "nahlad" or
"link" or "preview", while still forbidding pr-N preview URLs, /api/...
paths, git links, and admin URLs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 21:09:34 +00:00
bin Mia: Playwright MCP for live page introspection + outbound media forwarding 2026-05-08 21:04:53 +00:00
prompts liaison prompt: allow customer-facing preview URL on explicit request 2026-05-09 21:09:34 +00:00
src liaison: discover chromium dynamically; drop hardcoded baskervil paths 2026-05-09 17:40:09 +00:00
.env.example Initial implementation: kokpit-wa-bridge v0.1.0 2026-05-08 19:54:33 +00:00
.gitignore gitignore: drop accidental /tmp entry 2026-05-08 21:30:17 +00:00
ecosystem.config.cjs liaison: discover chromium dynamically; drop hardcoded baskervil paths 2026-05-09 17:40:09 +00:00
package-lock.json Fix outbound polling loop spam: filter inclusive cursor 2026-05-08 20:00:00 +00:00
package.json Fix outbound polling loop spam: filter inclusive cursor 2026-05-08 20:00:00 +00:00
README.md Fix outbound polling loop spam: filter inclusive cursor 2026-05-08 20:00:00 +00:00
tsconfig.json Initial implementation: kokpit-wa-bridge v0.1.0 2026-05-08 19:54:33 +00:00

kokpit-wa-bridge

Standalone WhatsApp ↔ Paperclip ↔ Claude bridge for PK01.

Replaces the old paperclip-whatsapp-bridge plugin (retired 2026-05-08 after multipart/permission issues — see ~/.claude/plans/ten-7-je-asi-playful-dahl.md for context).

What it does

  • Connects to WhatsApp via Baileys 7.x with on-disk auth state in ~/.kokpit-wa-bridge/auth/.
  • For each registered customer (= one WhatsApp group), forwards every inbound message into a fixed Paperclip "channel issue" as a comment, with media uploaded as attachments.
  • Asks Claude (via the local claude CLI) for a customer-facing reply in the Liaison persona, posts it as a Paperclip comment.
  • Polls Paperclip every 5 s for new comments on each channel issue and forwards customer-facing ones to WhatsApp. Comments containing <!-- internal --> stay internal; comments shaped **Name (+phone):** … (our own inbound echoes) are filtered out as anti-loop.

Architecture

Single Node 22+ process under PM2. SQLite on disk for customer registry, dedup, polling cursor. No plugin SDK, no embedded postgres dependency at runtime (only used once for auth-state migration). Multipart uploads to Paperclip via axios + form-data — the combination that the multer middleware actually accepts (Node native FormData + Blob does not work).

~/projects/kokpit-wa-bridge/
├── src/
│   ├── index.ts                # entry, wires everything
│   ├── config.ts               # env vars, customer seed
│   ├── db.ts                   # SQLite schema + seed
│   ├── customers.ts            # registry CRUD
│   ├── dedup.ts                # waMsgId tracking, outbound cursor
│   ├── format.ts               # canonical comment + media-tag formatting
│   ├── wa-client.ts            # Baileys socket wrapper
│   ├── paperclip.ts            # axios HTTP client
│   ├── inbound.ts              # WA → Paperclip pipeline
│   ├── liaison.ts              # claude CLI → reply comment
│   ├── outbound.ts             # polling loop, Paperclip → WA
│   └── logger.ts               # pino
├── bin/
│   ├── migrate-baileys-auth.ts # one-shot, paperclip postgres → fs
│   ├── add-customer.ts         # CLI: add to registry
│   └── list-customers.ts       # CLI: dump registry
├── prompts/
│   └── liaison.md              # Claude system prompt (customer-facing voice)
└── data/                       # gitignored runtime state (sqlite db)

Setup (first install)

  1. pnpm install (or npm install)
  2. cp .env.example .env and fill in PAPERCLIP_API_KEY (board token), WA_PHONE_NUMBER. Anthropic auth comes from your local claude CLI — no API key needed.
  3. npm run build
  4. Migrate Baileys auth state from the old paperclip plugin so you don't re-pair via QR. (One-shot — only needed during the original 2026-05-08 cutover. Already done; keep notes for the next time we need to extract Baileys creds: query the plugin_state table where namespace='wa-auth', write each row's value_json to ~/.kokpit-wa-bridge/auth/${state_key with -}.json. The script that did this lives only in git history at commit before 0.1.1.)
  5. Cutover (uninstall old plugin, start new bridge):
    paperclipai plugin uninstall whatsapp-bridge --force --api-base https://sitecraft.sk
    pm2 start ecosystem.config.cjs
    pm2 save
    
  6. pm2 logs kokpit-wa-bridge --lines 20 — verify "WhatsApp paired" appears.

Add a customer

node dist/bin/add-customer.js \
  --slug new-customer \
  --jid 1203...@g.us \
  --channel-issue <paperclip-issue-uuid> \
  --project <paperclip-project-uuid> \
  --goal <paperclip-goal-uuid> \
  --git ssh://git@git.kokpit.sk:2222/forge-admin/<repo>.git
pm2 restart kokpit-wa-bridge

You'll need to:

  1. Create the Paperclip Project + Goal + channel issue (originKind=plugin:whatsapp-bridge:channel, originId=<jid>) yourself in the dashboard or via API.
  2. Make sure your WhatsApp phone has joined that group already (the bridge doesn't auto-join).
  3. Restart the bridge so the in-memory customer registry rehydrates from SQLite.

Operations

pm2 logs kokpit-wa-bridge --lines 50
pm2 restart kokpit-wa-bridge
pm2 stop kokpit-wa-bridge
sqlite3 ~/.kokpit-wa-bridge/kokpit.sqlite "SELECT slug, wa_group_jid FROM customers;"

Re-pair (when WhatsApp logs out)

If pm2 logs shows kind: "logged_out" or you see a fresh QR string in the logs:

  1. pm2 restart kokpit-wa-bridge
  2. pm2 logs kokpit-wa-bridge --lines 5 — copy the QR string out of the log.
  3. Open WhatsApp on phone → Linked Devices → Link a device → scan.

License

MIT — Peter Kramarik peter.kramarik@pk01.sk