hephaestus/docs/how-to/heph-pwa.md
Erich Blume 936c2635ef
All checks were successful
Build / validate (pull_request) Successful in 6m18s
doc(heph-pwa): production runbook — host the app from the hub (indri) with OIDC
Add host-heph-pwa.md: a deployment how-to for serving the PWA from the canonical
hub in the hub/spoke OIDC setup (post-release) — fetch the shell at the hub's
tag, add --web-root, terminate TLS (tailscale serve / reverse proxy), and the
token-paste caveat with the device-code-login follow-up. Cross-linked from
heph-pwa and the how-to index.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 17:17:25 -07:00

119 lines
5.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
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
- [[host-heph-pwa]] — serve this app from the hub (indri) with OIDC, in the hub/spoke deployment
- [[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