odak
Your odak todos: add in one line, see today's on the bar
palupdated 2026-09-29ProductivityIn pal's registryMenu bar: Today1 deep link
In pal's registry: the button shows it in pal, which asks before installing; the command does the same from a terminal. This page can't see what your pal has installed.






What it does
Your odak todos in the panel: open ones by section with today's and the overdue on top, a new todo in one typed line, search across open and done, and today's count on the bar.
- Todos by section, overdue and today's on top;
entercompletes, with Undo right after - Add in one line:
#tag,!for urgent,/sectionand a day in words (tomorrow,fri,in 3 days) - Snooze, move between sections, or edit everything in a form
- Search across open and completed todos, and reopen what you checked off
- Today's count on the bar, red when anything is overdue; add and complete from its popover
pal://odak/add?text=...adds a todo from a script or a keybind
Palettes 4
-
Todos
odakliverefreshes every 1 minEvery open todo: the overdue and today's first, then the file's sections in order, subtasks under their parent, what waits for a day at the end. Add a todo from the first row, typed in the bar.
- ↵Complete (Tab marks several)
- ⌘EEdit: text, section, tags, due day, urgent
- ⌘TSnooze to tomorrow
- ⌘SSnooze: tomorrow, in 3 days, next Monday, next week, a day typed
- ⌘MMove to a section
- ⌘UMark urgent, or not
- ⌘NAdd a subtask
- ⌘LOpen the link in the todo
- ⌘OOpen odak
- ⌘CCopy the text
- ⌘⇧CCopy the link (the todo's, else odak's)
- ⌘DDelete (asks; subtasks go with it)
-
Add Todo
addinputfallback row: Add “…” to odakA todo typed in one line: #tag, ! for urgent, /section, d:day or a day in words at the end (tomorrow, fri, next mon, in 3 days, 20 sep); the row reads it back as you type, Enter adds it. Before you type: the selected text and the clipboard as todos.
- ↵Add
- ⌘↵Add and type another
- ⌘⇧CCopy the line
-
Search Todos
searchinputEvery word typed against the text, tags and section of every todo, open and completed; a completed one reopens on Enter.
- ↵Complete an open todo; reopen a completed one
- ⌘EEdit
- ⌘CCopy the text
- ⌘DDelete (asks)
-
Completed
doneliverefreshes every 1 minWhat is checked off, by section, the ones completed from pal with when; Enter reopens.
- ↵Reopen (Tab marks several)
- ⌘CCopy the text
- ⌘OOpen odak
- ⌘DDelete (asks; Tab marks several)
Links 1
odak answers these pal:// routes from a web page, a script or a keybind; pal call is the same route from a terminal. A link from a page asks first unless you trust the extension. How links work.
-
Add a todo; the text takes the add line's grammar (#tag, !, /section, a day at the end)
addpal call odak/add text=<text>text*The todosectionThe section; the setting's default otherwisedueA day: tomorrow, fri, next mon, in 3 days, 2026-10-01tagsTags, repeatedurgentFlag it
Settings
Extension, [extensions.odak]
urlThe odak server: http://host:8761 on your network, or its public address.
api_keyThe server's ODAK_API_KEY.
default_sectionWhere a todo lands unless the line names one with /section.
Defaults shown. Change them in pal's settings window or in the config file.
The README
Everything odak does, key by key, from the extension's own README.md
odak
Your odak todos in the panel: every open one by section with the overdue and today's on top, a todo typed in one line with its tags, flag, section and a day in words, search across open and completed, what you checked off. One bar item counts what is due today or sits in today's sections, turns red while anything is overdue, and hides at zero; its popover completes on Enter and adds from a field.
| palette | id | kind | what Enter does |
|---|---|---|---|
| Todos | odak |
live, 60 s | completes the todo (Tab marks several) |
| Add Todo | odak-add |
input | adds the line as read |
| Search Todos | odak-search |
input | completes an open todo, reopens a completed one |
| Completed | odak-done |
live, 60 s | reopens |
Signing in
Two settings under Settings › Extensions › odak: the Address of the
server (http://host:8761 on your network, or its public address; the
same origin serves the web UI) and the API key (the server's
ODAK_API_KEY, kept in the OS keychain). Without either, every palette is
one hint row naming which and opening it in Settings; a refused key says so;
a server that does not answer names the address and the retry key, and
the rows already fetched stay through an outage.
The endpoints it uses
Everything is the server's own REST API, Authorization: Bearer <key>:
| call | for |
|---|---|
GET /todos |
every todo, open and done, in the file's order (one call, cached 60 s, shared by the palettes and the bar item) |
GET /sections |
the file's ## headings in order, cached 5 min |
GET /todos/:id |
a todo the cache no longer has (a pick after a restart) |
POST /todos |
Add Todo, New todo, the popover's field, pal://odak/add |
PATCH /todos/:id/done |
Complete, Reopen (the id stays: odak hashes the line after its checkbox) |
PATCH /todos/:id |
Edit, Snooze, Mark urgent |
POST /todos/:id/move |
Move to section, Edit with a new section |
DELETE /todos/:id |
Delete (odak takes the subtasks with it) |
Two things about odak's model the extension works around. An id is a
hash of the line, so an edit, a snooze, a flag or a move gives the todo
a new id, and the server's answer carries the old one. The extension
computes the new id the way odak does (idOf in data.ts), patches its
cache with it, uses it for the move that follows an edit, and fetches the
list again behind every write so the server's view wins. A day cannot be
cleared: PATCH keeps an empty deadline, so Edit refuses an emptied
due field and says to move the day instead. urgent is written on every
PATCH (odak overwrites it), so the current flag rides along.
What each palette does
Todos lists every open todo: first two commands (New todo, whose text
is typed in the search bar as an argument, ⌘Enter opening Add Todo; Open
odak), then Overdue and Due today, then the file's sections in
their order (Focus, Today, Next, ... whatever the headings are), a subtask
right after its parent with the parent under it, and Not yet at the
end for todos waiting on a [w:date] still ahead. A row: the text, its
tags as coloured chips, the day as a chip (overdue 3 d red, today
amber, tomorrow blue, Fri within the week, Fri 26 Sep beyond), a red
mark for an urgent one, 2 subtasks on a parent. The pane: the text, the
subtasks as a task list, section, tags, due day, the link in the text, the
id. Typing a tag, a section or overdue narrows the list (they are the
rows' keywords), at the root too.
On every row: Complete (Enter; a toast, and an Undo row at the top
for a minute), Edit… (⌘E: text, section, tags, due day, urgent), Snooze
to tomorrow (⌘T), Snooze… (⌘S: tomorrow, in 3 days, next Monday, next
week, in a month, or a day typed), Move to section… (⌘M), Mark urgent
(⌘U), Add subtask… (⌘N), Open link (⌘L, when the text has one), Open
odak (⌘O), Copy text (⌘C), Copy link (⌘⇧C: the todo's, else
odak's), Delete (⌘D, asks; the subtasks go with it). Complete, Reopen,
Snooze to tomorrow, Mark urgent and Not urgent (both on every row, so a
mix of flagged and not can go either way), Open link, the copies (a line
each), Delete, and the Snooze… and Move to section… forms (one form for
them all, "Snooze 3 todos") take several marked rows (Tab marks); Edit
and Add subtask stay one todo's.
The root's Now section shows what is overdue or due today, from the cache alone.
Add Todo reads the line as you type and shows what will be created:
#tag (any number), a bare ! for urgent, /section (a prefix of one of
the file's sections; an unknown one stays in the text), d:day or
w:day (odak's due and wait-until days, without spaces: d:fri,
d:2026-10-01, d:3d), and a day in words at the end (tomorrow, fri,
next mon, in 3 days, in 2 weeks, 20 sep, sep 20 2027,
2026-10-01, by fri). A time after the day (next mon 9am) stays in
the text: odak keeps a day only. Enter adds and hides with the HUD line;
⌘Enter adds and keeps the line for a variation; ⌘⇧C copies the line.
Before anything is typed: what to type, what was just added (with Undo,
which deletes it), the front app's selection and the clipboard's text as
todos (Enter adds as typed, ⌘Enter edits first). Any root query with no
hit offers "Add “…” to odak". Pushed from Add subtask, the todo lands
under the parent in its section.
Search Todos matches every typed word against the text, tags and
section of every todo, open ones by section first, completed ones after
with a green mark. Completed lists what is checked off by section,
with when, for the ones completed from pal; Enter reopens, ⌘D deletes.
The bar item
odak/today: the count of open todos due today or in the sections named
by its today_sections setting (Focus and Today by default), plus the overdue ones,
every 300 s and on show, wake and network. Its facts are odak/overdue,
odak/today and odak/open; the manifest's rules hide it at zero and
colour it red while anything is overdue ([bar.items."odak/today"] show = "always" keeps the glyph at zero, muted; the rules are yours to override
under rules.quiet and rules.overdue). The popover: the overdue first,
then what is due today, then today's sections' todos, each with its flag,
section and tags under the text and the day on the right, a cursor the
arrows (j, k) move and a click sets; Enter/x completes, u flips
the flag, t snoozes to tomorrow, n turns the search row into a field
whose Enter adds a todo through the same grammar, o opens odak, p the
Todos palette, r fetches again.
Links
pal://odak/add?text=call the bank tomorrow #personal (and pal call odak/add text=...) adds a todo from a script or a keybind; the text takes
the add grammar, and section, due (a day in words), tags (repeated)
and urgent come on top. The HUD says where it landed.
Settings, [extensions.odak]
| key | type | default | what |
|---|---|---|---|
url |
text | (none) | The server's origin. |
api_key |
secret | (none) | ODAK_API_KEY. |
default_section |
text | Inbox |
Where a todo lands unless the line names a section; must be one of the file's (else Inbox, else the first). |
today item settings, [bar.items."odak/today".settings]:
| key | type | default | what |
|---|---|---|---|
today_sections |
list | ["Focus", "Today"] |
What the item counts as today's, on top of what is due today. |
For the tests, PAL_ODAK_URL and PAL_ODAK_KEY replace the two settings.
Not there
Reordering within a section (POST /todos/reorder; the file's order is
edited in odak), the raw file (GET /raw), clearing a day (the API cannot),
the WebSocket feed (the cache refetches on show and after every write
instead), several servers as instances (odak is one file per server).



