Files
Lumotia/docs/roadmap/2026-04-23-corbie-feature-complete-roadmap.md
Jake 7dea5533f7 docs(hardware): file pendant research + NLnet GenAI policy; reconcile roadmap
Two new docs in docs/hardware/:

- pendant-research-2026-04-27.md — buildable plan for a Corbie-paired
  open-hardware audio capture device. Nordic nRF5340 silicon (LE Audio
  is effectively a Nordic monopoly outside Apple/Samsung), Raytac
  MDBT53-1M pre-cert module to dodge GBP 8-15k EMC chamber bill, drop
  Wi-Fi for USB-MSC sync, single Knowles SPH0645 mic, microSD disguised
  as cassette spool, hardware-locked LED in series with mic V_DD,
  Sifam analogue VU meter, Sony WM-D6C / Nagra E / Playdate / TP-7
  aesthetic. ~GBP 107 BOM at qty 100. Funding sequence: NLnet first
  (deadline 2026/06/01), Corbie waitlist soft pre-orders second,
  Crowd Supply third. 22-month timeline, ~GBP 1,200 founder personal
  capital exposure.

- nlnet-genai-policy.md — verbatim NLnet GenAI policy v1.1 with TL;DR
  and a Corbie-specific compliance plan. Read before drafting any
  NLnet application or doing GenAI-assisted work on a funded milestone.

Roadmap entry under "Post-v0.1 ideas -> Hardware companion" rewritten
to match the compass research. The earlier off-the-cuff Tier-A/Tier-B
sketch (Hailo, Wi-Fi 6, three-mic array) is wrong on most decisions
and is superseded.

Hard discipline: hardware never ships before Corbie software hits
GBP 2k MRR.
2026-04-27 11:48:52 +01:00

33 KiB
Raw Permalink Blame History

