horae — GTD Terminal Task Manager
A GTD terminal task manager in Rust: SQLite data layer + CLI + ratatui TUI in one binary.
Core idea: time-datafication — every state change is stamped with UTC-ms and appended to an append-only task_events timeline, giving every task a full audit trail.
Features
- Full GTD workflow with weekly review, today/tomorrow views, and David Allen GTD philosophy guide
- Recurring tasks auto-reschedule on Done (complete RRULE daily/weekly/monthly/yearly + shorthands like
*2w[1,3],*m[1,-1],*y[jan,jul]) - Tags & priority: context tags + dedicated
high/medium/lowpriority column (!high/!medium/!lowshorthands) - Instant inline auto-completion with dual modes: Syntax Guide Cheat-Sheet vs Speed Compact mode (F7 toggle)
- Checklists with per-item tick/delete/reorder/rename and a progress badge in the list
- Quotes (opt-in): capture good sentences, ideas & knowledge into a dedicated view
- Pomodoro focus mode with progress ring, streaks and a waybar module
- Stats dashboard and TUI splash screen featuring Catppuccin ASCII art of the Goddess of Time and philosophical GTD slogans
- Bilingual UI (F6) and Catppuccin themes (F5)
Installation
Option 1: npm (Recommended, no Rust toolchain required)
For any machine with Node.js installed; automatically downloads prebuilt binaries for Linux, macOS, and Windows:
# Try instantly without installation
# Or install globally (provides the `horae` command)
Option 2: Cargo (Rust official crates.io)
Requires Rust 1.89+; SQLite is bundled, no extra system dependencies:
# Install latest release from crates.io
# Or install the git main branch
Option 3: Build from source
&&
Data lives in ~/.config/horae/ (horae.db + config.json (profile config) + pomo.json).
Recommended environment
For the best experience:
- Install a Nerd Font: UI icons default to Nerd Font glyphs; when none is found they fall back to plain ASCII (no tofu characters). Pick any font from Nerd Fonts and set it as your terminal font.
- Windows users:
- Build from source with Rust 1.89+ (
cargo build --release); the data directory is%APPDATA%\horae\. - Desktop notifications rely on Linux's
notify-send, so system pop-ups may not appear on Windows / macOS — but pomodoro timing and in-TUI reminders still work. - The
HORAE_CONFIG_DIRenvironment variable overrides the data directory.
- Build from source with Rust 1.89+ (
Quick start
Task refs accept a full id, a unique id-prefix, or an exact title.
CLI
| Command | Description |
| horae / horae --normal (-n) | Launch in normal mode (enter main view directly) |
| horae flash / horae -f (--flash) | Launch in flash capture mode: quick capture, Enter to save & exit (alias f) |
| horae capture [title] [--clip] [--notes N] [--tag T]... [--due TIME] [--status S] [--high\|--medium\|--low] [--json] | Capture (alias c, supports --clip ingest) |
| horae list [--status S] [--tag T]... [--date MMDD] [--due-before TIME] [--json] | List tasks (alias l); date search uses four digits, e.g. 0829 |
| horae show <id> [--json] | Show with timeline (alias s) |
| horae modify <id> [text] [--title T] [--due TIME] [--notes N] [--edit-notes] [--tag T]... [--untag T]... [--high\|--medium\|--low\|--clear-priority] [--status S] [--json] | Modify task (aliases m, mod, edit; quick-add syntax supported) |
| horae next\|wait\|someday\|done\|restore\|purge <id> | Move / restore / hard-delete (alias d for done) |
| horae schedule <id> [--start TIME] [--end TIME] [--rrule R] | Schedule (+recurrence) |
| horae archive <id> / horae restore <id> / horae purge <id> | Soft delete / restore / hard delete (aliases rm, delete for archive) |
| horae tag <id> <name> / horae untag <id> <name> | Manage tags |
| horae focus [--start] / horae do [--start] | Output the single top task now (can also start a pomodoro) |
| horae log [message] | Journal entry (no task) |
| horae stats | MOTD dashboard |
| horae export [--file PATH] | Full backup (tasks/events/tags/settings/pomodoro) |
| horae import <FILE> [--replace] | Merge / restore (--replace wipes then restores exactly) |
| horae review | Weekly review |
| horae tags | List tags |
| horae pomo start <id> \| stop \| daemon \| waybar | Pomodoro (alias p) |
| horae alarm waybar [slot] \| next [slot] [--limit N] [--all] | Upcoming-task reminders |
| horae watch [--dir PATH] [--interval S] [--once] | Phone bridge (Syncthing) + ntfy/Feishu push + WS capture |
| horae feishu <test\|due\|summary\|listen\|doctor\|sync> | Feishu/Lark alerts, WebSocket captures & native task sync |
| horae profile <list\|new\|rename\|rm\|set-default> [--db PATH] | Profile (data-set) management |
| horae completions <shell> | Generate shell completions |
Help language: CLI --help is English by default; pass --lang zh (or set the
HORAE_LANG=zh environment variable) to switch to Chinese, e.g. horae --lang zh --help
or HORAE_LANG=zh horae capture --help.
Short aliases: c=capture, l=list, s=show, m=modify/edit, d=done, rm=archive, p=pomo, do=focus.
TUI Keybindings
| Key | Action |
|---|---|
h / l |
switch pane |
j / k |
move up/down |
0-9 |
switch view (8=archive, 9=tags, 0=quotes) |
⇧J / ⇧K |
today / tomorrow |
/ |
global search |
f |
tag filter |
a |
quick capture (any view) |
" |
add to / remove from quotes (work-status tasks become reference) |
Space |
toggle-select current row |
Ctrl+a / Ctrl+u |
select all / invert |
Enter / e |
full edit (title @tags ~time *rrule !priority; instant completion card) |
x / w / s |
done / waiting / someday |
C |
add checklist item |
= |
tick next item (no auto-reset) |
Tab |
manage checklist items (j/k move, Space tick, d delete, J/K reorder, e rename; Tab/Esc exit) |
T |
bulk tag (visual multi-select) |
n |
edit notes ($EDITOR) |
P / S / [ |
pomodoro start/continue/stop/config (format work;short;long[;long-interval], e.g. 25;5;15;4) |
A / D |
archive (y/n) |
u |
restore from archive (batch-capable) |
c |
add tag (Tags view) |
r / R |
weekly review (start/next) |
F5 / F6 |
theme / language |
F7 |
module visibility & completion style (11 toggles, persisted) |
M |
settings (profiles: new/rename/delete/set-default) |
F1 or ? |
shortcut help |
q |
quit |
Today / Tomorrow views: Today = tasks inside today's window (including today's occurrence of recurring tasks) plus overdue tasks (a recurring task with no occurrence today shows its most recent missed occurrence, marked overdue). Tomorrow = only tasks inside tomorrow's window (including tomorrow's occurrence of recurring tasks); overdue and unfinished-today tasks are not carried over. Both views only take Next / Scheduled statuses — waiting, someday, reference and dated inbox items stay in their own status views.
Quotes
Quotes is an opt-in feature (off by default; F7 toggles it, persisted in settings). It's a notebook for quotes, inspirations and knowledge — not actionable tasks.
Icon fallback
Icons default to Nerd Font glyphs. On startup horae auto-detects support (via fc-list) and falls back to plain ASCII when no Nerd font is found — no tofu characters. Override with HORAE_ICONS=nerd|ascii, or toggle the corresponding entry of the F7 module-visibility popup (persisted).
How it works
- A quote is a task tagged
@quotewith statusreference, so it never surfaces in the inbox/action workflow. - Quotes live only in the Quotes view — the Reference view (and its badge) filters out
@quotetasks; turning the feature off restores them to Reference. - After enabling via
F7, the sidebar shows[Library] 0 quotes; press0to enter the Quotes view (newest first). - Inbox → quote: select an item and press
"to add@quoteand transition it to reference, leaving the inbox. - Quick capture: in the Quotes view press
aand type a sentence to store it directly (auto@quote). - Auto-route: capture with
@quoteanywhere (e.g.a idea @quote) → created as a quote and jumps to the Quotes view. - In the Quotes view
"removes the quote (drops the tag only). Enter/e edit,nnotes,Ttag,Aarchive — same as normal tasks. - CLI:
horae capture "…" --tag quote --status referencecollects a quote from the command line.
Journal
horae log reuses the append-only task_events timeline to record pure timestamped notes without creating a to-do — written to a dedicated system task __journal__, fully isolated from your tasks. horae log "drink water" adds one; horae log (without args) lists the last 50, newest first.
Time & recurrence syntax
now +15m +30m +1h +2h +4h +1d +3d +1w relative offsets
+3d 15:30 · +1w 09:00 offset + clock
today / tomorrow [HH:MM] day words (~td / ~tm to complete)
mon / tue / next fri [HH:MM] weekdays (supports next prefix)
09:00 · 18:00 · HH:MM same-day time (past → tomorrow)
8/20 15:30 · 2026.8.20 slash & dot dates
2026-07-24 [HH:MM] absolute date & time
~time in a quick-add line sets the schedule start (scheduled_start_at, status becomes Scheduled; start only, no end); --due sets a soft deadline (due_at).
Recurrence RRULE (* shorthand in a quick-add line): FREQ=DAILY|WEEKLY|MONTHLY|YEARLY, INTERVAL=2, BYDAY=SA,SU, BYMONTHDAY=1,-1 (-1 = last day of month), BYMONTH=1,7 (months by number or name, e.g. jan,jul), COUNT=10 / UNTIL=YYYY-MM-DD. Shorthands: *d/*w/*m/*y (daily/weekly/monthly/yearly), *weekday/*weekend (workdays/weekends), *2w[1,3] (every two weeks on Mon & Wed; 1-7 = Mon-Sun, 0 = Sun), *m[1,-1] (the 1st and last day of each month), *m[1,15] (the 1st and 15th), *y[jan,jul] (yearly in Jan & Jul), *2y[6] (every two years in June), dynamic inference (*2 → *2d/*2w). Priority supports !high/!h/!1, !medium/!m/!2, !low/!l/!3 (case-insensitive). Autocomplete features slot ghost hints and instant syntax reference.
Backup
The backup is one self-contained JSON file with format/version fields, containing every task column, the task_events timeline, tags, settings and pomodoro state. Backup = copy this one file to git/cloud/cron for free redundancy. --replace is the true restore path; plain import merges.
Phone sync (horae watch)
Bridge the phone–computer gap with Syncthing: sync ~/.config/horae/sync to your phone and run horae watch on the computer. No server, no app.
Folder protocol (phone writes, computer consumes):
| File | Purpose |
|---|---|
capture.txt |
one quick-add line per capture: title @tag ~time *rrule !p |
actions.txt |
done <id|title> · set <id|title> status next · set <id|title> due <time> |
today.md |
active-task snapshot (Next / Scheduled / Waiting / overdue) |
reminders/ |
due/overdue task reminders (Syncthing pushes a file-change notice to the phone) |
*.done |
receipts of consumed lines |
Feishu / Lark Integration (horae feishu)
horae provides end-to-end integration with Feishu (Lark):
- Webhook Bot: Due/overdue task alert cards & daily 08:30 briefing summary cards.
- Custom App (No Public IP Needed):
- Capture Everywhere: Send natural language quick-add tasks (e.g.
write report @work tomorrow 18:00 !high) to your bot in private chat; horae captures it into SQLite within milliseconds with UTC-ms audit timeline. - Interactive Card Actions: The bot replies with an interactive card. Click
[✅ Mark Done]or[📅 Postpone 1 Day]directly on your phone to transition tasks. - Native Task Sync (Tasks v2 API): Bidirectional synchronization with Feishu's official Tasks system.
- Capture Everywhere: Send natural language quick-add tasks (e.g.
Configuration (~/.config/horae/config.json)
Useful Commands
# Run diagnostics to check credentials and gateway connectivity
# Send test card to verify webhook alerts
# Manually scan and push due tasks or today's briefing
# Start WebSocket long connection listener in foreground
# Manually sync with Feishu Tasks v2
Note: When running
horae watch, configuringapp_idand secret will automatically spawn the WebSocket listener and task synchronizer inside the daemon.
Development
See AGENTS.md for architecture and contributor rules.
License
GPL-3.0, see LICENSE. You are free to use, modify, and redistribute it, provided that any derivative work is released under the same GPL-3.0 license.