ReKnock ร— Eisenhower

๐Ÿ”ฅ Do now
nags every 90 min, max 5
๐Ÿ—“ Schedule
one nag/day at a set time
โšก Quick
batched 12:30 & 17:00
๐ŸŒ™ Someday
silent, archives in 21 days

Mockups

1 ยท Matrix home
1 ยท Matrix home
2ร—2 tiles with counts, top tasks, Q1 capacity, triage strip. Drag tasks between tiles.
2 ยท Triage card
2 ยท Triage card
One task at a time, suggestion pre-highlighted, four thumb-zone buttons.
3 ยท Quadrant + Q1 full
3 ยท Quadrant + Q1 full
Rule line explains the nag behaviour; swap dialog stops Q1 inflation; done animation on the last row.
4 ยท Notifications
4 ยท Notifications
Q1 frequent, Q2 daily, Q3 batched, Q4 silent. Dismiss changes nothing.
5 ยท Widgets
5 ยท Widgets
Matrix, Q1 list, Q2 focus.
6 ยท Weekly reset
6 ยท Weekly reset
Five-minute guided ritual.

Claude Code prompt

# Task: add an Eisenhower Matrix to ReKnock (phased)

You are working in the ReKnock codebase on this EC2 box: a Node.js + SQLite backend (reknock.morristech.ca), an MCP server on the same machine, and a native Android (Kotlin) app that schedules exact alarms and fires persistent notifications. I (Rob) want the Eisenhower Matrix as a daily tool I genuinely enjoy: beautiful, low-friction, and โ€” critically โ€” **the quadrant must change how a task nags**.

## Ground rules (read first)
1. **Inspect before changing.** Start by reading the existing code: DB schema/migrations, task model, nag scheduling, contexts, dependencies (blocked_by/blocks), start_date logic, the "context-only tasks become daily 09:00 nags after 3 days unoffered" job, the daily email digest, the MCP tool definitions, and the Android alarm/notification/widget code. Write a short summary of what you found (file names, how nags are computed, naming conventions) and **adapt this spec to the real code** โ€” names below (tables, tools) are illustrative. Follow existing conventions and style.
2. **Preserve the no-dismiss philosophy.** Dismissing/swiping away a notification changes nothing; a task keeps knocking on its schedule. Only "mark done" stops a task โ€” with ONE deliberate exception: Q4 "Someday" tasks don't nag and auto-archive (recoverably) after 21 untouched days, announced in the digest. Never add a "snooze/dismiss" that silently ends a task.
3. **Lean.** No browse-and-ignore graveyard. Don't add settings screens full of knobs; use constants/a small settings table.
4. **Backward compatible & safe.** Existing API/MCP clients keep working. Back up the SQLite file before migrating (copy to a timestamped file). Migration must be idempotent. Existing tasks become *unclassified* and behave **exactly as today**.
5. **Never put secrets in files or commits.** Don't push to git remotes; commit locally in small commits if the repo uses git.
6. **Stop between phases** (see checkpoints). After each phase: run tests/add tests, give me a short report of what changed and exact steps to test manually, then **STOP and wait for my go-ahead.** Do not start the next phase on your own.

## Concept
|  | Urgent | Not urgent |
|---|---|---|
| **Important** | Q1 Do now | Q2 Schedule |
| **Not important** | Q3 Quick / batch | Q4 Someday |

Quadrant is **derived**, not stored:
```
effective_urgent = (urgent==1 and not decayed) OR due_date within 2 days OR overdue
important IS NULL            -> unclassified   (behaves as today)
important && effective_urgent   -> q1
important && !effective_urgent  -> q2
!important && effective_urgent  -> q3
!important && !effective_urgent -> q4
```
Manual `urgent` without a `due_date` decays after 3 days (set urgent=0, log event, mention "cooled off" in digest; one-tap "still urgent" re-affirms).

Defaults (constants/settings): q1_cap=5, q1_interval_min=90, q1_window 08:00โ€“21:00, q2_default_time 09:00, q3_batch_times 12:30 and 17:00, q4_archive_days=21, urgent_decay_days=3, weekly review Sunday 18:00.

