noti#
noti recommends notification actions from recent inbox state and account notification preferences.
It logs in with atproto OAuth, reads the live Bluesky notification inbox, and can:
- mute or unmute an account
- block or unblock an account
- turn post notifications on or off for an account
- turn reply notifications on or off for an account
- mark notifications seen
Mutations are code-mode: model-written compositions over a restricted atproto SDK surface, executed in a Cloudflare Worker isolate and verified against live state before success is reported.
architecture#
- Cloudflare Worker app in
src/worker.ts - D1-backed OAuth state, sessions, notification history, and user guidance in
src/cloudflare/* - Worker Loader sandboxing in
src/cloudflare/code-mode.ts - Background recommendations via Cloudflare Queues with D1 job/result storage
- D1 allowlist and LLM usage tracking/limits in
src/cloudflare/usage.ts - Anthropic prompt caching on the stable code-mode system prompt
- Local app bundle from
scripts/build-client.ts, including pinnedhtmx.organdsrc/client.ts - Login typeahead backed by
https://typeahead.waow.tech
OAuth scopes#
noti requests granular atproto OAuth scopes:
atprotorepo:app.bsky.graph.blockrpc:app.bsky.notification.listNotifications?aud=*rpc:app.bsky.notification.listActivitySubscriptions?aud=*rpc:app.bsky.notification.putActivitySubscription?aud=*rpc:app.bsky.notification.updateSeen?aud=*rpc:app.bsky.graph.getMutes?aud=*rpc:app.bsky.graph.getBlocks?aud=*rpc:app.bsky.graph.muteActor?aud=*rpc:app.bsky.graph.unmuteActor?aud=*rpc:app.bsky.actor.getProfile?aud=*rpc:app.bsky.actor.getProfiles?aud=*rpc:app.bsky.feed.getPosts?aud=*
local dev#
Create .dev.vars:
ANTHROPIC_API_KEY=...
Run:
bun install
bunx wrangler d1 migrations apply noti --local
bun run dev -- --ip 127.0.0.1 --port 8787
Open http://127.0.0.1:8787/oauth/login.
Allow a DID locally:
bunx wrangler d1 execute noti --local --command "INSERT INTO invite_allowlist (user_did, note, created_at) VALUES ('did:plc:...', 'local dev', datetime('now'))"
checks#
bun run check
bun test
bun run lint
bun run check:dry-run
deploy#
Before deploying:
- set
ANTHROPIC_API_KEYas a Cloudflare secret - create the
noti-recommendationsCloudflare Queue - apply D1 migrations to
noti - add allowed user DIDs to
invite_allowlist
Then:
bun run deploy
Current deployment: https://noti.n8-3e9.workers.dev