Features
Everything the bot does, today.
No 'coming soon', no waitlist, no roadmap-only headers. Six capabilities, live on the bot right now.
Capture
Everything in becomes an item. Type, forward, drop a voice note.
Natural-language to-dos
Type "buy milk" or "tomorrow 9am dentist" — the bot creates the item, sets the deadline, drops it on the list.
Forward-to-capture
Forward any Telegram message into the chat (DM or group, bot mentioned). Up to 20 distinct action items extracted in a single turn.
Voice notes — DM
Drop a voice message in DM. Transcribed via OpenRouter Gemini 2.5 Flash and routed through the same item-capture flow.
Voice notes — group ambient
In groups the bot listens to every voice note silently. To-dos surface as items; chatter never becomes a message. No reply spam, no token waste.
Photo / document / file attachments
Bot uploads attach to the most recently mentioned item. Stored as Telegram file_id references — zero local disk, zero S3 bill.
Organize
Lists per chat. Checklists for multi-step work. Tags for everything.
One list per Telegram chat
Every chat (DM or group) is its own to-do context. /items shows the open list for the chat you're in.
Checklists with gate-complete
Group multi-step work under one umbrella. Parent can't close while any child is open — the bot blocks the action and surfaces the unfinished children.
Cascade-archive on delete
Delete a parent checklist; all open children are archived in the same transaction. Confirmation phrase explicitly states the child count.
Memory mode
Tickets, docs, receipts, warranties — long-lived keepsakes that never auto-archive. /memory lists them; deletion requires explicit confirmation.
Tags
Free-form tags by prefixing #. "Buy bread #shopping" lands tagged. /tag shopping filters the list to that tag's open items.
Tag-based assignment
"Assign the report to Michael" creates an item tagged #michael. /tag michael lists Michael's items. No per-user role grants, no permission UI to babysit.
Smart views
/today, /thisweek, /done, /reminders — pre-canned views, all chat-scoped. Replies stay tight: counts + tappable rows + the right action buttons.
Remind
Natural-language scheduling. Routes to the right chat.
Natural-language scheduling
"Remind me about the milk in 1 hour" or "remind me Friday 6pm". Deadlines and reminders both get parsed from one sentence.
Button preset menu
Tap ⏰ on any item → preset offsets (5 min, 1 hr, tomorrow morning…). Faster than typing for routine intervals.
Group-aware routing
Reminders set on a DM item ring in DM. Reminders set on a group item ring in the group — so the whole team sees it.
Multiple reminders per item + RRULE
Stack reminders ("30 min before deadline" + "day-of 9am"). RRULE recurring supported for daily / weekly / monthly patterns.
Per-minute cron
A separate cron container polls every 60 seconds and dispatches due reminders. Idempotent — never double-sends.
Secrets, privacy, security
Credentials stay encrypted. Chat data stays in the chat.
/password — encrypted vault
Save credentials in a 3-step DM flow (label → username → password). AES-256-GCM at rest via ENV_KEY. Plaintext never reaches the database.
15-second self-destruct reveal
Asking for a password sends a Telegram message with HTML <code> tap-to-copy. The bot auto-deletes the message after 15 seconds.
DM-save, group-aware reveal
Save the secret in DM (always); the secret is scoped to its chat. Reveal works in the originating group as long as the requester is a chat member.
Per-chat isolation
Every database query is scoped to the Telegram chatId. Callback handlers verify (itemId, chatId) before any mutation — a guessed UUID from another chat resolves to nothing.
Constant-time webhook auth
The Telegram webhook authenticates via crypto.timingSafeEqual on the secret token header. No timing oracles, no header smuggling.
Audit log
Every mutation writes an activity_log row with payload_before / payload_after. Useful for undo, debugging, and explaining what the bot did.
Conversation + onboarding
How the bot greets new users and lets you tune it.
/onboarding — interactive walkthrough
8 steps, edits a single message in place. Covers to-dos, checklists, tags, reminders, /password, voice notes, /settings. Skip anytime.
/settings
One screen for language (TR / EN), notification toggle, date/time format, and your own OpenRouter key (set via force-reply paste; remove falls back to free tier).
/reset
Clears the LLM conversation history for this chat. Items, reminders, and memory are untouched — the bot just forgets the back-and-forth.
Bilingual replies
Bot replies in Turkish or English based on users.locale. Switch from /settings; bot remembers per-user, not per-chat.
BYOK + free-tier model
Bring your own OpenRouter key, or use the operator's shared free tier.
Free-tier on first message
Without any key, the chat runs on the operator's shared OpenRouter key + a free model. Zero cost, basic quality. 100 messages/hour during trial.
Voice off on free tier
Voice transcription needs a paid audio model. The free tier silently rejects voice and tells the user to add a key for it.
One key per chat
Set your own OpenRouter key via /settings → 🔑. Stored AES-256-GCM-encrypted; only the chat owner can set or remove it. Rate limit lifts; voice unlocks; better models open.
Per-user hourly cap
Self-host operators set LISTBULL_PER_USER_HOURLY_MSG_LIMIT to prevent runaway spend from a noisy user. Hosted prod runs 100/hour on free tier.
Self-host posture
Runs on a 5€ VPS. Yours to operate.
One Docker compose stack
postgres + app + cron. No managed dependencies. Bring your own reverse proxy (Caddy / Traefik / Cloudflare) for TLS.
Cron auto-applies migrations
Every cron container boot runs `drizzle-kit migrate` first (idempotent — already-applied migrations are skipped). New schema lands on the next deploy.
Telemetry off by default
Self-host setups don't ship a single byte to third parties. Sentry + Umami are opt-in via build args. Hosted prod.listbull.org runs both (cookieless Umami + Sentry crashes).
Attachments live on Telegram CDN
Bot only stores `telegram_file_id` references; the bytes never touch your disk. Zero storage cost, zero backup burden. (Bot token rotation invalidates all file_ids — plan the rotation.)