From b24a148add7b6137a1da3bd245178e40e7a7b18e Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Thu, 4 Jun 2026 16:59:38 -0700 Subject: [PATCH] doc(heph-pwa): how-to card, index entry, changelog fragment Document serving the app from the hub (--web-root), connecting (hub URL + optional token), quick-add syntax, voice, triage, and the deliberate design choices (PWA over native iOS; online-only; token paste vs device flow) with their known limitations to revisit. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../feature-heph-pwa-mobile.feature.md | 1 + docs/how-to/heph-pwa.md | 118 ++++++++++++++++++ docs/how-to/how-to.md | 1 + 3 files changed, 120 insertions(+) create mode 100644 docs/changelog.d/feature-heph-pwa-mobile.feature.md create mode 100644 docs/how-to/heph-pwa.md diff --git a/docs/changelog.d/feature-heph-pwa-mobile.feature.md b/docs/changelog.d/feature-heph-pwa-mobile.feature.md new file mode 100644 index 0000000..3dffb02 --- /dev/null +++ b/docs/changelog.d/feature-heph-pwa-mobile.feature.md @@ -0,0 +1 @@ +New **heph-pwa** mobile app: an installable, phone-first PWA that mirrors heph-tui — browse the built-in views and projects, triage tasks, and capture new tasks fast with the same quick-add syntax (`p1-4`, `#Project`, `today/+3d/fri`, `every …`) and live preview. Voice capture via on-device dictation. The hub (`hephd --mode server`) gains CORS and an optional `--web-root` so it can serve the app same-origin straight from the daemon. diff --git a/docs/how-to/heph-pwa.md b/docs/how-to/heph-pwa.md new file mode 100644 index 0000000..dbc19ef --- /dev/null +++ b/docs/how-to/heph-pwa.md @@ -0,0 +1,118 @@ +--- +title: heph-pwa (mobile app) +modified: 2026-06-04 +tags: + - how-to +--- + +# heph-pwa — the mobile app + +`heph-pwa` is a phone-first, installable web app that mirrors [[v1-prototype-tech-spec|heph-tui]]: +browse the built-in views and projects, triage tasks, and — the primary use +case — **capture tasks fast** with the same quick-add syntax as the TUI's `a` / +Cmd-' popover. Context/KB is **read-only** here (no Neovim editing surface). + +It is a thin, online-only client: every read and write is a JSON-RPC call to a +**server-mode `hephd`** (the sync hub, see [[set-up-sync-hub]]). There is no +local replica or background sync — when the hub is unreachable, the app shows an +error rather than queueing offline. + +> **Why a PWA and not native iOS?** A native Swift app cannot be signed, built, +> or installed without an Apple Developer account. A PWA delivers the primary +> use case today — installable to the home screen, full-screen, with home-screen +> launch and offline app-shell — and keeps the door open to a native wrapper +> later. This was a deliberate first-cut choice; revisit if a native app becomes +> worthwhile. + +## Serve it from the hub + +The hub can serve the app shell same-origin (no CORS or separate static host +needed). Point `hephd` at the `heph-pwa/` directory: + +```bash +hephd --mode server \ + --http-addr 0.0.0.0:8787 \ + --web-root /path/to/hephaestus/heph-pwa \ + --oidc-issuer https://auth.example.com/... \ + --oidc-audience heph-mobile +``` + +- `--web-root` is optional. Unset, the hub serves only its API routes (unchanged + behavior). Set, it serves the static shell for any non-API path, with an + `index.html` SPA fallback. The shell is unauthenticated (it's just HTML/JS); + all data still flows through the auth-gated `/rpc`. +- Every hub response now carries permissive CORS headers and answers the browser + `OPTIONS` preflight, so you can alternatively host the shell anywhere (any + static server, GitHub Pages, etc.) and still call the hub cross-origin. + +Then open `https://:8787/` on your phone and **Add to Home Screen**. + +## Connect + +On first launch the app opens **Settings**: + +- **Hub URL** — the server-mode `hephd` base URL (e.g. `https://hub.example.com:8787`). + When served from the hub, use that same origin. +- **Token** — a bearer token, if the hub requires OIDC (`--oidc-issuer`/`-audience`). + Leave blank for an unauthenticated hub (local network / dev). Tap **Test** to + verify the connection (it calls the `version` RPC). + +Settings persist in the browser's local storage. + +> The device-code OIDC login flow (RFC 8628) the CLI/daemon use is **not** yet +> wired into the PWA — for now paste a bearer token obtained out-of-band. Wiring +> the in-app device flow is the obvious next step. + +## Quick-add + +Tap **+** (or press Cmd-' / Ctrl-' on a keyboard) to capture. The single input +accepts the exact [[v1-prototype-tech-spec|tech-spec §8.1]] syntax, parsed live +into preview chips before you submit: + +| Token | Example | Effect | +|-------|---------|--------| +| `p1`–`p4` | `p1` | attention: red / orange / blue / white | +| `#Project` | `#Camano Chores` | file under a project (greedy multi-word match) | +| date | `today` `tomorrow` `+3d` `fri` `2026-07-01` | do-date | +| `every …` | `every 3 days` `every other wed` `every workday` | recurrence (RRULE) | + +Unmatched `#tags` stay in the title verbatim. With no `#Project` token, the task +files into the currently selected project (or Inbox). The parser is a faithful +JS port of the Rust `quickadd`/`datespec` modules, covered by parity tests +(`heph-pwa/test/parsers.test.mjs`, run with `node --test`). + +## Voice + +The quick-add field supports voice two ways: + +- **iOS / iPadOS:** use the **microphone key on the on-screen keyboard** — Apple + dictation works in the text field for free, no app permission needed. +- **Chrome / Android / desktop:** a 🎤 button appears when the Web Speech API is + available and dictates straight into the field. + +(Anthropic has no speech-to-text endpoint, so transcription leans on the +platform. A server-side transcription proxy could be added later if needed.) + +## Triage + +Tap a task to expand its actions, mirroring the TUI keys: **Done** (`x`), +**Drop** (`d`), **Skip** (`S`, recurring only), **Attn** (cycle attention, `A`), +**Date** (reschedule, `e`), **Move** (project picker, `m`), **Delete** +(tombstone, `D`). Done/Drop show an **Undo**. The expanded view also shows the +task's canonical-context body + recent log tail (read-only). + +Search (🔍 or `/`) runs full-text search across tasks and docs. + +## Known limitations (first cut) + +- Online-only; no offline write queue or CRDT replica. +- No in-app OIDC device-code login yet (paste a token). +- Context/KB is read-only (no wiki-link navigation or editing). +- Undo covers Done/Drop only. + +## Related + +- [[set-up-sync-hub]] — stand up the server-mode hub the app talks to +- [[run-the-daemon]] — run `hephd` as a managed service +- [[v1-prototype-tech-spec]] — data model, RPC API, quick-add spec +- [[design]] — vision and rationale diff --git a/docs/how-to/how-to.md b/docs/how-to/how-to.md index eb0a6c8..62c0173 100644 --- a/docs/how-to/how-to.md +++ b/docs/how-to/how-to.md @@ -21,3 +21,4 @@ Task-oriented guides for common operations. - [[set-up-sync-hub]] — Stand up the canonical hub (indri) and connect an existing device as an offline-capable spoke - [[import-todoist]] — Seed a heph store from your Todoist projects + tasks (`mise run import-todoist`) - [[self-update]] — Opt-in `hephd` self-update: poll the forge for new releases and auto-update +- [[heph-pwa]] — The mobile app: an installable PWA mirror of heph-tui (browse, triage, fast quick-add, voice)