name, description, type, tags, created, status, author
name description type tags created status author
Corbie — feature-complete roadmap Build plan from 2026-04-23 baseline to full feature-complete v0.1 release roadmap
roadmap
planning
corbie
release
2026/04/23 active Wren (CORBEL's resident agent) on behalf of Jake Sames

Corbie — Feature-Complete Roadmap

What Corbie is. A local-first, cognitive-load-aware dictation + task-capture desktop app. Vulkan-accelerated Whisper / Parakeet speech-to-text, a local LLM (Qwen3 tiers) for transcript cleanup and task extraction, an MCP server for integration with Claude Desktop / Cline / Cursor, and a UI designed around ADHD / executive-dysfunction needs. Tauri 2 + Svelte 5 + Rust. Zero telemetry.

Formerly known as Kon. Rebrand in flight; repo names at jakejars/kon + git.corbel.consulting/jake/kon still carry the Kon name and will rename together with the codebase sweep in the final phase.

Baseline — where we are (2026/04/23)

Core MVP (from docs/brief/feature-set.md): 9 of 10 complete.

One gap: visual time representation (the spec's "#1 community-requested feature" — shrinking colour disks / progress rings, externalising time passage). The rest — local transcription, auto-populating tasks, WIP limits, history + search, light/dark theming, templates, vocabulary profiles, file upload, open-format markdown export — all shipped.

Post-MVP (designed, not yet prioritised): 1 of 9 complete.

MicroSteps is shipped; its "just-start" timer button emits an event that currently has no listener anywhere in the codebase. The differentiating ADHD-specific features (Margot nudges, energy-aware sequencing, rituals, if-then intentions, forgiving gamification, TTS, human-in-the-loop feedback) are all documented in the brief but not started.

Release-blockers: 1 — RB-08 macOS power-assertion, pending manual verification on a real Mac (Jake's friend Rachmann has a Mac and can run this offline).

Workspace state: main is clippy-zero-warnings, 245/245 tests passing, fmt clean, svelte-check clean, npm build clean. Three dependabot bumps landed this session plus a clippy cleanup pass and a needless_range_loop refactor. One orphan design-system WIP branch parked on github as archive.

Approach

Layer 1 first (per Jake's standing rule): build the features roughly, in series, through Phase 1 Phase 8. Do polish passes in Phase 9 and QC + release in Phase 10. Do not mix make-it-work and make-it-neat passes — every phase ships end-to-end (event wired, UI rendered, store state committed, tests updated) but does not chase aesthetic polish until Phase 9.

Ordering rationale. Phase 1 closes the Core MVP gap and unblocks the already-half-wired just-start timer. Phase 2 enables model improvement by collecting human feedback — useful even while later phases are being built. Phases 38 build the differentiating ADHD-specific features from highest-utility-per-effort to lowest. Phase 9 is polish debt. Phase 10 is release prep (including Rachmann's RB-08 verification and the Kon → Corbie codebase rename).


Phase 1 — Visual countdown + Just-Start timer

Why now. Closes the one remaining Core MVP gap. Unblocks the dangling kon:start-timer emit from MicroSteps. Directly combats time blindness, which the brief names as the single biggest lever for the target audience.

Scope.

  • FocusTimer.svelte — a progress-ring countdown component. Shrinking colour ring (not digital). Subtle colour shift across the last 15%. Remaining time label inside the ring for users who want the number; small enough that the ring dominates the visual field.
  • focusTimer.svelte.ts store — single active timer, running / paused / completed state, elapsed / remaining computed, event dispatch on state transitions.
  • Mount in +layout.svelte so the timer persists across page navigation (dictation → tasks → settings).
  • Listener for window event kon:start-timer with { durationSeconds, label } payload.
  • Trigger from MicroSteps row (already exists). Trigger from task-row context button (new).
  • Floating position top-right of main content, above everything, not intrusive when idle (hidden until a timer is running).
  • On completion: gentle chime + 3-second ring flourish + OS notification via tauri-plugin-notification. No modal. No guilt copy.
  • Store survives window close/reopen via localStorage.

Out of scope for Phase 1. Rhythmic voice anchoring (part of Margot, Phase 6). Custom-duration picker (fixed 2 / 5 / 10 / 15 min presets for now). Multi-timer UI.

Acceptance. From a MicroStep row, clicking the timer button (a) shows the ring visible somewhere on screen, (b) it counts down, (c) at 0 it fires completion + notification, (d) works across page switches, (e) survives a window close + reopen mid-countdown.

Estimated effort. Half day.


Phase 2 — Human-in-the-loop feedback

Why here. AI output quality is the single biggest determinant of whether Corbie feels useful. Thumbs-up / thumbs-down on AI-generated micro-steps and task extractions costs almost nothing to add and gives us a feedback corpus the moment anyone uses it. Enables later retraining / prompt tuning.

Scope.

  • Thumbs-up / thumbs-down buttons on every AI-generated item (micro-step row, extracted task, cleanup paragraph).
  • "Edit" path already exists for text; the feedback is additive.
  • feedback table in SQLite: item_id, item_type, rating, timestamp, optional correction_text.
  • Rust command record_feedback + list_feedback (for later export).
  • No UI surface for viewing feedback yet. Just capture. A future export pass to JSONL feeds prompt-engineering or fine-tuning.

Out of scope. Retraining loop, per-user profile adjustment, any UI to view feedback history.

Acceptance. Thumbs visible on AI-generated items. Clicking records to SQLite. cargo test on storage covers migration + insert + list.

Estimated effort. Half day to 1 day.


Phase 3 — Energy-aware task sequencing

Why here. Next-highest-utility post-MVP feature. Replaces the cut-for-OS-reasons temptation-bundling feature. Small surface, clear user-facing outcome.

Scope.

  • energy column on tasks: nullable enum High | Medium | BrainDead.
  • Migration + Rust CRUD.
  • Tag chip on task rows; tap to cycle / set.
  • Sort / filter option on the tasks page: "Match my energy" → AI surfaces tasks matching a user-set current energy, falls back to Medium if unset.
  • No automatic energy detection. Pure user input.

Out of scope. Time-of-day heuristics, calendar integration, AI-predicted user energy.

Acceptance. User tags a task, sets their current energy via a header control, tasks page filter respects it.

Estimated effort. 1 day.


Phase 4 — Read Page Aloud (TTS)

Why here. Small and self-contained. Engages auditory processing which the brief specifically calls out as a retention lever for the target audience. Uses OS-native TTS (no new dependencies, no model download). Clean single-tap affordance.

Scope.

  • Rust command tts_speak(text: String, rate: f32, voice: Option<String>) — platform dispatch:
    • Linux: spd-say (speech-dispatcher is available on most distros; graceful fallback to espeak if missing).
    • macOS: say (built in).
    • Windows: PowerShell System.Speech.Synthesis.SpeechSynthesizer.
  • Small "speaker" icon on any text view (transcript viewer, micro-step list, cleanup result).
  • Single-tap play; second tap stops. No pause/resume in v1.
  • Settings: voice picker (populated from OS), rate slider (0.52.0).

Out of scope. Premium voices. Cloud TTS. Concurrent-speaking queue. SSML.

Acceptance. Tap speaker icon on a transcript → hear it read on Linux + expected-to-work-on macOS+Windows (test matrix in Phase 10).

Estimated effort. Half day.


Phase 5 — Start / shutdown rituals

Why here. Meaningful UX but larger surface. Needs calm copy, gentle flow, and a default-off toggle because rituals can feel parental if not optional.

Scope.

  • Morning triage: on first launch after 06:00, show a modal / dedicated page: "yesterday's incomplete tasks" (from SQLite query: completed = false AND created_at < today), with checkbox pick-list, and "pick 13 for today" constraint that refuses selections > 3.
  • Evening shutdown: user-triggerable (not scheduled) review: "what got done today", "open loops to close", "separate work from rest" copy. No automation; ritual as reflection.
  • Both off by default in settings. When off, no modal, no pressure.
  • Skip-for-today button on morning triage; never shows guilt copy.

Out of scope. Calendar integration, automatic sleep detection, weekly / monthly reviews.

Acceptance. Morning modal shows correct tasks. Selecting > 3 is prevented with a gentle message. Skip works and doesn't re-prompt same day. Evening shutdown opens a reflective page, doesn't block closing the app.

Estimated effort. 1 2 days.


Phase 6 — Soft-touch nudging (Margot protocol) — REVISED 2026/04/23

Why here. Big differentiator. Scheduled late because it nudges about the things the earlier phases built (tasks, timers, rituals), and needs careful copy so it doesn't collapse into a push-notification daemon. Spec is explicit: not push notifications — anticipatory guidance.

Revised architecture — "nudge bus" hybrid. Earlier drafts proposed a Rust-side OS-activity watcher (keyboard, active window). Cross-platform review flagged this as fragile: Wayland offers no sanctioned global-keyboard API, macOS needs accessibility permission, Windows needs a message-loop hook, and the signal is low quality everywhere. Deferred to post-v0.1.

Phase 6 instead ships a frontend-owned nudge bus that consumes signals Corbie already produces:

  • Focus-timer state (running / completed / cancelled) — already on window events from Phase 1.
  • Task-completed events — adds a kon:task-completed window event dispatched when complete_task_cmd / complete_subtask_cmd resolve.
  • Micro-step generation — event from the decompose path.
  • Ritual state — ritualsMorning, lastTriageDate from settings/storage.
  • App focus / visibility — document.visibilitychange + Tauri window focus/blur events.

The bus applies suppression rules, then dispatches via Rust commands for platform-native delivery.

Notification plugin prerequisites (new cross-cutting work, done in Phase 6).

  • Add tauri-plugin-notification = "2" (Cargo.toml) + @tauri-apps/plugin-notification (package.json).
  • Register the plugin in lib.rs.
  • Frontend checks isPermissionGranted() and calls requestPermission() on first use.
  • Expose ACL entries in src-tauri/capabilities/default.json.
  • Windows caveat: notifications only deliver properly for installed apps (not tauri dev builds). Flag this in release notes and the dev HANDOVER.
  • Sound path: Windows expects a .wav file path, not a platform sound name. Drop the original spec's "Default" string for Windows; ship a tiny custom .wav in src-tauri/sounds/. macOS "Glass" is valid. Linux freedesktop sound-name message-new-instant works via tauri-plugin-notification's sound option.

Scope (revised).

  • nudgeBus.svelte.ts store — subscribes to the in-app signals above, owns cooldown/suppression logic.
  • Rust command deliver_nudge(title, body, sound?) — thin wrapper around tauri-plugin-notification that also persists a row to a new nudges SQLite table (for debugging + future analytics).
  • Trigger set for v1 (all in-app, no OS-wide detection):
    • inactivity_with_active_timer — timer running + document.visibilitystate === 'hidden' OR window blur for 90 s continuous. (We know the user has switched away; we don't need to know what they switched to.)
    • pending_morning_triage — past 10:00 local + triage enabled + last-shown ≠ today. Fires once per day; gets suppressed forever if user later skips or completes.
    • micro_step_idle — micro-step created + no kon:task-completed or kon:step-completed event for that parent-task-id within 15 min.
  • Suppression rules:
    • Global mute in settings (on/off).
    • Hard cap 3 nudges per rolling hour.
    • No nudge in first 60 s of a timer.
    • No nudge during app focus (the user is already looking).
  • Rhythmic voice anchoring: piggy-back on Phase 4 TTS. Optional "speak nudges aloud" toggle. Default off. British-English calm lines: "Time to move on", "Your list is still here". No personality yet — Phase 9.

Out of scope.

  • OS-wide activity detection (keyboard hooks, active-window polling). Deferred post-v0.1 as a separate phase, if a real need emerges.
  • Custom trigger editor (owned by Phase 7).
  • Biometric signals. Any Margot-as-character visual.

Acceptance. Each trigger fires on its defined condition in a dogfood walkthrough. Suppression observed (hidden-for-90 s → nudge; return-to-focus → no nudge). Global mute kills everything immediately. Notification permission request appears on first trigger; denial is respected.

Estimated effort. 1 2 days (including notification-plugin setup and the nudges table).


Phase 7 — Implementation intentions (if-then automation) — REVISED 2026/04/23

Why here. Leans on Phase 6's nudge bus. User-defined rules reuse the same delivery path.

Rule idempotency (new explicit requirement).

  • Each rule stores last_fired_at: ISO8601 and, for daily rules, last_fired_local_date: YYYY-MM-DD. Without this, a poll-driven "at 09:00" fires on every tick.
  • On sleep/resume: on app focus after > 10 minutes away, check each time-of-day rule; if today's fire time has passed and last_fired_local_date is not today, fire once and update. Configurable per-rule toggle: catch_up_on_resume (default ON for time-of-day rules).
  • "After a task completes" rule: subscribes to the kon:task-completed event from Phase 6. Rule fires once per task id (guarded via last_fired_task_ids).
  • "Morning triage finishes" rule: fires on either "Start the day" or "Skip for today" — skip counts as finishing. Fires once per last_fired_local_date.

Scope.

  • Rule editor UI. Minimal: if [when-condition], then [action].
  • When-conditions for v1: time of day = HH:MM, after a task completes (pick a specific task from list), morning triage finishes.
  • Actions for v1: surface a specific task (jump to Tasks page + highlight), start a 5-min timer, speak a line aloud (reuses Phase 4 TTS).
  • Rules stored in SQLite (rules table: id, name, when_json, then_json, enabled, last_fired_at, last_fired_local_date, last_fired_task_ids). Global mute respected.
  • No location triggers (desktop app, no geolocation). No app-running detection (fragile cross-platform — revisit post-v0.1).

Out of scope. Calendar triggers, cross-app automation, macro-style action chains, shared/community rules.

Acceptance. User can write "at 09:00, speak 'time to plan the day' aloud and surface my 'daily standup' task", save it, have it fire next morning at 09:00. Polling tick does not re-fire it. Delete works. Sleep the machine through 09:00; on resume the rule catches up once, then goes quiet until tomorrow.

Estimated effort. 1 1.5 days.


Phase 8 — Forgiving gamification — REVISED 2026/04/23SHIPPED 2026/04/24

Why here. Low-risk, closes the spec list.

Scope (revised — grace days dropped).

  • Completion count per day (non-punitive). "You've finished 3 today."
  • No streaks, no chains — so the original "grace days" logic was solving a problem that doesn't exist in this design. Dropped.
  • Optional "recent momentum" sparkline: last 7 days' daily completion counts as a tiny inline chart on the Tasks header. Always additive; empty days render as baseline, never as gaps.
  • Visual: soft-edged numeric badges on the Tasks header. No leaderboards, no social comparison.
  • Zero loss language. Always "look what you did".

Out of scope. Leaderboards. Shared challenges. Streak repair purchases. XP systems.

Acceptance. Complete 3 tasks today, header shows "3 today". Open the app after 4 days off, no "you were away" framing; header reads today's count only; sparkline simply shows flat zero bars for the away days.

Estimated effort. Half day.

Shipped note (2026/04/24). Landed on main across commits 729b82c to fa93033 (13 feature commits plus one style-fix commit for a comment em-dash). Migration v13 adds auto_completed on tasks; cascade path in complete_subtask_and_check_parent sets it, uncomplete_task clears it on both target and reopened parent. New storage fn list_recent_completions(pool, days) + Tauri wrapper list_recent_completions_cmd expose the fixed-length, oldest-first 7-day series. Frontend has a dedicated completionStats.svelte.ts store (listens on kon:task-completed / kon:step-completed / kon:task-uncompleted / kon:task-deleted / focus), a CompletionSparkline.svelte SVG component, and header wiring in TasksPage.svelte. Settings toggle showMomentumSparkline added (default true) in the Rituals section; Phase 9 polish may resection. Acceptance list verified by full suite: 273 Rust tests pass, cargo clippy --all-targets -D warnings clean, cargo fmt --check clean, npm run check 0/0, npm run build clean. Manual dogfood walkthrough (Task 12 Step 6) still owes real-app verification when Jake next opens Corbie.


Phase 9 — Polish debt — MOSTLY SHIPPED 2026/04/24-25

All Phase 9 work is paused until Phase 1 Phase 8 are closed. Per Jake's rule: features first, polish second.

Contents.

  • File-system .md save dialog (replace clipboard-only export). Rust write_text_file command; platform dialog via tauri-plugin-dialog.
  • Bulk select + bulk export in History.
  • LLM-powered content tags (topic:*, intent:*). Slot into the existing kon-llm stub.
  • Settings UX overhaul: bundle high-traffic settings into a "Start here" group; hide advanced behind a disclosure.
  • Visual polish pass on all Phase 1 Phase 8 surfaces: spacing, typography, motion curves, colour, dark-mode parity.
  • Accessibility pass: keyboard navigation, screen reader labels, focus order, colour contrast audit against WCAG AA.

Estimated effort. 1 2 days.

Shipped note (2026/04/25). Sub-phases 9a (export plumbing) + 9b (LLM content tags + migration v14 + storage extension) + sparkline motion / a11y polish all on main, commits 49a795f to dd45f10. Migration v14 adds transcripts.llm_tags; update_transcript_meta gains a sixth Option; the latent manualTags persistence bug was also fixed in passing (the pre-existing saveHistory() no-op stub is now bypassed by HistoryPage tag handlers calling saveTranscriptMeta). Suite green: 277 cargo tests / clippy clean all-targets / fmt clean / svelte-check 0/0 / npm build clean.

Deferred to Phase 9 follow-up (post-v0.1 polish iteration):

  • Full SettingsPage regroup into 7 progressive-disclosure groups (Start here / Transcription / Tasks / Rituals / Notifications / Accessibility / Advanced) plus search box. The 2309-line file uses a hand-rolled accordion that needs careful unwinding; only the Phase 8 carryover sparkline relocation landed this session. SettingsGroup.svelte component is in tree, ready for that pass.
  • Walkthrough-driven a11y / contrast / typography sweeps. The scoped checklist (keyboard traversal, focus-visible ring sweep, WCAG AA contrast in both themes, dark-mode parity, prefers- reduced-motion checks) needs a running dev server to validate. Phase 10a QC absorbs the walkthrough.

Phase 10 — QC + rename + release — SPLIT 2026/04/23

Earlier draft rolled QC, a full codebase rename, an app-data migration shim, and the release ceremony into one day. Review flagged this as unrealistic and split it. The rename sweep in particular crosses every surface in the app; rushing it is how you end up with kon.db on half the users' machines and corbie.db on the rest.

Pre-Phase-10: Cargo.lock policy decision — RESOLVED 2026/04/24

  • .gitignore previously excluded Cargo.lock. For a Tauri binary workspace this was the wrong default, since CI resolves dependencies fresh each run (the leading theory for the 2026-04-24 CI red-state noted in earlier HANDOVER.md revisions).
  • Resolution (Jake's hardening pass, commit b333c62): Cargo.lock now committed. Captures the dep set users actually get from release artefacts rather than whatever crates.io happened to resolve at build time.
  • No further action before v0.1.0 tagging.

Phase 10a — QC (estimated half day)

Prerequisite: Phase 1 Phase 9 complete. Cargo.lock committed.

  • Full dogfood walkthrough: record a real brain-dump → clean transcript → task extraction → micro-step one task → run a focus timer → tag energy → complete → open evening wind-down → skip morning triage → re-check no re-prompt.
  • RB-08 macOS power-assertion verification: Rachmann runs this offline on his Mac. pmset -g assertions during a live session; expected PreventSystemSleep attributed to Corbie's bundle id. On confirmation, close RB-08 and move docs/issues/power-assertion-macos-objc2.md to docs/issues/resolved/.
  • Cross-platform build matrix green across Linux / macOS / Windows.
  • Accessibility regression check: keyboard-only traversal of every new Phase 5 Phase 8 surface.
  • Freshly-clean install test on a spare user account: no stray data leaks from dev.

Rachmann's Mac slot runs in parallel; not blocking the rest of 10a.

Phase 10b — Kon → Corbie rename sweep (estimated half day to 1 day)

Runs after Phase 10a QC, after Jake has renamed the two repos in GitHub + Gitea web UIs. The rename only starts here, not earlier, so in-flight Phase 1 Phase 9 work doesn't have to re-learn event names mid-cycle.

  • package.jsonname: "corbie", description update. (Version stays at 0.1.0.)
  • Cargo crates: kon, kon-audio, kon-storage, kon-transcription, kon-llm, kon-ai-formatting, kon-core, kon-cloud-providers, kon-hotkey, kon-mcpcorbie-*. Mass-rename via Cargo.toml name field + workspace path references + use imports.
  • Binary + product names: src-tauri/tauri.conf.json (productName, identifier), .desktop file, Windows product name, macOS bundle name.
  • Install paths: ~/.local/share/kon/~/.local/share/corbie/ (plus the macOS ~/Library/Application Support and Windows %APPDATA% equivalents). App-data migration shim required — first-run checks for the old dir, moves contents, writes a sentinel .migrated-from-kon. Shim must handle the case where both dirs exist (prefer new, log the duplicate).
  • Database filename: kon.dbcorbie.db. Handled by the same shim.
  • Window titles, tray tooltip, About-dialog, README body, docs references where they name the product (leave historical brief content talking about "Kon" — it's a historical document).
  • Event names: kon:start-timer, kon:task-completed, kon:open-wind-down, kon:preferences-changed, kon:hotkey-pressed, kon:llm-download-progresscorbie:*. Single commit; one find-replace; both emitter and listener in the same diff.
  • Logs, error messages, user-facing copy (including toast strings that mention "Kon").
  • Settings SQLite key: kon_preferencescorbie_preferences. Migration reads old key on first launch, writes new key, deletes old.
  • Remotes: ssh://git.corbel.consulting:2222/jake/kon.git + github.com:jakejars/kon.git…/corbie.git. git remote set-url locally after web-UI renames.

Phase 10c — Release (estimated half day)

  • Version is already 0.1.0 in Cargo.toml, package.json, and tauri.conf.json — no bump needed. Confirm the three match.
  • Write CHANGELOG.md. Seed from this roadmap's phases. Entries are written to end-users, not engineers — "You can now read transcripts aloud" not "Added tts_speak command".
  • Write release notes in plain language: what it does, who it's for, the Kon-data migration note, the Windows notifications caveat (installed app only).
  • Tag v0.1.0 on the head commit.
  • Push tag to both remotes. GitHub Actions release workflow auto-builds artefacts for Linux / macOS / Windows.
  • Smoke-test at least one artefact per platform (ideally Rachmann covers macOS) before the release is made public.

Estimated effort (Phase 10 total). 1 2 days across 10a / 10b / 10c plus Rachmann's parallel Mac session.


Totals

  • Phase 1 8 feature build: 6 9 days of focused work
  • Phase 9 polish: 1 2 days
  • Phase 10 QC + rename + release (split): 1 2 days + Rachmann's Mac session

Total to v0.1.0 feature-complete release: ~8 13 days of focused work, depending on how much polish time Jake wants in Phase 9. Revised downward at the lower end after the Phase 8 grace-day drop and Phase 10 split clarified actual scope.

Explicit non-goals

  • Mobile apps. Corbie is desktop-first; a mobile companion is post-v0.1.
  • Cloud sync. Local-first is the floor, not a feature. Sync is out of scope through v0.1.
  • Premium voices, paid tiers, subscription. Licensing + monetisation is a separate track tracked in memory project_marketplace_creem.
  • AI body doubling (low-fi focus rooms) — validated but parked to post-v0.1.
  • Temptation bundling — cut (OS-integration impossible cross-platform; replaced by Phase 3 energy-aware sequencing).

Post-v0.1 ideas (captured, not scheduled)

Ideas worth keeping warm once the v0.1 release is out. Not tracked as phases until the core release is done.

  • Calendar integration. Read-only first pass could parse a local ICS file (Thunderbird / Evolution export) and surface day events alongside the tasks list — stays local-first. A cloud-sync pass (Google / iCloud / CalDAV) is a v0.2+ conversation because it re-opens credential handling and refresh-token plumbing that v0.1 deliberately avoids.
  • Right-click highlighted text → capture as task. Two flavours: (a) In-Corbie — context menu on a selected transcript range or viewer segment, routes to create_task_cmd with the selection as text. Small — lives naturally in Phase 9 polish or a bolt-on. (b) System-wide — highlight anywhere (browser, Slack, IDE) and call Corbie. Platform-painful: macOS Services API, Windows shell-extension, Linux desktop-env-specific context menus. Scope as a separate post-v0.1 phase.

Pocket-inspired features (2026/04/27 competitive review)

Captured after a feature scrape of heypocket.com. Pocket is the closest direct competitor in the AI transcription space. Some of its features map cleanly onto Corbie's local-first principles, others conflict and are flagged below. None scheduled into v0.1; these sit alongside the calendar and right-click ideas above as post-v0.1 candidates.

  • Multiple summary styles. A named library of cleanup templates. Realistic target is 6 to 10 well-chosen presets: action items, narrative, decisions made, meeting minutes, SOAP (clinical), brain-dump tidy-up, daily standup. Slots into the existing kon-llm cleanup pipeline; each style is a system prompt plus light GBNF grammar where structure matters. Per-profile default style. Effort: 1 to 2 days. Already half-built (the cleanup prompt does this for one style today).

  • Mind maps from transcripts. Visual topic clusters generated from a transcript. Local LLM extracts nodes and edges (GBNF-constrained), Svelte renders with Cytoscape or vis-network. Screenshot-shareable, strong marketing surface, runs entirely on-device. Differentiating, not common in this space. Marketing asset for the Innovate UK pitch (visible artefact of "on-device intelligence"). Effort: 3 to 5 days for a usable v1, mostly in the rendering and interaction layer.

  • Bulk export format expansion. Phase 9 shipped single-transcript markdown export and bulk select. Pocket ships JSON, plain text, SRT subtitles, and audio bundle. Adding format options to the existing dialog is mechanical. Effort: half day.

  • Local webhooks. HTTP POST to a user-configured local URL on transcript-finalised, task-created, task-completed events. Stays local-first (no cloud relay). Powers Obsidian plugins, Hermit integration, home automation, n8n flows. Doesn't break any design principle; composability is principle 3. Effort: 1 day. Small Tauri command, settings UI, retry-with-backoff.

  • Language picker UX. Whisper already supports 120+ languages; Corbie's UI defaults to English with no per-profile picker. Pure UX gap. Per-profile language default plus a language picker on the dictation page. No model work needed. Effort: half day.

  • "Ask the transcript" Q&A — scope expansion, requires explicit decision. Pocket's "Ask Pocket" is RAG over the user's recording history. Corbie's design principle 4 says "LLM scope is narrow ... not a chat UI". Adding this is a deliberate doctrine change, not a feature add. If it ships, scope tight: single-transcript Q&A only (not cross-history initially), local Qwen3, no chat history retained, output renders as a one-shot answer not a conversation thread. Effort: 2 to 3 days if scoped tight, open-ended otherwise. Decision required from Jake before scheduling.

Hardware companion (Corbie Pendant) — separate track

Long-horizon hardware play surfaced by the Pocket review. Not a phase of the desktop roadmap; tracked as its own programme.

Authoritative spec: docs/hardware/pendant-research-2026-04-27.md. Read that before any hardware planning conversation. The earlier Tier-A / Tier-B / Hailo / Wi-Fi-6 / three-mic sketch in this section's previous draft was off-the-cuff and is superseded.

Headline decisions (from the research):

  • Silicon: Nordic nRF5340 only. Espressif have closed LE Audio support as Won't Do; TI/Ambiq have no shipping LC3 stack. Use the Raytac MDBT53-1M pre-certified module to inherit FCC / IC / CE / UKCA, dodging an £8k to £15k EMC chamber bill.
  • Connectivity: drop Wi-Fi entirely. Sync via USB-C Mass Storage Class. The microSD card mounts as a thumb drive when plugged in. Simpler firmware, no Wi-Fi cert headache, more honest UX.
  • Mic: single Knowles SPH0645LM4H-1 PDM digital MEMS mic, ~£1.20 qty 100. AirPods Pro 1 used a single mic; that's the right precedent. No beamforming on v1.
  • No DSP. Software Opus encoding on the nRF5340 application core. xMOS XU316 draws ~120mA vs ~5mA software penalty; not worth it for v1.
  • Storage: microSD in a Hirose push-push socket, disguised as a cassette spool window inside the enclosure. Cassette aesthetic becomes literal storage.
  • Battery: single 18650 Molicel M35A from Fogstar UK (Bromsgrove), Keystone 1042 surface-mount holder. Replaceable, vape-shop-commodity supply, right-to-repair story.
  • Hardware-locked LED: in series with the mic preamp V_DD rail. Firmware physically cannot record without forward-biasing the LED. Tampering requires solder paste, not firmware compromise.
  • DPDT mute switch: cuts mic power directly, not a soft signal to the MCU.
  • Aesthetic: Sony WM-D6C × Nagra E × Playdate × TP-7. RAL 7035 or 9002 body, PMS Orange 021 C accent reserved for record button and recording indicator only. Sifam Tinsley analogue VU meter (Bracknell, custom dial MOQ 50+).
  • UK suppliers: 3DPrintUK SLS body, JLCCNC anodised faceplate, JLCPCB Economic 4-layer SMT for prototypes, JJS Manufacturing in Lutterworth (35 minutes from Northampton) for production. Tusting in Northampton for leather strap.

BOM and pricing. ~£107 all-in at qty 100 before packaging. Supports £249 retail at 55% margin or £299 Founders Edition at 63%.

Funding sequence (the research's strongest finding):

  1. NLnet NGI Zero Commons Fund first — €5k to €50k, 4 to 8 hour application, two-month decision, mandatory FLOS licence on outputs (CERN-OHL-S, GPL, CC BY-SA all fine), commercial use permitted, 0% equity. Audio-hardware precedents (Tiliqua, MILAN). Deadline 1 June 2026. GenAI compliance details in docs/hardware/nlnet-genai-policy.md.
  2. Soft pre-orders to Corbie waitlist second — Stripe payment_intent, conservative delivery promise, capped at 100 units to stay under the £90k VAT threshold. Requires Ltd company first.
  3. Crowd Supply third — only credible crowdfunding platform whose operating model handles solo-founder fulfilment via Mouser. 12% campaign fee, >90% campaign success, 100% historical delivery rate. Apply once 10 prototypes exist plus 50-100 validated pre-orders.

Total elapsed timeline: 22 months from 2026/04/27 to first units shipped. Total founder personal capital exposure: ~£1,200 across dev hardware, Ltd company setup, T&Cs review, PCB iterations beyond what NLnet covers, and contingency.

Hard discipline: hardware never ships before Corbie software hits £2k MRR. No hardware work in any week where Corbie software has not shipped a meaningful change.

Why it fits Corbie's positioning. Plays directly to the local-first moat; Pocket cannot match because their stack is cloud-routed. The pendant's marketing line writes itself: "your audio never leaves your machine."

Anchors


This roadmap is a living document. Update it at the end of each phase with actuals vs estimates and any scope revisions.