Self-hosted, single-user, keyboard-first task manager — a Todoist-compatible open alternative.
Formerly OpenDoist — renamed in v0.4.0; every legacy surface (env vars, tokens, backups, data files) keeps working. See Migrating from OpenDoist.
OpenTask is a task manager you run yourself: one container, one /data volume, one account. It speaks
the Todoist workflow you already know — the Quick Add grammar, the filter language, the keyboard map —
without the cloud, the subscription, or the second user you never wanted.
Everything below is shipped, tested, and in main.
Capture
| Feature | Notes |
|---|---|
| ✅ Quick Add grammar | Full Todoist syntax — natural-language dates (tom 4pm, mid january, bare 6pm → today-or-tomorrow), #project /section @label p1–p4, {deadline}, !reminders, for 45min duration, plus // description and a leading * for uncompletable headers |
| ✅ Recurrence engine | every / every! (advance from schedule vs. completion), workdays, ordinals (every 3rd friday, every last day), day/date lists, starting / until / for bounds — DST-safe and property-tested |
| ✅ Ramble (voice capture) | Hold-to-record → pluggable STT (OpenAI-compatible / Deepgram / ElevenLabs / self-hosted Whisper) → optional LLM task extraction → review & confirm |
Organize
| Feature | Notes |
|---|---|
| ✅ Tasks & subtasks | Priorities (1 = highest), durations, deadlines, markdown content, comments with attachments, soft delete |
| ✅ Projects & sections | Nested projects, sections, a 20-color palette, favorites, drag-to-reorder |
| ✅ Labels | @label with colors and dedicated label views |
| ✅ Filters | The Todoist filter language — & | ! ( ) , panes, date/deadline/created operators, p1–p4, @label* wildcards, #Project / ##Project (with descendants) / /Section, search:, subtask, view all |
| ✅ Search | SQLite FTS5 across content, descriptions, and comments |
Plan
| Feature | Notes |
|---|---|
| ✅ Views | Inbox · Today (overdue + reschedule) · Upcoming (week strip, drag between days) · Project / Label / Filter (comma = multiple panes), with per-view layout (list or kanban board), group / sort / filter |
| ✅ Keyboard-first | Full web shortcut map, ? shortcuts overlay, 10 s undo toasts |
| ✅ Command palette | ⌘K fuzzy navigation and actions |
| ✅ Productivity | Daily/weekly goals, streaks, karma, vacation mode, an activity feed, and unlimited history |
Remind
| Feature | Notes |
|---|---|
| ✅ Web Push | Installable-PWA push on desktop and mobile (iOS 16.4+ works after Add to Home Screen), with automatic offsets and recurring reminders |
| ✅ Notification channels | ntfy, Gotify, and webhook delivery as alternatives or backups to Web Push |
| ✅ iCal feed | Read-only tasks calendar for Google / Apple Calendar via a tokenized webcal:// URL |
Own your data
| Feature | Notes |
|---|---|
| ✅ Todoist importer | Backup ZIP upload or a live API token — projects, sections, tasks, labels, and comments (priorities remapped, since Todoist stores 4 = highest) |
| ✅ Export | Full JSON snapshot plus per-project CSV |
| ✅ Backups | Nightly VACUUM INTO snapshots with retention and one-click restore |
Platform
| Feature | Notes |
|---|---|
| ✅ PWA + offline | Installable app with a Workbox app shell; last-viewed lists stay readable offline |
| ✅ REST API | Hono, every route zod-typed → OpenAPI + Scalar docs at /api/v1/docs, cursor pagination, SSE live updates, scoped ot_… API tokens |
| ✅ CLI | opentask add "…" with the identical parser; --json on every read command |
| ✅ Auth | Password + TOTP 2FA, generic OIDC SSO; registration auto-locks after the first user |
Non-goals (v1): collaboration/sharing, the calendar layout, CalDAV, an email reminder channel, native mobile apps (the PWA is the mobile story), and localization.
OpenTask is one container writing to one volume:
docker run -d --name opentask -p 7968:7968 -v ./data:/data ghcr.io/pranav-karra-3301/opentaskOr with Docker Compose:
services:
opentask:
image: ghcr.io/pranav-karra-3301/opentask:latest
container_name: opentask
ports: ["7968:7968"]
volumes: ["./data:/data"]Then open http://localhost:7968 and create your account. Registration locks automatically after the
first user; re-open it with OPENTASK_ALLOW_REGISTRATION=true. HTTPS is required for Web Push and PWA
install (localhost is exempt) — see docs/install.md.
OpenTask v0.4.0 is a rename of OpenDoist — same data model, same API, same image lineage. An existing deployment upgrades in place; every legacy surface is honored:
| Legacy surface | What happens |
|---|---|
OPENDOIST_* env vars |
Still honored as fallbacks (a boot warning suggests renaming to OPENTASK_*) |
opendoist.db in the data dir |
Renamed to opentask.db (with WAL sidecars) automatically on first boot |
od_… API tokens |
Keep working — verification is by hash; new tokens mint as ot_… |
Old backup zips (opendoist.db entry) |
Still restorable |
opendoist / od CLI names |
Kept as aliases of opentask / ot (Docker image and npm bin) |
ghcr.io/pranav-karra-3301/opendoist |
Frozen at ≤ 0.3.x — switch to ghcr.io/pranav-karra-3301/opentask |
The old GitHub repo URL redirects. The JSON export format marker is now opentask-export.
The CLI talks to your instance with the same Quick Add parser as the web app. It ships inside the
container (with an ot short alias; the legacy opendoist/od names still work), so the quick
start above already installed it — create an API
token in Settings → Integrations, then:
docker exec -e OPENTASK_TOKEN=ot_… opentask opentask add "Pay rent tomorrow 9am p1 #Home"
docker exec -e OPENTASK_TOKEN=ot_… opentask opentask today(The image already points OPENTASK_URL at the bundled server, so the token is all it needs.)
npm package:
npm install -g opentaskis planned but not published yet at 0.1.0. Until it lands, use the bundled binary above, or build from a source checkout withpnpm --filter opentask buildand runnode packages/cli/dist/index.js.
Full command reference — including opentask login and env-var configuration — in
docs/cli.md.
Full docs live in docs/:
- Documentation index
- Install & first run
- Configuration (environment variables)
- Import from Todoist
- Voice capture (Ramble & STT)
- Backups & restore
- REST API
- Command-line client
- FAQ
Requires Node ≥ 22 and pnpm 10.
git clone https://github.com/pranav-karra-3301/opentask.git
cd opentask
pnpm install
pnpm verify # lint + typecheck + test + build, everything CI runsHandy during development:
pnpm --filter @opentask/core test # core engine test suites (golden tables + property tests)
pnpm --filter @opentask/web dev # web app (Vite)
pnpm seed # load a demo account with example data
pnpm lint:fix # Biome, auto-fixSee CONTRIBUTING.md for commit conventions and the design-token rules.
| Layer | Choices |
|---|---|
| Runtime | Node.js ≥ 22 · single Docker container · SQLite on one /data volume |
| Monorepo | pnpm workspaces + catalog · TypeScript (strict) · Biome 2 · Vitest 4 + fast-check |
Core (packages/core) |
zod 4 · chrono-node · date-fns 4 + @date-fns/tz · temporal-polyfill + rrule-temporal — pure, zero-IO, shared by web/server/CLI |
Server (apps/server) |
Hono 4 + @hono/zod-openapi · Drizzle + better-sqlite3 · better-auth · croner · web-push |
Web (apps/web) |
Vite 8 · React 19 · Tailwind 4 · TanStack Query + Router · Base UI · dnd-kit · cmdk · vite-plugin-pwa |
CLI (packages/cli) |
commander · tsdown · bundled in the Docker image as opentask / od (npm publish planned) |
| Releases | Conventional commits · git-cliff changelog · GHCR images (amd64 + arm64) |
Brand icon derived from "List" by Glyphy (Noun Project), licensed CC BY 3.0 — details in assets/brand/ATTRIBUTION.md.
