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) <noreply@anthropic.com>
This commit is contained in:
Erich Blume 2026-06-04 16:59:38 -07:00
commit b24a148add
3 changed files with 120 additions and 0 deletions

View file

@ -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.

118
docs/how-to/heph-pwa.md Normal file
View file

@ -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://<hub-host>: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

View file

@ -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)