Own your TeamPlus history — capture every message (and image, and file) into your own cloud database, queryable from anywhere. No laptop required.
Self-hosted tooling around a TeamPlus account:
- Cloud archive — an always-on Cloudflare Worker that captures every message into your own Turso (SQLite) database, so you have a private, queryable log of who said what, when, where — DMs, groups, and bots — without keeping a laptop running.
- Read & reply from the CLI — Claude Code skills (
dms,fetch-hx) and small Node scripts read your history and send messages, straight over TeamPlus's authenticated REST endpoints or through the worker.
Everything talks to TeamPlus over the same authenticated WebSocket + REST
endpoints. The TeamPlus instance URL is configured via TEAMPLUS_BASE; nothing
about a specific organisation is baked into the source.
Heads-up: TeamPlus has no public API. This drives the same endpoints the web client uses, authenticated with session cookies you refresh yourself. Use it only with your own account and within your organisation's policies.
- 🗄️ Cloud message archive — a Durable Object holds the TeamPlus WebSocket and writes every message to Turso: who, when, which chat, direction, content. DMs, groups, and bots.
- 🏷️ Name resolution — numeric sender/chat IDs are resolved to real names via the TeamPlus REST API (cached per session).
- 🖼️ Attachment archive — images and files are downloaded and stored in R2; rich flex cards are kept as JSON.
- 🔗 Time-limited viewer links — signed, browser-openable URLs for any attachment that the worker hard-caps to expire within a week.
- 🔑 Read API —
GET /v1/logsreturns recent messages as JSON (default 24h, up to 7 days), gated by a shareable read-only key. Browse from the CLI with./scripts/logs.mjs(see the Playbook). - ✉️ Send from anywhere —
./scripts/send.mjs --to <userNo> --text "…"sends a TeamPlus DM (or group message) through the worker, no local process required. - 🤖 Claude Code skills —
dmstriages your inbox (read, draft, send, ignore lists);fetch-hxjumps straight to one person's or group's recent thread by name. - ♻️ Self-healing — the Durable Object reconnects on drops, with a cron keepalive as backstop.
- ☁️ No laptop required — cookie refresh runs as a GitHub Actions cron.
┌─────────────────────────────┐
your TeamPlus account │ TeamPlus (TEAMPLUS_BASE) │
└───────────┬─────────────────┘
WebSocket + REST (session cookies)
┌───────────┴───────────────────┐
┌─────────────▼──────────┐ ┌────────────────▼────────────┐
│ scripts/ + .claude/ │ │ worker/ (Cloudflare Worker)│
│ • dms / fetch-hx skills│ │ • Durable Object holds the │
│ • logs.mjs (read API) │ │ cookie + WS, self-heals │
│ • send.mjs (cloud send)│ │ • normalises every message │
│ • cookie refresh (OCR) │ │ • resolves sender/chat names│
└────────────────────────┘ │ • Turso + R2 attachments │
└─────────────┬───────────────┘
│
Turso (SQLite)
who / when / where / what
The cloud archive needs no local process once deployed; the only recurring task is re-uploading fresh cookies (~daily), which a GitHub Actions cron handles for you. The CLI scripts and skills read that same archive and send replies on demand.
The retired Telegram-bridge daemon (a Bun process that mirrored messages to a Telegram bot and drafted replies) is preserved under
archive/telegram-bridge/for reference; it is no longer part of the setup.
| Path | What |
|---|---|
worker/ |
Cloudflare Worker + Durable Object → Turso archive (see worker/README.md) |
scripts/ |
Cookie refresh (Patchright + Tesseract OCR), signed upload, logs.mjs/send.mjs/attachment_url.mjs/cf_worker_request.mjs helpers |
docs/ |
Operations playbook — querying logs, monitoring, key rotation, troubleshooting |
.claude/ |
dms + fetch-hx skills for reading and replying from Claude Code |
Makefile |
make refresh (cookie capture) + make setup-creds |
archive/ |
telegram-bridge/ — the retired Telegram bridge daemon, kept for reference |
- Node.js + pnpm — runs the worker tooling and CLI scripts
- Python 3 — cookie refresh (a venv is bootstrapped automatically)
- Tesseract — captcha OCR (
brew install tesseract) - For the cloud archive:
wrangler, thetursoCLI, and a Cloudflare + Turso account
# 1. Configuration
cp .env.example .env # set TEAMPLUS_BASE + your TeamPlus login
# 2. First cookie capture (also fills my_id in .config.json)
make refresh # headless login + OCR; ./scripts/refresh.sh --headful to watch
# 3. Deploy the cloud archive
cd worker
pnpm install
turso auth login
./scripts/setup_turso.sh teamplus-messages # creates DB + schema + secrets
# → edit worker/.dev.vars and set TEAMPLUS_BASE
./scripts/push_secrets.sh && wrangler deploy
# → set CF_TEAMPLUS_WORKER_URL in ../.cf-worker.env to the deployed URL
cd ..
./scripts/refresh_and_upload_cf.sh # refresh cookies + push to workerThe TeamPlus session token (TSSID) lives ~1 day, so schedule
./scripts/refresh_and_upload_cf.sh to keep the cloud session alive. A local
cron works, but to drop the laptop entirely, run it from CI (see below).
.github/workflows/refresh-cookies.yml.example runs the cookie refresh on a
GitHub-hosted runner (Chromium + Tesseract) and uploads to your worker — no
machine of your own needed. Recommended split for open-sourcing:
- Public repo — the code, with the workflow as a
.exampletemplate only. - Private repo — your actual deployment: copy the template to
.github/workflows/refresh-cookies.ymland add the five Secrets it lists (TEAMPLUS_ACCOUNT,TEAMPLUS_PASSWORD,TEAMPLUS_BASE,CF_TEAMPLUS_WORKER_URL,CF_TEAMPLUS_UPLOAD_SECRET).
GitHub Actions Secrets are encrypted, never stored in the repo, and masked in
logs — open-sourcing the code does not expose them. Keep the running workflow in
the private repo and use only schedule / workflow_dispatch triggers (never
pull_request) so fork PRs can never reach the secrets.
All secrets live in gitignored files; templates are committed:
| File | Holds | Template |
|---|---|---|
.env |
TEAMPLUS_BASE, TeamPlus login |
.env.example |
.config.json |
your TeamPlus my_id + mute lists |
auto-filled |
cookies.json |
captured session cookies | scripts/refresh.sh |
worker/.dev.vars |
Turso creds, upload secret, TEAMPLUS_BASE, TEAMPLUS_DB_KEY |
worker/.dev.vars.example |
.cf-worker.env |
deployed worker URL + upload secret | worker/scripts/setup_turso.sh |
Nothing in version control contains a real credential or organisation URL.
MIT.