Skip to content

Releases: pixari/OpenTodo

OpenTodo v0.6.1

Choose a tag to compare

@pixari pixari released this 17 Oct 04:54
62cc132

OpenTodo 0.6.1 makes plain-http installs work: opened by a home server's or NAS's address (http://192.168.1.10:8080), the app no longer shows Offline with nothing saved. It adds an Unraid template, and fixes encryption turning off part-way, settings pages scrolling away, and two small things in the task panel.

Upgrade notes

  • No migration, no new environment variables, no sync or API change. Replace the image or the binary and restart.
  • Image tags. The release publishes ghcr.io/pixari/opentodo:0.6.1 and moves :0.6, so installs that follow :0.6 (Coolify, Unraid) get it from their usual update.

Added

  • Unraid template. A Community Applications template sets up the container on Unraid: the release image, the Web UI on port 8080, the appdata folder on /data, and the optional settings with descriptions; nothing is required. Until it is listed in Apps, add it from the template URL. The template is published in its own template repository, pixari/opentodo-unraid, from a checked copy in deploy/unraid/upstream/. The guide covers appdata permissions (the image ignores PUID and PGID), https behind a reverse proxy, updates and backups. (Unraid)

Fixed

  • Repeat says what it accepts, and the time zone button shows once. The repeat field takes any interval or pattern, such as every 3 months or every 10 days after completion, not only the suggestions; it now says so under the empty field, suggests every 3 months, and keeps its example rule in English in every language (rules are written in English). In the task panel the time zone button appears beside a due date only when the due has a time, and no longer twice while the When editor is open. (Recurring tasks and reminders)
  • Plain-http installs on a network address work. Opened as http://<address>:<port> on a home server or NAS (for example Unraid), the app showed Offline and nothing you added was saved, because it used a browser function that only exists over HTTPS. Adding and editing, sync and attachments now work over plain http too; installing the app, push notifications, passkeys and end-to-end encryption still need HTTPS. (Docker)
  • Settings no longer scroll past the end of the page. On General, Integrations, People and Server, the whole app could be scrolled up and away, leaving an empty page below the last card. Labels that are only read out by screen readers sat outside the scrolling area and stretched the page; they now stay inside it. The layout check fails any screen where the page itself scrolls.
  • Turning encryption off no longer stops part-way. With a task or project note on the account, the re-write to plaintext (and, on a fresh page load, the re-write to ciphertext) failed after its first batch with "Transaction has already completed" when the note code still had to be fetched: the fetch let the browser close the database transaction under it. The code is now loaded without letting the transaction go, and an interrupted run still resumes where it stopped. (End-to-end encryption)

Install

  • Docker: docker run -d -p 8080:8080 -v opentodo:/data ghcr.io/pixari/opentodo:0.6.1
  • Binary: download opentodo-<os>-<arch> below, then run it (data goes to ./data).
  • Command-line client: ot-<os>-<arch>. Browser extension: opentodo-browser-extension.zip.

Verify downloads with sha256sum -c SHA256SUMS. Self-hosting guides: docs/self-hosting.

OpenTodo v0.6.0

Choose a tag to compare

@pixari pixari released this 16 Oct 15:53
761e83e

OpenTodo 0.6.0 speaks your language and looks back as well as ahead. The interface comes in English, German, French, Spanish, Italian and Portuguese. Statistics and a guided weekly review show what you finished, what slipped and what has no next action, computed on your device, with an optional weekly digest by email. Filter by completion date (completed = last week) and a day-by-day Completed logbook answer "what did I do this month?". Habits keep a streak and a month history, custom fields add typed values to a project's tasks, and display mode puts a view full screen on a wall tablet or an e-ink panel. Importers from Todoist, TickTick, Linear and Things keep more of what you had, and operators can run many OpenTodo servers in one process with host mode. Clicking a task's circle completes it again.

Upgrade notes

  • Migration 0034 (weekly digest settings) is applied automatically at startup. Back up /data before upgrading: there are no down-migrations.
  • No new environment variables are required. Host mode is off unless OPENTODO_HOST_URL is set; OPENTODO_HOST_TOKEN (required only with it), OPENTODO_HOST_OPERATOR_ADDR, OPENTODO_HOST_IDLE_MINUTES, OPENTODO_HOST_MAX_OPEN and OPENTODO_HOST_LIMITS configure it. A self-hosted server behaves exactly as before.
  • Sync is additive: the entities field and review, the task fields habit, skipped, completed_by and fields.<id>, and the user_prefs field language. Older clients ignore them; upgrade the server before the devices, as for every new field.
  • New routes: /api/v1/fields, GET/PUT /api/v1/me/email-digest, GET /api/v1/export/archive (owner), and completed_after/completed_before on GET /api/v1/tasks. All require authentication; the digest settings write is refused on the demo.
  • The installed app downloads the five language catalogs once (about 100 kB gzipped each) so a language switch works offline; the precache grows from about 2.7 to 4.4 MiB.
  • Binary size is about 27 MB (24 MB in 0.5): mostly the language catalogs.
  • Image tags. The release publishes ghcr.io/pixari/opentodo:0.6.0 and :0.6 for linux/amd64 and linux/arm64 (:latest follows main). The Coolify template now follows :0.6; if you use :0.5, change the tag in Edit Compose file and click Deploy.

Added

  • The app in your language: English, German, French, Spanish, Italian and Portuguese. Settings → General → Language picks the interface language for every device of the account (or System, the browser's first shipped language), and the app switches at once, without a reload, also offline once a language has been loaded on the device. Month and weekday names, the clock and the date order on System follow it with the browser's region kept (Swiss German stays Swiss German); quick add and voice capture try it first; reminder notifications (Snooze 10 min, Dismiss, the due date) are written in it by the service worker; server errors are shown in it by error code; the browser extension follows the browser's language. Tasks, project and label names, filter queries and repeat rules are never translated, and the documentation and the Help guide stay English (Help says so). Each language is a separate chunk of about 100 KB gzipped, loaded only when chosen and precached for offline switching; the main chunk grows by about 6.5 KB gzipped. Sync is additive (user_prefs.language); make check now runs catalog and untranslated-string checks. (The app in your language, Translating OpenTodo)
  • Custom fields per project: text, number, date, choice, link and checkbox values on tasks, filterable, exported, in the API and the assistant tools. Fields… in a project's menu (Shift+F) defines up to 30 typed fields, for editors and above; each task of the project then has a Fields group in its panel, rows and board cards show up to three values as badges, and on a wide screen the list offers a Columns layout, remembered per project on the device. Values work offline and converge field by field: two people editing different fields of one task both keep their change. Filter with cost > 100, client = "Acme", "Order date" <= friday or no client. A task moved to another project keeps its values, hidden until it comes back; deleting a field hides its values without touching them. The REST API has /api/v1/fields and a fields object on tasks, the export and own-export import carry both, webhooks deliver the values, and the MCP tools list a project's fields and set values. On end-to-end encrypted accounts field names, options and text values are encrypted. Sync is additive (the field entity and the task's fields.<id> values); upgrade the server before the devices, as for every new field. (Custom fields, Filter queries, API)
  • Statistics and weekly review: on-device numbers, a guided review, an optional weekly digest by email. Statistics (g Shift+S, under More) shows for this week, last week, the last 4 or 12 weeks what you completed (each day of a recurring task once, skipped habit days never), created, completed late and let slip, and what is overdue, with bar charts per day, week, weekday and project; everything is computed on the device from your tasks, offline, and nothing is sent or stored. In shared projects a completion counts for whoever completed it (completed_by), the assignee for older tasks. Review (g r) walks four steps with live data: get the Inbox clear, look back at the week and what is overdue, give every project a next action or archive it, and look ahead seven days; Finish review syncs to your devices and the sidebar marks a review as due after seven days. In Settings → Notifications each user can opt in to a weekly digest email on their review day (needs outgoing email; not offered with end-to-end encryption, and turning encryption on switches it off; refused on the demo). Sync is additive (a personal review entity); migration 0034 adds the digest settings table; GET/PUT /api/v1/me/email-digest. (Weekly review and statistics, API)
  • Host mode: one process serves many OpenTodo servers. For operators of a hosted service: with OPENTODO_HOST_URL=https://example.cloud, each tenant is an ordinary data directory answering at <name>.example.cloud. Tenants open on their first request (running their migrations), close when idle unless a device holds a live stream, and at most OPENTODO_HOST_MAX_OPEN stay open. One scheduler runs reminders, backups, Trash retention, webhooks, calendar fetches and weekly digests for tenants with work due only, so thousands of idle tenants cost nothing. Per-tenant limits on storage, changes per hour and in total, requests, import size and members refuse single changes with a named reason while the rest keeps syncing; the app keeps a refused change and shows it as waiting. Outgoing email, single sign-on, backup destinations, attachment limits and the AI switches belong to the operator. A token-authenticated operator interface on its own address creates tenants (empty with a setup link, or from any backup archive), suspends, resumes, deletes and exports them. (Host mode)
  • Owners of a hosted server can take their data away. Settings → Server → Download your data saves the whole server as one backup archive that opentodo restore reads, so moving to a self-hosted server takes one download. (Host mode, API)
  • Habits: track a repeating task as a habit with a streak and a month history; skip keeps the chain. Turn on Track as a habit under a task's repeat rule (any rule except after completion). Its row shows a streak chip, and the task panel shows the current and best streak and a month grid of done, skipped, missed and upcoming days, navigable with the keyboard. Everything is computed on the device from the series' occurrence records, offline too. Skipping a habit records the day as skipped, so the streak holds; a scheduled day that passes without a record breaks it. Skipped days are not completions: they stay out of Completed and completed filters and never count towards for N times. The new habit filter keyword makes a Habits saved view one word. Sync is additive (the task fields habit and skipped); upgrade the server before the devices, as for every new field. (Recurring tasks and reminders, Habits reference)
  • Filter by completion date. completed = last week, completed >= 7 days ago or ##Work & completed >= this month list what you finished; a completion date implies completed tasks. Every date term also takes periods: this week, last week, next week, this month, last month, next month, 2 weeks ago, 3 months ago, where = means within the period and weeks start on your first day of the week. Saved views keep the period, so "last week" moves with the calendar. Closes #86. ([Filter queries](https://gi...
Read more

OpenTodo v0.5.0

Choose a tag to compare

@pixari pixari released this 16 Oct 07:15
c21b4ba

OpenTodo 0.5.0 is a new interface on the same data. The task panel is part of the frame and reads like a summary, the sidebar is shorter, Settings has nine sections with a search field, every keyboard shortcut comes from one registry and ? lists the ones for where you are, and on a phone there is a tab bar, a + button and full-screen tasks. Around it: Process the Inbox one task at a time, a rich-text note at the top of every project, public links that share a project's list with anyone, optional outgoing email for password resets, verified sign-up and invitations, a Month calendar and a project Timeline, calendar feeds in both directions, attachments, tasks that wait for other tasks, bulk changes, duplicates and templates, and search and commands on Ctrl+K. Every help page is now short and opens with a screenshot.

Upgrade notes

  • Migrations 0031, 0032 and 0033 (calendar feeds, public links, pending sign-ups) are applied automatically at startup. Back up /data before upgrading: there are no down-migrations.
  • No new environment variables are required. OPENTODO_CALENDAR_FEEDS, OPENTODO_SMTP_* and OPENTODO_ATTACHMENTS_* are optional; everything they configure is off, or has a default, until you set it or the owner turns it on in Settings.
  • Sync is additive: the project fields icon, description and notes_doc, the task field blocked_by, the attachment entity and the user_prefs fields sidebar_destinations, density and first_run. Older clients ignore them; a 0.4 device keeps syncing.
  • Two families of anonymous routes are new: GET /api/v1/public/{token} with POST …/tick (public links) and the password-reset request and sign-up verification routes (outgoing email). All are rate limited, re-check their secret on every use, and are refused on the demo. Nothing is reachable without a link or without SMTP configured.
  • Settings moved. The fourteen sections of 0.4 are nine; old addresses such as /settings/security and old help ids open the right section at the moved rows. The activity feed is Updates at /updates (old links redirect). Owner settings for attachments, outgoing email and the audit log live under Server.
  • Some shortcuts changed. Skip occurrence is Shift+K, Shift+↓ / Shift+↑ extend a selection, . opens the row's menu; the keys printed in the app return with Show shortcut hints. Press ? for the current list.
  • Binary size stays at about 24 MB. (The email templates briefly pulled in text/template, whose reflection stops the linker from pruning unused code and had grown the binary to 37 MB; they are plain placeholders again.)
  • Image tags. The release publishes ghcr.io/pixari/opentodo:0.5.0 and :0.5 for linux/amd64 and linux/arm64 (:latest follows main). The Coolify template now follows :0.5; if you use :0.4, change the tag in Edit Compose file and click Deploy.

Changed

  • A calmer frame. The task panel is now part of the app's frame: it stays put while the list scrolls, keeps its task in the address (reload or share a link and it reopens), and opens the same way from every list, the calendar, filters and dashboards. The sidebar scrolls as one, with Help and your account always at the bottom and Labels as their own group. Task rows line up across every view and show a second line only when there is something to show. The duration filter lives under a Filter button in the list's header, with one chip while it's on; the Inbox no longer labels every row "Inbox". Press ? for a searchable cheat sheet that lists the shortcuts for where you are first. (Views, Keyboard shortcuts)
  • A task panel that reads like a summary. The checkbox and title stay at the top while you scroll, with Expand opening the task as its own page. Notes are one quiet line until you click them. The properties are chips that read their values, with Do on and Priority always there and everything else under Add (each entry with its shortcut); a chip opens its editor in place, and the date chips share one When editor for the due date, start, deadline, evening, repeat and reminders. Subtasks are a checklist with a quiet add line, attachments start as one Attach action, the comment box stays at the bottom of the panel, and Activity starts with when the task was created and completed. Completing, deleting, moving, rescheduling or parking a task offers Undo in a toast, offline too. (Tasks and projects)
  • For contributors: a page template, a tooltip and skeleton, sidebar building blocks, a style lint over the screens and an interface budget every screen change states (Interface guide).
  • A shorter sidebar and clearer names. The sidebar starts with Inbox, Today, Upcoming and Calendar; Anytime, Someday, Assigned to me, Completed, Updates, Trash and Filter wait under More (the unread count shows on its header while it is closed), and any of them can be promoted next to the primary four from Settings → Preferences. Calendar is one destination that remembers Day or Week, with its planning list in the panel. The sidebar's "Views" group is now Filters, the activity feed is Updates at /updates (old links redirect), and Settings → You → Activity reads Sessions and audit log; the search box still answers to the old words. Every page shares one header with its title, actions, a ⋯ menu and a Help button that opens the guide for that screen; projects keep Share and the List/Board switch in it, with Activity and History opening in the panel from the menu, and sub-projects listed as a collapsible group above the tasks. Lists hide empty date groups and an empty "No section", keep a section with only completed tasks as "n completed" with Show, and remember which groups you collapsed on each device. Help opens on its search with eight common tasks before the guides, and quick add links to its guide for your first three tasks. (Views, Settings)
  • Settings in nine sections. Settings is one layout: the list of sections (your profile, a Search settings field, the groups You, App, Data and Server) is the left column on a wide screen with Account already open, and the whole screen on a phone where each section opens as a page with a back link. The sections are Account (profile, sessions, password, two-factor, passkeys, linked accounts, encryption), Appearance, General, Notifications, Capture, Integrations (now with the assistant and AI assistants), Data (with archived projects), People (users, members, access policies and single sign-on) and Server (backups, attachments, the audit log). Old addresses such as /settings/security open the right section at the moved rows. Search finds a setting by name or by what it does, in Settings and in the command palette ("passkey" opens Account at the passkeys row). Every card has the same shape: a heading, one sentence, rows with the state as a badge beside the label, and the Help button sits once in the page header. Appearance gains Density (Comfortable or Compact, synced, touch targets kept on phones) and the sidebar switches. On the demo, every section is listed and the rows it refuses are shown disabled under one note. (Settings)
  • One shortcut registry. Every keyboard shortcut is declared once, with the scope it belongs to (everywhere, a view, a task list, the board, the calendar, the task panel, the notes editor or the Vim layer), and one dispatcher resolves a key in the innermost scope on screen, so a key runs one action and never two. The ? cheat sheet, the keyboard guide and the shortcut column of the command palette all read the registry. Resolved clashes: Skip occurrence is now Shift+K (in a list and in the panel) while Shift+S stays Share project; s schedules in a list and saves in Filter; . opens the focused row's menu or the Actions menu; a adds a subtask in a list and a card in a board column; Shift+↓ / Shift+↑ extend a ticked range (Shift+J / Shift+K no longer do). Shortcut hints live in tooltips, menus and the palette; the keys printed in the app itself (quick add's q, the sidebar's g keys, prompts) return with Show shortcut hints in Settings → General → Keyboard, per device. The palette groups its results under Recent, Tasks, Projects, Labels, Filters, Commands and Settings. (Keyboard shortcuts)
  • Built for a phone. Below 768 px a bar at the bottom of the screen switches between Today, Inbox, Upcoming, Search and More (the sidebar as a drawer), and a round + button adds a task from any page as a bottom sheet with the page's defaults and the keyboard up; both step aside while a sheet or a task is open. A task opens as a full-screen page with Back, or a swipe down on its header, to close it. A project's board shows one column at a time with a dot pager and the column's name under the title, and "No section" is a column only while it has open tasks. The Week calendar is a day-by-day list on a phone. The sidebar's project chevrons are full-size touch targets. (Getting started, [Installing the app](https://github.com/pix...
Read more

v0.4.0: Merge pull request #45 from pixari/chore/site-bundle-3-2-done

Choose a tag to compare

@pixari pixari released this 15 Oct 05:50
b28bdaf
site-bundle 3.2 verified with v0.3.1-rc.1

OpenTodo v0.3.1-rc.1

OpenTodo v0.3.1-rc.1 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 15 Oct 03:47
2693445

A release candidate that tests the release pipeline: the release now attaches opentodo-site-bundle-v0.3.1-rc.1.tar.gz (the documentation website, screenshots, colour tokens, icons, changelog and feature manifest for the website) next to the binaries, listed in SHA256SUMS. It carries everything under Unreleased above; it is not a supported release, and the :0.3 and :latest image tags do not move.


Install

  • Docker: docker run -d -p 8080:8080 -v opentodo:/data ghcr.io/pixari/opentodo:0.3.1-rc.1
  • Binary: download opentodo-<os>-<arch> below, then run it (data goes to ./data).
  • Command-line client: ot-<os>-<arch>. Browser extension: opentodo-browser-extension.zip.

Verify downloads with sha256sum -c SHA256SUMS. Self-hosting guides: docs/self-hosting.

OpenTodo v0.3.0

Choose a tag to compare

@pixari pixari released this 13 Oct 06:52
08476fc

OpenTodo 0.3.0 is about bringing your own AI, if you want one. There is a chat assistant inside the app that answers questions about your tasks and proposes changes you review and undo in one step, with Anthropic, OpenAI, Gemini or a model on your own network. An assistant you already use can now make changes over MCP, and the ot command is ready to be driven by coding agents. All of it is off until the owner turns it on; nothing is sent anywhere before that. Use AI with OpenTodo compares the three options. Settings is also split into sections with their own pages, and a project can be shared with a single invite link.

Upgrade notes

  • Migrations 0026 to 0029 (agent tokens and switches; assistant consent and usage; members' own assistant provider; project invite links) are applied automatically at startup. Back up /data before upgrading: there are no down-migrations. No new environment variables are required; OPENTODO_MCP_WRITES is optional.
  • Image tags. The release publishes ghcr.io/pixari/opentodo:0.3.0 and :0.3 for linux/amd64 and linux/arm64 (:latest follows main). The Coolify template now follows :0.3; if you use :0.2, change the tag in Edit Compose file and click Deploy.
  • ot scripts: destructive commands now need --yes off a terminal, and refusals exit 5 instead of 1 (see Breaking below).
  • Binary size. The server binary grows from about 17 MB to about 23 MB, mostly the official Anthropic SDK used by the assistant.

Breaking

  • ot: destructive commands need --yes without a terminal. ot rm, ot project rm, ot token revoke and ot auth logout used to proceed silently when stdout was not a terminal or --json was given. They now refuse with exit code 2 (confirmation_required) before sending anything. Migration: add --yes to scripts and cron jobs that delete on purpose, e.g. ot rm "$ID" --yes. On a terminal without --json they still ask. (CLI)
  • ot: new exit code 5, "not permitted". Refusals for scope, role, a switch, encryption or read-only mode (insufficient_scope, forbidden, not_permitted, writes_disabled_by_owner, writes_disabled_by_user, encryption_enabled, read_only) exit 5 instead of 1, so scripts and agents can stop instead of retrying. Migration: scripts that test for exactly 1 should also accept 5; scripts that test for non-zero are unaffected. The op log and the REST API are unchanged.

Added

  • Invite to a project with a link. In a project's Share dialog, the owner and admins can create a single-use invite link with a role (viewer or editor; admin for the owner), an optional email binding and an expiry from 1 hour to 30 days (default 7 days). The link is shown once; pending links are listed with their role, email, expiry and creator and can be revoked. Opening /invite/p/<token> shows who invited you to which project: signed in, you select Join project; otherwise you sign in and join, or create an account that joins in the same step. A link creates accounts only when its creator is the server owner or an admin, when open sign-up is on, or when the owner switches on Members can invite new people with project links in Settings → Administration (off by default); otherwise the page asks the person to get an account first. Links stop working when revoked, used or expired, when the project is deleted, or when their creator is no longer the project's owner or an admin. Links are server-side data, never synced; refused on the demo instance. (Sharing, API)

  • New routes: GET/POST /api/v1/projects/{id}/invites, DELETE /api/v1/projects/{id}/invites/{inviteId}, GET /api/v1/project-invites/{token} (public preview), POST /api/v1/project-invites/{token}/accept, GET/PUT /api/v1/settings/project-invites; POST /api/v1/auth/register accepts projectInvite. New error code project_invite_not_allowed; audit events project_invite.created, project_invite.revoked, project_invite.accepted. Migration 0029_project_invites.sql is applied automatically.

  • Your own assistant provider. When the owner lets members bring their own key, each person can choose Anthropic, OpenAI or Google Gemini, a model and their own key in Settings → AI → Assistant → Which assistant you use, with Test connection. Members are never offered the compatible endpoint, so they cannot make the server connect to an address of their choosing. The disclosure names the provider actually used ("from this server to … with your own API key") and is asked again when it changes. Turning member keys off makes everyone use the owner's provider again; choices are kept for later. Keys stay in <data>/secrets/assistant.json, never returned, logged, exported or backed up. (AI assistant)

  • Own keys outside the allowance. Answers on a member's own key are recorded and shown as "your key", but neither counted nor stopped by the monthly token allowance unless the owner turns on the new Count members' own keys toward the monthly limit (cap_member_keys). One answer per person and 8 per server still apply. The owner sees how many people use their own provider and key.

  • API (additive): own_provider, own_model and new status fields on GET/PUT /api/v1/me/assistant; POST /api/v1/me/assistant/test (signed-in sessions, 5 per 10 minutes); cap_member_keys and own_key_members on /api/v1/settings/assistant; counted_tokens and own_key on the usage route and own_key on the turn's usage event. (API)

  • AI assistant in the app. A chat panel (Shift+I or Assistant in the header; a side sheet on wide screens, full screen on phones) that answers questions about your tasks and proposes changes: "move everything overdue to Friday", "break this task into steps". Each proposal is a reviewable list with every change in words; you apply the checked part (at most 50 changes) and undo it in one step. Applied changes are ordinary edits from your device: offline-capable, synced, labelled Assistant in history. Providers, each with the owner's or a member's own key: Anthropic through the official Anthropic Go SDK (default claude-opus-5-5; claude-sonnet-5-5 and claude-haiku-5-5 offered), OpenAI, Google Gemini and any OpenAI-compatible endpoint, including Ollama or LM Studio on your network. Off by default: the owner enables it in Settings → Assistant (provider, models, keys, private endpoints, monthly token allowance, member keys, Test connection); each person accepts a disclosure naming the provider and the fields sent before their first message, and again when the provider changes. Keys live only in <data>/secrets/assistant.json, never returned, logged, exported or backed up. The assistant cannot change sharing, members, settings or tokens, make outbound requests or delete permanently; task text is marked as untrusted. Conversations stay on the device and are deleted at sign-out. Not available for end-to-end encrypted accounts or on the demo instance. Optional per-device auto-apply of up to 3 small, reversible changes, off by default. (AI assistant, API, security)

  • New routes: GET/PUT /api/v1/settings/assistant, POST /api/v1/settings/assistant/test (owner), GET/PUT /api/v1/me/assistant, GET /api/v1/me/assistant/usage, and POST /api/v1/assistant/turn (signed-in sessions only; streams server-sent events). /api/v1/sync accepts the op device prefix assistant:; history entries from it carry device_label: "Assistant".

  • Dependency: github.com/anthropics/anthropic-sdk-go (the server binary grows by about 5 MB; see the change's design notes).

  • ot for agents and automation (CLI): --json output is documented with JSON Schemas and output_version 1 (ot version --json); ot schema (or ot help --json) prints every command, flag, exit code, error code and output schema, offline; --dry-run on every write command resolves references and prints the requests it would send without writing; --idempotency-key on ot add and ot project add makes retries return the same entity; ot done/ot reopen on a task already in that state report unchanged and send nothing, and ot edit with unchanged values sends nothing; --read-only (or the optional OPENTODO_READ_ONLY=1) refuses every write before any request; ot refuses writes locally for read tokens and outside the allowed routes for agent tokens; ot auth status shows the token's scope and whether assistant writes are allowed. With --json, errors carry an additive exit field and stderr gets one ot: line; done/reopen/rm add ref and status to each task.

  • Agent skill file. ot skill prints SKILL.md, which teaches an agent to use ot safely (agent token, --json, dry runs, idempotency keys, exit codes, task text as untrusted data). Each release ships it as opentodo-agent-skill.zip.

  • Idempotency-Key on POST /api/v1/{collection}: the entity and op ids derive from your account, the collection and the key, so a retried create returns 200 with the stored entity and Idempotent-Replayed: true; the same key with other content answers 409 `...

Read more

OpenTodo v0.2.0

Choose a tag to compare

@pixari pixari released this 11 Oct 14:09
05c58f2

OpenTodo 0.2.0 is about trying it, using it on a phone and running it without fuss. Every visitor to the public demo now gets a private sandbox. The phone layout has been reworked so menus, pickers and dialogs fit small screens. There is a docs website and a Help view inside the app, which works offline. Archived projects can be restored with one click. Updates roll out without a Stop → Deploy. Rate limits work correctly behind trusted proxies and Cloudflare. The app meets WCAG AA contrast in light and dark, and this release includes several security fixes.

Upgrade notes

  • From 0.1.0, stop once. 0.1.0 locked the data directory exclusively, so a 0.2.0 container cannot start beside it. Plain docker compose pull && docker compose up -d works as before. With Coolify or another orchestrator that starts the new container first, click Stop, then Deploy for this one upgrade (otherwise the deploy fails with "data directory is in use by another opentodo process" and rolls back). From 0.2.0 on, updates roll without downtime. (Docker, Coolify)
  • Image tags. The release publishes ghcr.io/pixari/opentodo:0.2.0 and :0.2 for linux/amd64 and linux/arm64 (:latest follows main). The Coolify template in deploy/coolify/opentodo.yaml now follows :0.2; if you pinned :0.1, change it.
  • Migration 0025 (demo sandbox bookkeeping) is applied automatically at startup. Back up /data before upgrading: there are no down-migrations. No new mandatory environment variables; OPENTODO_TRUSTED_PROXIES, OPENTODO_DEMO_MAX_SANDBOXES and OPENTODO_DEMO_MAX_DB_MB are optional.
  • Behind a CDN or second proxy, set OPENTODO_TRUSTED_PROXIES (for example cloudflare) so rate limits and the audit log see visitors' addresses. (Reverse proxy)

Added

  • User documentation: seventeen task-based guides for people using the app (getting started, installing the app on iOS, Android and desktop, tasks and projects, views, sections and boards, labels and filters, recurring tasks and reminders, time blocking, sharing and comments, notifications, offline and sync, keyboard shortcuts, account security, import and export, trash and history, settings, troubleshooting and FAQ), with light and dark screenshots generated from the demo data (make docs-screenshots). Every page in docs/ has front matter (title, summary, audience, the capabilities it covers, the app screens it explains). (Docs)
  • Docs website at opentodo.pixari.dev/docs, generated from docs/ by make docs into website/docs/: grouped by audience, in-browser search over a prebuilt index (nothing typed leaves the browser), light and dark, readable without JavaScript, "On this page", previous and next, the version described and "Edit this page on GitHub". "Docs" is in the website's navigation.
  • Help inside the app: a Help view with the user guide of the running version, searchable and available offline (a lazily loaded chunk, precached by the service worker; screenshots stay on the website). Open it from the sidebar, Settings, the ? overlay, g then ?, or :help <topic> with Vim keybindings. Settings sections, the share dialog, the Filter view, quick add and the import screen have a Help link that opens the matching section in a side panel (a full-screen sheet on phones) without closing what you were doing.
  • Unarchive projects: Settings → Projects lists your archived projects, with their parent and open task count, and a Restore button that brings one back to the sidebar. Restoring is an ordinary change, so it works offline and syncs to every device; sub-projects stay archived until restored on their own, a project restored by hand is not archived automatically again on that device, and in shared projects only the owner or an admin can restore. Previously only the automatic-archive notice could undo an archive. (Trash and history)
  • npm run docs:check (part of make check and CI) fails on missing front matter, broken links or anchors, images without alt text, capabilities in openspec/specs/ that no page covers, help links to unknown sections, a keyboard guide that differs from the app, and stale generated files. The shortcut table moved to web/src/lib/shortcuts.ts, shared by the ? overlay and the keyboard guide. The CI layout job also runs axe-core on the Help view, the help panel and the docs website, and checks the docs website at 360, 390 and 1280 px with and without JavaScript.

Changed

  • The public demo (OPENTODO_DEMO=true) gives every visitor a private sandbox instead of one shared account: "Try the demo" creates a password-less account with its own copy of the sample data and a non-interactive collaborator, and nobody sees anybody else's changes. Sandboxes are deleted after 2 hours of inactivity, 24 hours after creation and by the nightly reset, which now also runs VACUUM. The published demo password is gone; the first start deletes the old shared demo accounts. auth/status.demo carries a creation token instead of credentials; new route POST /api/v1/demo/sandbox, new error codes demo_expired, demo_limit, demo_busy and demo_token; optional OPENTODO_DEMO_MAX_SANDBOXES and OPENTODO_DEMO_MAX_DB_MB. Migration 0025 adds the sandbox bookkeeping tables. (Public demo)
  • Links in comments and notes render with rel="nofollow ugc noopener noreferrer" on every instance.

Security

  • Demo instances bound abuse: sandbox creation needs a single-use, signed, 10-minute token from the sign-in page and a same-origin request, at most 5 new sandboxes per address per hour (addresses are stored only as salted hashes), a live cap with idle eviction and a database size guard; each sandbox may write 600 ops per hour, 5,000 ops and 2 MB of values in total, values are capped at 4 KB (32 KB for notes), and above the database size limit live sandboxes cannot write either. Every demo response carries X-Robots-Tag: noindex, nofollow and the demo page declares noindex.

  • Per-address rate limits (sign-in, passkeys, two-factor, single sign-on, CalDAV, demo sandboxes) and audit-log addresses now use the last X-Forwarded-For hop, the one the reverse proxy appended, instead of the first entry, which the client controls behind an appending proxy such as Traefik and could change to evade the limits. Run one proxy in front of the server and do not publish its port. (Reverse proxy)

  • Behind a CDN, set the optional OPENTODO_TRUSTED_PROXIES (IP addresses, CIDR prefixes and/or cloudflare) so the CDN's hop is skipped and visitors are not all counted as the CDN's address. With cloudflare, requests from a Cloudflare edge use CF-Connecting-IP. (Reverse proxy)

Fixed

  • Phones: every menu, popover, picker and dialog now fits the screen. The notifications panel was cut off on the left; it, the mention picker and the section, project, label and view menus open as bottom sheets below 640 px and next to their button (kept inside the screen) above. Dialogs (rename, share, sign-in confirmation, user administration, voice consent, label and assignee pickers, keyboard help) are full screen on phones with a pinned close button, and all overlays close with Escape or a tap outside and return focus to their button. Touch targets are at least 44 px, row menus are visible without hover on touch screens, long words and URLs wrap, the sidebar scrolls on short screens, and layouts respect the safe areas and the on-screen keyboard. A new CI job opens every screen and overlay at 360, 390 and 768 px in Chromium and WebKit (make layout-check). (mobile-layout)
  • Contrast and accessibility across the app: secondary text (sidebar section names, counts, dates, descriptions), the "All" links, primary buttons (now a darker green, white text at 5.5:1), status and priority colours and dark-mode muted text all meet WCAG AA (4.5:1) in light and dark. Secondary text uses two theme-aware tokens, text-muted and text-faint. Label and assignee pickers no longer nest buttons inside list options, the priority buttons say which one is selected (aria-pressed), and the filter and view result lists are named regions. The layout check now runs axe-core on every screen and overlay in light and dark, not only on the Help view, and fails on serious or critical issues.
  • Task and project History names people, projects, sections and parent tasks instead of showing their ids, labels fields in words ("assignee" rather than assignee_id), and no longer lists writes that kept the value, such as the plain-text copy of a note rewritten when the note is upgraded.
  • Zero-downtime updates work again: several server processes may now use one data directory, so Coolify's rolling update (new container started before the old one stops) no longer fails with "data directory is in use by another opentodo process" and rolls back. Background jobs (reminder push, webhooks, backups, email polling, Trash cleanup, audit pruning, demo reset) run in one process only and move to the new one when the old one stops; maintenance commands still require ev...
Read more

OpenTodo v0.1.0

OpenTodo v0.1.0 Pre-release
Pre-release

Choose a tag to compare

@pixari pixari released this 11 Oct 05:22
791ec28

The first release, and the first feature-complete version: every item on the roadmap is implemented. Each feature was planned and built as an OpenSpec change; the archived changes under openspec/changes/archive/ hold the full proposals, designs and task lists, and openspec/specs/ the resulting behaviour contracts.

Upgrade notes

  • No mandatory configuration. Every new environment variable is optional and every feature that talks to the outside world is off until configured. The complete list is in the README.
  • Database migrations 0001 to 0024 are embedded and applied automatically at startup, in order, tracked by PRAGMA user_version (numbers 0016–0018 and 0020 are unused). Back up /data before upgrading an existing instance: there are no down-migrations. Rolling back to a binary older than user administration lets deactivated accounts sign in again.
  • Update the server before clients. The op schema only grew (new fields and entities, nothing renamed), but an older server rejects sync batches that carry fields it does not know; those ops wait in the device's outbox until the server is upgraded. Older clients keep syncing their personal data and skip ops for entities they do not know.
  • Sizes (measured for this release, linux/amd64): server binary 16,715,938 bytes (15.9 MiB) built with -trimpath -ldflags="-s -w", web app embedded; ot CLI about 6.9 MB; initial web bundle 261 KB JS + 10.7 KB CSS gzipped, with the rich-text editor (97 KB), voice recognition (4 KB) and Vim layer (4 KB) loaded on demand; idle memory about 18 MB on a fresh instance. The container image adds the distroless static base (about 2 MB) to the binary. Release assets: server and ot binaries for Linux, macOS and Windows (amd64 and arm64), the browser extension zip and SHA256SUMS; images ghcr.io/pixari/opentodo:0.1.0 and :0.1 for linux/amd64 and linux/arm64.

Added

Core platform

  • Go + SQLite server with the React PWA embedded, local-first storage in IndexedDB, field-level last-writer-wins op log, owner setup, sessions, API tokens, REST API that writes through the op log, JSON export, a single distroless container and a Coolify-ready compose file. Architecture, sync protocol
  • Live sync: a server-sent event stream (GET /api/v1/sync/events) wakes other devices as soon as ops are recorded; 30 s polling remains the fallback. Live updates, proxy notes
  • Vim keybindings, opt-in per device and loaded only when enabled.

Capture

  • Natural-language quick add in English, German, French, Italian, Spanish and Portuguese: dates, times, #project, @label, p1–p4, +30m estimates, with preview chips; parsed on the device. Quick add
  • Voice capture into quick add (Shift+V), opt-in per device, using the browser's speech recognition. Voice
  • Share target, bookmarklet and a Manifest V3 browser extension for Chromium and Firefox (make extension), opening a capture screen at /share. Capture
  • Email to task: a personal secret address per account, polled from one operator-configured IMAP mailbox (OPENTODO_EMAIL_*). Email
  • ot command-line client (cmd/ot), cross-compiled for Linux, macOS and Windows and attached to releases. CLI

Organisation and views

  • Nested projects and subtask trees to any depth, with deterministic, write-free cycle breaking for concurrent moves.
  • Sections and a Kanban board per project; new section entity and task field section_id. Sections
  • Manual ordering by drag and drop and Alt+↑/↓, one position op per move. Manual order
  • Labels as a synced entity referenced by id from task.labels. Task labels
  • Filter query language evaluated on the device, and saved views and dashboards (view entity, REST /api/v1/views, validated by a Go port of the parser). Filters
  • Rich-text notes with collaborative editing: new task field notes_doc (a Yjs document envelope, up to 256 KB) next to description, which stays the note's Markdown projection for the API, export, CalDAV, MCP and webhooks. Mergeable documents
  • Trash with restore, revision history from the op log, permanent purge (purges table, purged in sync responses), automatic purge after OPENTODO_TRASH_RETENTION_DAYS (default 30) and automatic archiving of finished projects. Trash and history, Purge

Time

  • Duration estimates (task field estimate_minutes) and Day/Week time-blocking calendars with drag, resize and full keyboard control.
  • Recurring tasks: task fields recurrence and series_id, one grammar implemented in Go and TypeScript against 180 shared vectors, convergent completion of the same occurrence on two offline devices. Recurrence
  • Reminders (reminder entity, relative or absolute) with in-app notifications, snooze and dismiss, and web push implemented with the standard library (VAPID, RFC 8291); key pair in <data>/push_vapid.pem, OPENTODO_PUSH=off to disable. Reminders
  • Time-zone-fixed due times: optional tz key in due (IANA zone, only with time), resolved by internal/zoned and the web app against shared vectors. Zoned due values

Collaboration

  • Project sharing with viewer, editor, admin and owner roles: the op log is partitioned into sharing scopes, ops are authorised against the author's membership at receipt and refused ones are reported per op. Sharing scopes, API
  • Task assignment (assignee_id), the Assigned to me view and in-app notifications (GET /api/v1/notifications). Assignment
  • Threaded Markdown comments (comment entity) with @mentions, and an activity log derived from the op log, per task and per project. Comments
  • Activity feed across shared projects with unread counts (project_prefs entity, personal scope only; GET /api/v1/activity). Activity feed
  • Invitations: single-use, expiring links in Settings → Members. Invitations
  • User administration: admin role, deactivation, deletion, password reset links, owner transfer, own password change and opentodo reset-owner-password on the host. User administration

Integrations and data

  • Data import of the app's own export, CSV and JSON exports of other task managers, with preview, duplicate detection and undo (OPENTODO_IMPORT_MAX_MB, default 20). Import
  • Scheduled backups to a folder, S3-compatible storage or WebDAV with retention, optional OTBK1 encryption, OPENTODO_BACKUP_* presets and opentodo restore; sync responses carry a log generation so devices re-send newer edits after a restore. Backups
  • Signed outbound webhooks with a durable queue, retries, delivery log and SSRF protection (OPENTODO_WEBHOOKS_ALLOW_PRIVATE preset). Webhooks
  • CalDAV two-way sync under /dav/ with per-device app passwords (otap_…), off until the owner enables it (OPENTODO_CALDAV preset); new task field ical_extra keeps unmapped iCalendar properties. CalDAV
  • Read-only MCP endpoint at /mcp for AI assistants (five tools, opentodo:// resources), off until the owner enables it (OPENTODO_MCP preset). MCP

Security and access

  • Passkeys (WebAuthn) when OPENTODO_BASE_URL is https; verification in internal/webauthn.
  • Two-factor authentication (TOTP) with recovery codes, remembered browsers, an owner policy (none, owner, all), step-up re-authentication for sensitive routes and opentodo mfa-reset on the host.
  • Single sign-on with one OpenID Connect provider (PKCE, JWKS verification with the standard library), optional OPENTODO_OIDC_* overrides, account linking and an SSO-only mode with owner break-glass. SSO
  • Audit log...
Read more