---
## PHASE 1 โ€” Backend + DB
1. Additive migration on `tasks`: `important INTEGER NULL`, `urgent INTEGER NULL`, `urgent_set_at TEXT`, `due_date TEXT` (skip if already present), `quadrant_changed_at TEXT`, `last_nagged_at TEXT`, `archived_at TEXT`; allow status `archived`. Add `matrix_events` (id, task_id, at, kind, from_q, to_q, source) and a small settings store for the defaults. Add an index on (status, important, urgent). Do backup + idempotency checks.
2. Implement one pure function `getQuadrant(task, now)` plus `effectiveUrgent`. Unit-test it thoroughly (decay, due-date boundary, null importance, timezone โ€” use the app's existing timezone handling).
3. API (additive): `POST/PATCH tasks` accept `important`, `urgent`, `due_date`, and shorthand `quadrant` (`q1..q4`, `do|schedule|quick|someday`, `unclassified`; q1โ†’1,1 q2โ†’1,0 q3โ†’0,1 q4โ†’0,0). Q1 cap: moving a task into Q1 when 5 already exist returns 409 `{error:"q1_full", q1:[...]}` unless `force=true` or `swap_out_id` (that task is demoted to q2). Due-date-derived urgency may exceed the cap (truth beats cap) and is flagged `over_capacity`.
   - `GET tasks?quadrant=โ€ฆ&context=โ€ฆ`; `GET /matrix` (per-quadrant count + top 3, q1_cap, done_today, unclassified count); `GET /triage/next?n=` (unclassified tasks with `suggested_quadrant`, `confidence`, `reason`); `POST tasks/:id/reaffirm-urgent`; `POST tasks/:id/restore`; `GET /review/weekly` and `POST /review/weekly/complete`.
   - Every task payload adds `quadrant`, `effective_urgent`, `next_nag_at`, `blocked`, `archive_in_days`.
4. Suggestion heuristic (deterministic, explainable, no LLM): urgent words (today, tonight, tomorrow, asap, deadline, overdue, due, by EOD, expires) or due โ‰ค48h; important words (tax, insurance, doctor, health, bill, pay, renew, contract, client, invoice, license, kids, family) / contexts ODL, Premco / blocks other tasks; low-importance words (maybe, someday, look into, idea, organize); quick words (call, email, reply, text, book, order, pick up) with Phone call/Errands context. Context-only auto-nag tasks โ†’ suggest Q2 or Q4. Return a reason string. Never auto-apply.
5. **Nag plan per quadrant** โ€” extend whatever computes a task's nag times / `next_nag_at` so the Android app can schedule: Q1 = its nag_times + every 90 min inside the window, immediate on entry; Q2 = one nag at `nag_times[0]` (else 09:00); Q3 = no per-task nags, instead two grouped batch nags at 12:30/17:00; Q4 = none; unclassified = unchanged. Existing suppression rules (start_date in future, blocked by dependencies) apply first. Provide a "batch" entry in the plan format for Q3.
6. Jobs: hourly urgency decay + Q4 auto-archive (archived_at set, recoverable, logged); weekly-review trigger.
7. Daily digest by quadrant (keep existing numbers): done yesterday split by quadrant; knocking-now split `๐Ÿ”ฅ Do now N ยท ๐Ÿ—“ Schedule N ยท โšก Quick N ยท ๐ŸŒ™ Someday N ยท โ” unsorted N`; Q1 list; Q3 batch estimate; "archiving soon"; "cooled off"; "N left to sort". Subject like "19 done ยท 3 to do now". Warm tone, no shaming.
8. Tests: migration on a copy of the real DB, quadrant derivation, cap/409/swap, nag plans, decay, archive, digest rendering.

**CHECKPOINT 1 โ€” STOP.** Report: migration result on a DB copy (counts per quadrant = all unclassified), sample API calls with curl, digest preview, anything you adapted. Wait for my OK.

---
## PHASE 2 โ€” MCP server
Update existing tools and add new ones (match existing style/schemas):
- `add_task`, `update_task`: add optional `quadrant`, `urgent`, `important`, `due_date`. If no classification is given: create unclassified and return `suggested_quadrant` + reason so Claude can ask one short question.
- `list_tasks`: add `quadrant` filter and `sort=quadrant`; output shows quadrant label per task.
- New: `set_quadrant(id, quadrant)`, `matrix_summary`, `triage_next(n=3)`, `weekly_review_summary`.
- Handle `q1_full` gracefully: return a clear message listing current Q1 tasks so Claude can ask which to demote, then accept `swap_out_id`.
- Write tool descriptions that teach the voice mapping: "urgent and important"โ†’q1; "important but not urgent"โ†’q2; "urgent but not important"/"quick one"โ†’q3; "not important"/"someday"โ†’q4; unsure โ†’ leave unclassified. Must remain voice-friendly and short in responses.
- Test every tool against the Phase 1 API (script or MCP inspector).

**CHECKPOINT 2 โ€” STOP.** Report with example tool calls/results and a voice test script I can say to Claude. Wait for my OK.

---
## PHASE 3 โ€” Android app (Kotlin)
Follow the app's existing architecture (Compose vs Views โ€” check and match). Server is source of truth; cache and queue offline edits.
1. **Theme/colours** (dark-first, light supported): Q1 coral #FF5A5F, Q2 blue #4C8DFF, Q3 amber #FFB020, Q4 slate #7C8AA0; bg #0F1420, surface #181F2E, text #EAF0FA; 20dp rounded tiles, tinted gradient (~14%) with 2dp edge; each quadrant also has an icon (๐Ÿ”ฅ/flame, calendar, bolt, moon) and label (don't rely on colour alone). Rounded font, big hero counts.
2. **Matrix home**: 2ร—2 tiles (columns Urgent | Not urgent, rows Important | Not important), each with icon, name, big count, top 2โ€“3 titles, "+N more"; Q1 tile shows `n/5`. Header "Done today โœ“ N". Bottom strip "N to sort โ†’ Triage" (only when unclassified>0) and "I'm inโ€ฆ" context chips. FAB ๏ผ‹ (long-press = voice/mic if existing). Tap tile โ†’ quadrant screen (list, big done targets, context chips, due badge, dimmed "blocked by โ€ฆ", rule line like "Nags every 90 min until done"; Q4 rows show "archives in N days").
3. **Drag & drop** between tiles via long-press (haptic lift, tiles highlight as drop zones, drop = reclassify with snackbar "Moved to Schedule ยท next nag 09:00 ยท Undo"). Q1-full โ†’ dialog to swap one out.
4. **Add/edit sheet**: Urgent and Important toggle chips with live preview ("โ†’ Do now, nags every 90 min"), optional due date, suggestion ghost state to accept in one tap.
5. **Triage**: card-per-task, task text + contexts + age + suggestion pill with reason; 2ร—2 big coloured buttons in the thumb zone (suggested one outlined); Done-already / Skip / Delete; swipe aliases; progress "7/47", 10-card sessions with "Continue / Later"; card flies to its quadrant with haptic tick. Summary screen "accept all high-confidence suggestions" with review. One gentle daily "5 to sort" notification until none remain.
6. **Notifications**: per-quadrant channels (Q1 high importance/ongoing with actions โœ“Done and "Not urgent" (cools to Q2); Q2 default/ongoing; Q3 one grouped InboxStyle batch at 12:30/17:00; Q4 none; unclassified existing channel). Use the server's nag plan to schedule exact alarms. Reclassification must cancel old alarms and register new ones immediately; same notification id replaced. **Dismiss still does nothing.** Verify boot, timezone, Doze/exact-alarm permission paths still work.
7. **Done feedback**: checkbox fills with quadrant colour, check stroke draws, ring pulse, row collapses, tile count rolls down, 8โ€“12 particle burst, haptic CONFIRM; "Q1 clear" soft confetti โ‰ค1.5s. Respect reduce-motion.
8. **Widgets**: Matrix 2ร—2 (counts, tap โ†’ quadrant), Q1 "Do now" list (โ‰ค4 tasks, โœ“ opens confirm), Q2 "Today's focus"; keep planned "knocking now"/"all" widgets coherent. Update via broadcast on change. No dismiss action.
9. **Weekly review**: stepper โ€” celebrate โ†’ Q1 audit (keep / cool to Q2 / done) โ†’ pick up to 3 Q2 focus tasks โ†’ Q3 sweep โ†’ Q4 purge (keep/delete/promote) โ†’ leftover triage. โ‰ค5 min, skip allowed (re-prompts next day).
10. Contexts: "I'm inโ€ฆ" lists sort Q1โ†’Q4, quadrant colour dots, Q4 hidden by default.
11. Build a debug APK / give exact build+install commands; add tests where the project has them.

**CHECKPOINT 3 โ€” STOP.** Report with a manual test checklist (classify, drag, triage 5 tasks, Q1 notification repeat + dismiss does nothing, Q3 batch, widget, done animation, review).

---
## Definition of done
Existing 47 tasks untouched until triaged; classifying a task visibly changes its nag pattern; Q1 can't silently balloon; Q4 can't silently rot; dismissing never stops a task; the app is something I want to open daily.

Begin with the inspection summary, then Phase 1. Don't ask me questions you can resolve by reading the code; make a sensible choice and note it in your report.

Documents

DESIGN.md
# DESIGN โ€” Eisenhower Matrix for ReKnock

Mockups: open `index.html` (phone-friendly) or `mockups/*.svg`.

## 0. Principles
1. **Capture is free; classification is optional and fast.**
2. **Quadrant changes nag behaviour** โ€” otherwise it's decoration.
3. **Nothing leaves by dismissal.** Only done, or an explicit/reviewed Q4 archive.
4. **Show less.** Home shows counts + top few, never 47 rows.
5. **Unclassified = today's behaviour**, so the migration changes nothing until Rob triages.

## 1. Data model

SQLite, additive migration (no destructive changes).

```sql
ALTER TABLE tasks ADD COLUMN important INTEGER;          -- NULL = unclassified, 0/1
ALTER TABLE tasks ADD COLUMN urgent INTEGER;             -- manual urgency flag, NULL/0/1
ALTER TABLE tasks ADD COLUMN urgent_set_at TEXT;         -- ISO ts, for decay
ALTER TABLE tasks ADD COLUMN due_date TEXT;              -- 'YYYY-MM-DD' optional, drives effective urgency
ALTER TABLE tasks ADD COLUMN quadrant_changed_at TEXT;   -- for Q1 age / Q4 archive clock
ALTER TABLE tasks ADD COLUMN last_nagged_at TEXT;        -- for Q1 interval + audit
ALTER TABLE tasks ADD COLUMN archived_at TEXT;           -- Q4 auto-archive; status stays recoverable
-- status gains 'archived' (active | done | archived)
CREATE TABLE IF NOT EXISTS settings_matrix (key TEXT PRIMARY KEY, value TEXT);
CREATE TABLE IF NOT EXISTS matrix_events (               -- audit: classification + review history
  id INTEGER PRIMARY KEY, task_id INTEGER, at TEXT, kind TEXT, from_q TEXT, to_q TEXT, source TEXT);
CREATE INDEX idx_tasks_quadrant ON tasks(status, important, urgent);
```

**Quadrant is derived, not stored** (single source of truth):

```
effective_urgent = urgent==1 (and not decayed) OR (due_date - today <= 2 days) OR overdue
if important IS NULL            -> 'unclassified'  (urgent alone doesn't classify)
important && effective_urgent   -> 'q1'  (Do now)
important && !effective_urgent  -> 'q2'  (Schedule)
!important && effective_urgent  -> 'q3'  (Quick / batch)
!important && !effective_urgent -> 'q4'  (Someday)
```
Urgency decay: manual `urgent=1` with no `due_date` expires 3 days after `urgent_set_at` (job sets urgent=0, logs event, appears in digest as "cooled off"). Re-affirm resets `urgent_set_at`.

Default settings (all configurable, stored in `settings_matrix`): `q1_cap=5`, `q1_interval_min=90`, `q1_window=08:00-21:00`, `q2_default_time=09:00`, `q3_batch_times=12:30,17:00`, `q4_archive_days=21`, `urgent_decay_days=3`, `review_day=sun`, `review_time=18:00`.

### Migration for the existing ~47 tasks
- All existing tasks: `important=NULL, urgent=NULL` โ†’ **unclassified, behaviour identical to today.** Zero surprise.
- Compute a **suggestion** (not stored, or stored in a `suggested_q` cache) per task via the heuristics in RESEARCH ยง7, used by the triage flow.
- Tasks with start_date in future, done tasks, and context-only tasks: left alone; context-only auto-nags get suggestion Q2/Q4.
- Backup the SQLite file before migrating; migration idempotent (check `PRAGMA table_info`).

## 2. API changes (REST, existing server)

Keep existing endpoints working. Additive:

- `POST /tasks` and `PATCH /tasks/:id` accept: `important` (bool|null), `urgent` (bool|null), `quadrant` (`q1..q4`|`do|schedule|quick|someday`|`unclassified`) as shorthand, `due_date`.
  - `quadrant` sets both flags: q1 โ†’ important=1, urgent=1; q2 โ†’ 1,0; q3 โ†’ 0,1; q4 โ†’ 0,0. (Setting q2/q4 with a due_date within 2 days still evaluates as q1/q3 โ€” response includes `note`.)
  - Moving into q1 when full โ†’ `409 {error:"q1_full", q1:[...tasks]}` unless `force=true` or `swap_out_id` given (that task is demoted to q2).
- `GET /tasks?quadrant=q1|q2|q3|q4|unclassified&context=...&include_blocked=...`
- `GET /matrix` โ†’ `{q1:{count, top:[...]}, q2:..., q3:..., q4:..., unclassified:{count}, q1_cap, done_today}`
- `GET /triage/next?n=5` โ†’ unclassified tasks with `suggested_quadrant, confidence, reason`.
- `POST /tasks/:id/reaffirm-urgent`
- `POST /tasks/:id/restore` (archived โ†’ active, q4)
- `GET /review/weekly` โ†’ structured payload for the review flow; `POST /review/weekly/complete`.
- Every task payload gains: `quadrant`, `effective_urgent`, `important`, `urgent`, `due_date`, `next_nag_at`, `blocked`, `archive_in_days` (q4).

## 3. MCP tool changes

Existing: add_task, list_tasks, update_task, mark_done (names may differ โ€” adapt). Changes:

| Tool | Change |
|---|---|
| `add_task` | + `quadrant?` , `urgent?`, `important?`, `due_date?`. If none given: unclassified, and the response includes `suggested_quadrant` so Claude can ask one short question. |
| `update_task` | + same params |
| `list_tasks` | + `quadrant?` filter, `sort=quadrant`; each task shows quadrant label |
| `set_quadrant(id, quadrant)` | convenience for voice ("make that urgent and important") |
| `matrix_summary` | counts per quadrant + Q1 list + unclassified count + Q1 cap status |
| `triage_next(n=3)` | returns tasks with suggestions so Claude can run a voice triage: *"Renew passport โ€” I'd say important, not urgent. OK?"* |
| `weekly_review_summary` | Q1 audit list, Q2 candidates for focus, Q4 expiring |

Tool descriptions must teach Claude the voice mapping: "urgent and important" โ†’ q1; "important but not urgent" โ†’ q2; "urgent but not important / quick" โ†’ q3; "not important / someday" โ†’ q4; "I don't know" โ†’ leave unclassified. On `q1_full` Claude asks which to demote.

## 4. Notification behaviour (Android scheduling)

Server is source of truth; app schedules exact alarms from `next_nag_at` plans (as today). Per quadrant:

| Q | Schedule | Notification style |
|---|---|---|
| Q1 | task `nag_times` **plus** interval nags every `q1_interval_min` inside window; immediate on entry | Coral channel, high importance, persistent (ongoing), action buttons: โœ“ Done ยท ๐Ÿ˜ฎโ€๐Ÿ’จ Not urgent (cools to Q2) |
| Q2 | once daily at `nag_times[0]` or `q2_default_time` | Blue channel, default importance, persistent; actions โœ“ Done ยท Move |
| Q3 | no per-task alarms; **batch alarm** at each `q3_batch_times`: one grouped notification "N quick tasks", InboxStyle lists up to 5 | Amber channel, default; per-line done via tapping into app |
| Q4 | none | โ€” |
| Unclassified | unchanged | existing channel |

Rules: dismiss changes nothing (schedule continues). Blocked / `start_date`-future tasks suppressed. Separate notification channels per quadrant so Rob can tune sound/vibration in Android settings. Boot/timezone/permission handling reuses existing code. Moving a task between quadrants cancels old alarms and registers new ones immediately (server push or next sync).

## 5. Android UI

### Visual language
- Colours (dark-first, light supported):
  - Q1 Do now โ€” coral `#FF5A5F`
  - Q2 Schedule โ€” indigo-blue `#4C8DFF`
  - Q3 Quick โ€” amber `#FFB020`
  - Q4 Someday โ€” slate `#7C8AA0`
  - Background `#0F1420`, surface `#181F2E`, text `#EAF0FA`. Each quadrant tile is a soft gradient of its colour at ~14% over surface, with a 2dp colour edge. Never colour alone: each quadrant has an icon (๐Ÿ”ฅ flame, ๐Ÿ—“ calendar, โšก bolt, ๐ŸŒ™ moon) and label.
- Type: rounded sans (e.g. Nunito/Google Sans), large counts (40sp) as hero numbers.
- Rounded 20dp corners, 12dp gaps, generous padding.

### Home: 2ร—2 matrix (mockup 1)
- Top: greeting + "Done today โœ“ 3" pill. Axis labels: columns *Urgent | Not urgent*, rows *Important | Not important* (small, muted).
- Each tile: icon + name, big count, top 2โ€“3 task titles (ellipsized), "+N more". Q1 tile shows `3/5` capacity ring.
- Bottom strip: **"12 to sort โ†’ Triage"** (only if unclassified>0), context chips ("I'm inโ€ฆ").
- FAB: **๏ผ‹** (type) with long-press for mic.
- Tap tile โ†’ quadrant screen (full list, Q1 first card enlarged). Long-press a task row โ†’ lifts (haptic) โ†’ drag; other tiles pulse; drop zone highlights; drop = reclassify (haptic + brief toast "Moved to Schedule ยท next nag 09:00 ยท Undo").
- Landscape/tablet: same grid.

### Quick classify chip on add/edit (mockup 2 sheet)
Two toggle chips **Urgent** / **Important** with live preview: "โ†’ Do now, nags every 90 min". Optional due date picker. Suggestion shown as a pre-filled ghost state ("Suggested: Schedule โ€” tap to accept").

### Triage flow (mockup 2)
- Entry from home strip, notification ("5 tasks to sort โ€” 1 min"), or Claude voice.
- One card at a time: task text, contexts, age ("added 12 days ago"), suggestion pill with reason ("mentions 'tax'").
- Four large buttons in a 2ร—2 mirror of the matrix at the bottom half (thumb zone); the suggested one outlined. Swipe aliases: โ† not important, โ†’ important then second prompt Urgent?/Not; or just buttons.
- Extras: **Done already**, **Skip** (returns later), **Delete**.
- Progress bar "7 / 47", session default 10 cards then "Nice โ€” 37 left. Continue / Later". A gentle daily nudge (one notification, 5 cards) until unclassified = 0, then it stops forever.
- Haptic tick + card flies to its quadrant corner with colour flash.
- "Accept all suggestions" option on a summary screen listing suggestions by quadrant for quick review (high-confidence only), since 47 tasks is a lot.

### Quadrant screen
Header colour band, rule line explaining behaviour ("Nags every 90 min until done"). List sorted by age/due. Row: checkbox-style done target (large), title, context chips, due badge, "blocked by โ€ฆ" dim state. Q1 "full" banner when 5/5. Q4 shows "archives in N days" per row and a weekly review shortcut.

### Done feedback
Tap done โ†’ checkbox fills with quadrant colour (150 ms), ring pulse + check draw (stroke animation), row collapses; tile count ticks down with number roll; small particle burst (8โ€“12 dots, quadrant colour); haptic `CONFIRM`. Clearing Q1 entirely: bigger "Q1 clear" celebration (soft confetti, 1.5 s, no blocking). Respect "reduce motion". Done-today counter bumps.

### Weekly review (mockup 4)
Stepper per RESEARCH ยง10. Each step one screen with big buttons; progress dots; โ‰ค5 min; "Skip step".

### Widgets (Glance/AppWidget)
- **Matrix 2ร—2 (4ร—2 cells)**: four coloured tiles with counts; tap tile deep-links to quadrant. Shows next nag time.
- **Q1 "Do now" list (4ร—2)**: up to 4 tasks with โœ“ buttons (tap opens a confirm to prevent accidental done).
- **Q2 "Today's focus" (2ร—2)** and **Knocking now** (existing plan).
- Updates on every change via broadcast; no polling.
Widgets never offer "dismiss".

### Digest (email)
```
ReKnock โ€” Tue 4 Nov
โœ“ 19 done yesterday (Q1 4 ยท Q2 7 ยท Q3 6 ยท Q4 0 ยท unsorted 2)
Knocking now: 47 โ†’ ๐Ÿ”ฅ Do now 3 ยท ๐Ÿ—“ Schedule 11 ยท โšก Quick 6 ยท ๐ŸŒ™ Someday 9 ยท โ” unsorted 18

๐Ÿ”ฅ Do now (3/5)
 โ€ข Call accountant (due tomorrow)
 โ€ฆ
๐Ÿ—“ Today's scheduled (9:00)
 โ€ข โ€ฆ
โšก Quick batch: 6 tasks โ‰ˆ 15 min
๐ŸŒ™ Archiving soon: 2 (in 3 days) โ€” reply or open app to keep
Cooled off: "Fix gutter" (no longer urgent)
18 left to sort โ†’ open triage
```
Subject: "19 done ยท 3 to do now". Honest tone, no shame.

## 6. Anti-inflation & hygiene jobs (server cron)
- Hourly: urgency decay; due-date driven recompute of `next_nag_at`; Q4 archive after `q4_archive_days` since `quadrant_changed_at` with no edit.
- Daily: digest.
- Sunday: weekly review notification; if skipped, repeats next day.

## 7. Edge cases
- Task with `due_date` but `important=NULL` โ†’ stays unclassified (nags as today) but shows due badge; triage suggests urgent.
- Quadrant changes while notification showing โ†’ replace notification via same id.
- Offline app: caches matrix; reclassification queued and synced; server wins on conflict by `updated_at`.
- Done tasks remain historical in digest stats only.
- Dependencies: blocked tasks excluded from Q counts for nag purposes but visible dimmed; unblocking triggers an immediate nag per its quadrant.
- Q1 cap bypass for due-date-derived urgency: still counts toward cap but is allowed over cap (truth beats cap) with a banner "Over capacity โ€” 7 in Q1".

## 8. Rollout phases
1. Backend + DB (migration, derivation, scheduler plan, jobs, API).
2. MCP tools.
3. Android (matrix, triage, notifications, widgets, review, polish).
Each phase ends with a testing checkpoint.

## 9. Decisions Rob may want to change
Q1 cap 5; Q1 interval 90 min; Q3 batches 12:30/17:00; Q4 21-day archive; urgency decay 3 days; unclassified unchanged; palette. All are settings/constants.
RESEARCH.md
# RESEARCH โ€” Eisenhower Matrix for ReKnock

> Method note: this is synthesised from my own knowledge of the model and of these apps' public behaviour (as of my training; app details change). I did not browse live, so treat specific app feature claims as "well-known as of last I knew" and glance at each app if a detail matters.

## 1. The model, and what it actually says

- Origin: Dwight Eisenhower ("What is important is seldom urgent, and what is urgent is seldom important"), popularised by Stephen Covey as the Quadrant Iโ€“IV model in *7 Habits*.
- Four quadrants:
  | | Urgent | Not urgent |
  |---|---|---|
  | **Important** | Q1 **Do now** (crises, deadlines) | Q2 **Schedule** (planning, health, relationships, prevention) |
  | **Not important** | Q3 **Delegate / batch** (interruptions, most email/calls) | Q4 **Drop / someday** (time-wasters) |
- The real insight is not the grid, it is **Q2 is where life improves, and Q1 is what Q2 becomes when neglected.** A Q2 task with a deadline *migrates* to Q1 as the date nears. A good implementation models that migration instead of making the user re-sort.
- Definitions that keep sorting honest:
  - *Urgent* = has a consequence **soon** (time-boxed, someone is waiting). It is about the clock, not about feeling anxious.
  - *Important* = moves you toward your goals/values or avoids real harm. It is about the outcome.

## 2. Best practices

1. **Two binary questions, not four buckets.** "Does this have a clock?" and "Does this matter?" are easier than "which quadrant?" and map to two taps.
2. **Keep Q1 small.** Commonly cited limit: ~3โ€“5 items in "Do now" at once. If Q1 has 15 things, nothing is in Q1.
3. **Protect Q2.** Put Q2 items on a *specific time*, not just a list. Unscheduled Q2 is just a wish list.
4. **Q3 = batch or hand off.** Process in one or two windows per day; don't let them interrupt Q1/Q2.
5. **Q4 = decide, then let go.** Explicit "not now" is a decision; a task that rots untouched is a hidden cost.
6. **Re-evaluate on a rhythm.** Urgency changes daily, importance rarely. A weekly review is where the matrix stays honest.
7. **Limit WIP / pick one.** Matrix tells you *category*, not *next action*; pair with "the one thing now".

## 3. Common pitfalls

| Pitfall | Why it happens | Mitigation for ReKnock |
|---|---|---|
| **Q1 inflation** โ€” everything becomes "urgent+important" | Urgency feels good; no cost to marking it | Soft cap (5) with a forced swap prompt; urgency **decays** (expires after N days unless a due date backs it); show "Q1 age" |
| **Q2 graveyard** | No time attached, never surfaces | Q2 gets a daily nag at a *scheduled time*; weekly review picks "this week's Q2 focus" |
| **Sorting fatigue** | Classifying 47 tasks in one sitting | Triage in small sessions (5/day), pre-suggest quadrant, swipe UI, unclassified stays valid |
| **Static classification** | Deadlines approach but flag stays "not urgent" | Effective urgency derived from `due_date` automatically |
| **Matrix becomes a browse-and-ignore list** | Pretty grid, no consequence | Quadrant **drives nag behaviour**; no quadrant is passive except Q4, which is an explicit, reviewed, auto-archiving parking lot |
| **Q3 disguised as Q1** | Other people's urgency | Label Q3 "Quick / batch"; digest shows Q3 ratio |
| **Over-engineering input** | Many fields per task | Quadrant optional on add; voice default is "unclassified โ†’ triage later" |

## 4. How other apps do it

*(High level; verify details in-app.)*

- **Todoist** โ€” no native matrix. Users emulate with priorities P1โ€“P4 (P1=red) plus filters (`p1 & due before: +3 days`), or the community "Eisenhower" template using labels like `urgent`/`important` and a filter-based board view. Lesson: *priority levels are the closest thing, and filters make views cheap*; but there is no drag between quadrants. Natural-language input (`p1`) is a nice low-friction pattern.
- **TickTick** โ€” built-in Eisenhower Matrix view (Pro). Four coloured quadrants, drag-and-drop tasks between them, each quadrant driven by smart-list rules (priority + due date). Defaults: high priority = important, due today/overdue = urgent. Lesson: **derive urgency from the due date, importance from priority; drag rewrites the underlying fields.** Closest to what ReKnock needs.
- **Things 3** โ€” deliberately no matrix; uses Today / Upcoming / Anytime / Someday. "Someday" is the Q4 analogue; "This Evening" is a batch bucket. Lesson: a **Someday** state with distinct, calm visual treatment; restraint is the product.
- **Sunsama** โ€” daily planning ritual: pull tasks into today, set time estimates, shutdown ritual. Not a matrix, but strong on **ritual and a "you're overcommitted" signal** when planned hours exceed capacity. Lesson: caps and rituals prevent inflation.
- **Akiflow** โ€” time-blocking inbox: triage inbox โ†’ schedule onto calendar. Lesson: **Q2 = give it a time slot**; "inbox โ†’ triage" flow with keyboard/swipe speed.
- **Eisenhower.me / Eisenhower app (Android/iOS)** โ€” pure matrix apps: 2ร—2 board, tap quadrant to add, drag between, sometimes AI "auto-sort". Often criticised for being a prettier list with no follow-through (no reminders per quadrant). Lesson: **the gap ReKnock fills โ€” the quadrant should change reminder behaviour.**
- **Priority Matrix (Appfluence)** โ€” enterprise-ish; 2ร—2 board with quadrants as expandable "buckets", drag items, email-to-task, and a bubble ordering within a quadrant. Lesson: ordering inside a quadrant matters; show top 3 with "+N more".
- **Notion / Trello templates** โ€” static boards; cautionary tale for graveyards.
- **Motion / Reclaim** โ€” auto-schedule tasks by priority + deadline: shows value of deriving urgency automatically.

**Cross-app takeaways:** (a) derive urgency from dates; (b) drag-to-reclassify rewrites fields; (c) Someday is a first-class calm state; (d) a quadrant that doesn't change behaviour is decoration; (e) triage inbox UX should be swipe-fast.

## 5. ADHD-friendly / low-friction design

- **Zero required decisions at capture.** Capture first, classify later. Unclassified is a normal state, with a gentle "triage" affordance.
- **Few choices per screen**: one card at a time, big targets, thumb-reachable bottom half.
- **Immediate, tactile reward**: haptic tick on classify, satisfying done animation, streak/"cleared" counters. Dopamine without shame.
- **No shame mechanics**: avoid red overdue counts that grow without bound; Q4 and auto-archive are framed as *relief* ("lighter by 6").
- **Externalise time**: show "next nag at 14:00" so the brain trusts the system.
- **Reduce visible load**: home shows counts and top items, not 47 rows. Q1 shows max 5; others are one tap away.
- **Time-boxed rituals**: triage of 5 tasks (~60 sec), weekly review โ‰ค5 minutes with a progress bar.
- **Voice as first-class**: Rob captures by voice; classification phrases must be forgiving.
- **Resilience to forgetting**: the persistent no-dismiss nag is already the core ADHD feature; the matrix tunes its *volume*, never removes it silently.

## 6. Fast classification methods

| Method | Gesture | Notes |
|---|---|---|
| Two taps | Tap "Urgent?" chip, tap "Important?" chip (each toggles) | Works anywhere; default both off = unclassified until touched |
| Four-button | Big coloured Q1โ€“Q4 buttons | Used in triage card |
| Swipe (Tinder-style) | Triage card: โžก important, โฌ… not important, then โฌ† urgent / โฌ‡ not urgent as second pass; or swipe into corner | Two-pass per card is still 2 gestures; alternatively diagonal swipes โ†’ 4 quadrants (more error-prone) |
| Drag | Long-press chip/row, drop in quadrant | Best for rearranging on matrix home |
| Voice | "urgent and important", "important but not urgent", "just do it quickly", "someday" | Parsed by Claude on the MCP side into booleans; MCP tool takes explicit params |
| Row swipe | In lists: swipe right = promote, left = demote | Optional |

Recommendation: **triage card with 4 big buttons + horizontal/vertical swipe aliases; drag on matrix; voice via MCP params.**

## 7. Auto-suggest quadrant

Deterministic, explainable heuristics (no LLM needed on-device; Claude on voice can do richer reasoning and pass explicit values):

- **Urgent signals**: `due_date` โ‰ค 48h; words "today", "tonight", "tomorrow", "asap", "deadline", "overdue", "before <weekday>", "by EOD", "expires", "due"; task with nag history of repeated offers; blocking other tasks (`blocks` non-empty โ†’ raise urgency/importance).
- **Important signals**: words "tax", "insurance", "doctor", "health", "pay", "bill", "renew", "contract", "client", "kids", "family", "launch", "invoice", "license"; context `Premco`/`ODL` (work) โ†’ important; `blocks` count โ‰ฅ 1.
- **Not important signals**: "maybe", "someday", "look into", "check out", "organize", "browse", "idea"; context-only tasks that were auto-promoted to daily nags after 3 days unoffered โ†’ suggest Q4 or Q2 and ask.
- **Delegate/quick signals**: "call", "email", "reply", "text", "book", "order", "pick up", "drop off"; context Phone call / Errands โ†’ Q3 candidate if not important.
- Output `{suggested_quadrant, confidence, reason}`. Never auto-apply below high confidence; in triage the suggestion is the **pre-highlighted button**, one tap to accept.

Also, **effective urgency** is computed live: `urgent = manual_urgent OR due_date within 2 days`.

## 8. Quadrant โ†’ nag intensity

| Quadrant | Behaviour | Rationale |
|---|---|---|
| **Q1 Do now** | Persistent notification; re-nags every **60โ€“120 min** (default 90) between 08:00โ€“21:00 in addition to its `nag_times`; first nag immediately when moved into Q1; cap of 5 tasks | Real urgency deserves frequency; the cap stops notification fatigue |
| **Q2 Schedule** | **One** nag per day at its chosen time (default 09:00 if none; use existing `nag_times[0]`); optionally "this week's focus" pin | Calm, predictable, protects important/non-urgent work |
| **Q3 Quick/batch** | No individual nags; **two batch notifications** per day (e.g. 12:30 and 17:00): "6 quick tasks โ€” 15 min?" with expandable list; each still needs mark-done | Batch cuts interruptions |
| **Q4 Someday** | No daily nags. Included in Sunday weekly review. If untouched **21 days** โ†’ auto-archive (status `archived`, recoverable, announced in digest). | Prevents graveyard without losing data |
| **Unclassified** | **Current behaviour unchanged** | Safe migration; no surprises |

Philosophy check: dismissing a notification still changes nothing; the schedule continues. Only done (or an *explicit* user re-classification / auto-archive of Q4) stops nagging. Q4 is the one deliberate carve-out and is a conscious user decision, reviewed weekly, and reversible. Contexts and `start_date` still apply first (a task quiet until a date stays quiet; blocked tasks don't nag until unblocked).

## 9. Preventing Q1 inflation

1. **Soft cap 5**: adding a 6th shows "Q1 is full. Swap one out?" (pick one to demote). Voice/MCP gets a response telling Claude, who asks Rob.
2. **Urgency decay**: manual urgency without a due date expires after **3 days** โ†’ falls to Q2 (with a visible "cooled off" note in the digest). Re-affirm with one tap ("still urgent").
3. **Due-date-backed urgency is truthful**: derived, not manual, so no gaming.
4. **Q1 ratio in digest**: "Q1 is 8% of your tasks" โ€” gentle awareness.
5. **Q1 age badge**: items in Q1 > 7 days ask "Is this really urgent, or just important?"
6. **Frequency cost**: Q1 nags are loud, so users self-police.

## 10. Weekly review ritual

Sunday (configurable) notification "Weekly reset โ€” 5 min". Guided steps, each a single screen:
1. **Celebrate**: done this week by quadrant.
2. **Q1 audit**: each Q1 item: still urgent? (keep / cool to Q2 / done).
3. **Pick Q2 focus**: choose up to 3 Q2 tasks to give a specific day/time this week.
4. **Q3 sweep**: batch or drop.
5. **Q4 purge**: keep / delete / promote; items with archive countdown shown.
6. **Triage leftover unclassified.**
Finish โ†’ confetti-lite, `last_reviewed_at` set; skip allowed (reminds again next day, nag-style).

## 11. Integration with contexts and dependencies

- **Contexts**: orthogonal to quadrant. "I'm in Computer mode" shows tasks for that context **sorted Q1โ†’Q2โ†’Q3โ†’Q4** with quadrant colour dots; Q4 hidden by default. The matrix home gets a context filter chip.
- **Dependencies**: a blocked task is dimmed in its quadrant ("waiting on X") and doesn't nag; the *blocker* inherits `max(urgency/importance)` of what it blocks as a *suggestion/badge* ("blocks a Q1 task") โ€” and optionally effective quadrant promotion, but only displayed, never silently rewriting fields.
- **Context-only tasks** (become daily 09:00 nags after 3 days unoffered): treated as unclassified; triage suggests Q2 (keep nagging daily) or Q4.
- **start_date**: quiet tasks are shown dimmed/collapsed in a "Later" strip, not in quadrant counts.

## 12. Sources / further reading (from memory โ€” verify links)
- Covey, *The 7 Habits of Highly Effective People* (Quadrant II).
- Eisenhower speech, 1954 (quoting Dr. J. Roscoe Miller).
- TickTick help centre: "Eisenhower Matrix".
- Todoist templates/blog on Eisenhower filters.
- Things 3 docs on Someday/This Evening.
- Sunsama "daily planning ritual" documentation.