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.)