You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+4-4Lines changed: 4 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,7 +8,7 @@ The product requirements document is in [`docs/prd/pi-postbox.md`](docs/prd/pi-p
8
8
9
9
## Current status
10
10
11
-
Version 0.2.9 coordinates protocol 0.1.9 with Android 0.4.2 (build 6), generated cross-language conformance fixtures, exact-match version gating, hard-block mismatch UX, durable Answer-driven agent auto-wake, and answer-ready widget cleanup after reads.
11
+
Version 0.2.10 coordinates protocol 0.1.9 with Android 0.4.3 (build 7), keeps the current-owner footer count synchronized with Question lifecycle changes, makes configured development and production API ports strict, and adds a privacy-preserving Android notification-backed launcher badge for the full pending queue. It retains generated cross-language conformance fixtures, exact-match version gating, hard-block mismatch UX, durable Answer-driven agent auto-wake, and answer-ready widget cleanup after reads.
12
12
13
13
Issues #1-#11 provide the v1 implementation: runnable TypeScript workspace, `pi-postbox-server` CLI, Pi extension with `write_question`, WebSocket session registration, SSE browser state, SQLite persistence/history, structured Questions and options, semantic working/blocked/idle state, reconnect/idempotency/expiry, local terminal fallback commands, editable presentation metadata, and packaging/deployment docs plus a release smoke script. Version 0.2.6 updates Android 0.4.1 to include the server-required Question revision when submitting an Answer. Version 0.2.5 keeps the footer and status surfaces from undercounting a locally tracked open Question when the durable owner snapshot is briefly stale, makes published package updates robust on npm 11, and prebuilds the shared protocol before clean-checkout test runs. Version 0.2.3 adds validated npm Trusted Publishing from pushes to the main branch through GitHub Actions OIDC. Version 0.2.2 adds complete npm license and source metadata, fixes the published CLI bin path, and excludes test source from the package tarball. Version 0.2.1 bounds and paginates every model-facing bulk read, uses compact stateless cursors, hides inactive historical owners by default, trims repeated list fields, and preserves checkout development ports across restarts. Version 0.2.0 replaces the separate model-facing create/update tools with one explicit-action `write_question` surface and returns reusable current Question handles from creation. Version 0.1.9 requires a concise ambiguity for new Questions, simplifies parent and expiry inputs, renames option `meaning` to `impact`, removes top-level handoff context and per-option context, removes reconstructed Question Chat, and renders single/multi choice with accessible ballot controls. Version 0.1.8 exposed single-Question create/idempotent receipt disposition and safely required a full Pi restart when `/reload` retained an incompatible shared protocol dependency. Version 0.1.7 reduced model-facing tool schemas, strictly described exact-owner filters, and made recovery reads compact by default with an explicit full view while preserving strict server-side action validation and internal provenance/expiry compatibility.
14
14
@@ -26,7 +26,7 @@ Start the local server with defaults:
26
26
node packages/server/dist/cli.js
27
27
```
28
28
29
-
The server binds to `127.0.0.1`, treats port `32187` as the canonical default, stores data in `~/.pi-postbox/postbox.sqlite`, and prints the actual listening URL. If port `32187` is already in use, it automatically selects another local port and prints an explicit warning that the local/Tailnet bookmark URL is non-canonical; free `32187` or set `--port` / `PI_POSTBOX_PORT` to a stable available port if you need a bookmarkable URL.
29
+
The production server binds to `127.0.0.1`, uses the fixed canonical port `32187`, stores data in `~/.pi-postbox/postbox.sqlite`, and prints the listening URL. If configured port `32187` is already in use, startup fails instead of silently changing the local and Tailnet URLs. Use `--port` / `PI_POSTBOX_PORT`only to configure a deliberate stable alternative.
30
30
31
31
## Workspace commands
32
32
@@ -135,7 +135,7 @@ An answered request, a cancelled request, expiry, or Pi Session replacement thro
135
135
Supported server flags and environment variables:
136
136
137
137
-`--host` or `PI_POSTBOX_HOST` (default `127.0.0.1`)
138
-
-`--port` or `PI_POSTBOX_PORT` (preferred default `32187`; falls back to another local port if already in use)
138
+
-`--port` or `PI_POSTBOX_PORT` (fixed canonical default `32187`; startup fails if the configured port is already in use)
139
139
-`--ui-dist-dir` or `PI_POSTBOX_UI_DIST_DIR` (default packaged `dist/public` beside the server CLI)
140
140
-`--database` or `PI_POSTBOX_DATABASE` (default `~/.pi-postbox/postbox.sqlite`)
141
141
-`--profile` or `PI_POSTBOX_PROFILE` (`production` or `development:<checkout-id>`)
@@ -160,7 +160,7 @@ Override config location with `PI_POSTBOX_CONFIG_PATH` or `PI_POSTBOX_CONFIG_DIR
160
160
161
161
For local self-healing, each profile publishes only `<profile-state-dir>/active-local/server.json`. The extension validates that record against `/healthz` profile, instance, URL, protocol, and build identity. Health reports the package version separately from the protocol version, while the default build id fingerprints the loaded runtime bytes. It never orders or falls back across profiles. A global production loopback `serverUrl` is therefore invisible to a checkout development profile, while `PI_POSTBOX_URL` remains an intentional escape hatch.
162
162
163
-
`npm run dev` derives the checkout identity, selects independent backend/UI ports, persists them in the checkout profile's `dev-ports.json` for safe reuse across restarts, uses its own database and metadata, and never stops production. It relies on the server's content-specific build fingerprint instead of assigning one static build id to the checkout. It exposes the development API through Tailscale Serve when available and non-conflicting, using the API's separate port so the production mapping remains untouched. Set `PI_POSTBOX_TAILSCALE=off` to disable this exposure. Separate clones and worktrees can run concurrently. The dashboard title and persistent accessible `Development server` badge come from authoritative `/healthz` profile state.
163
+
`npm run dev` derives the checkout identity, binds its API to the canonical development port `45795` (or an explicit `PI_POSTBOX_PORT`), selects and persists a separate Vite/HMR port in the checkout profile's `dev-ports.json`, uses its own database and metadata, and never stops production. If the API port is occupied, startup fails instead of changing the API URL; the Vite port may be safely reselected and persisted. The launcher relies on the server's content-specific build fingerprint instead of assigning one static build id to the checkout. It exposes the development API through Tailscale Serve when available and non-conflicting, using the API's separate port so the production mapping remains untouched. Set `PI_POSTBOX_TAILSCALE=off` to disable this exposure. The canonical API port is shared intentionally, so separate clones/worktrees need explicit distinct `PI_POSTBOX_PORT` values if run concurrently. The dashboard title and persistent accessible `Development server` badge come from authoritative `/healthz` profile state.
164
164
165
165
Package-local autostart is enabled by default for `write_question` and the user-only `/postbox` dashboard command. Set `PI_POSTBOX_AUTOSTART=off` to disable spawning a bundled server. Set `PI_POSTBOX_AUTOSTART_TIMEOUT_MS` to change the recovery wait; the default is 10 seconds (`10000` ms).
The app verifies the server with `GET /healthz` before saving the URL. Keep the existing Tailnet-private trust model: do not expose the Postbox server publicly for this prototype.
53
53
54
-
Android 0.4.2 (build 6) supports Postbox protocol 0.1.9 exactly. The app displays this identity before and after connection, rechecks saved endpoints, and blocks state, Answer, cancel, refresh, Question Chat, and push registration when the active endpoint reports missing or different protocol evidence. Regenerate the shared contract with `npm run generate:android-protocol-contract`; CI uses `npm run check:android-protocol-contract` plus Android unit/lint/assembly gates to reject drift.
54
+
Android 0.4.3 (build 7) supports Postbox protocol 0.1.9 exactly. The app displays this identity before and after connection, rechecks saved endpoints, and blocks state, Answer, cancel, refresh, Question Chat, and push registration when the active endpoint reports missing or different protocol evidence. Regenerate the shared contract with `npm run generate:android-protocol-contract`; CI uses `npm run check:android-protocol-contract` plus Android unit/lint/assembly gates to reject drift.
55
55
56
56
## Emulator localhost fallback
57
57
58
58
Android emulators cannot reach the host machine at `localhost`. If the Postbox server is running on the development machine and you are testing in an emulator, use `10.0.2.2` as the host, for example:
59
59
60
60
```text
61
-
http://10.0.2.2:32187/
61
+
http://10.0.2.2:45795/
62
62
```
63
63
64
64
Prefer the Tailnet HTTPS URL for real-device evidence; use the emulator fallback only for local development.
65
65
66
66
## Notifications and FCM push
67
67
68
-
The native app does not reuse browser Web Push subscriptions. Two notification paths share the same notifier and per-request notification ids, so a question never shows up twice:
68
+
The native app does not reuse browser Web Push subscriptions. Two notification paths share the same notifier and per-request notification ids, so the same question does not produce duplicate per-question notifications:
69
69
70
70
1.**In-app observation**: while the connected question screen is active, fetched/SSE state snapshots are observed and newly seen pending request ids post one Android local notification.
71
-
2.**FCM push (app closed or backgrounded)**: when Firebase is configured, the app registers its FCM token with the verified Postbox server, and the server pushes new pending questions as data-only FCM messages that `PostboxFirebaseMessagingService` renders through the same notifier.
71
+
2.**FCM push (app closed or backgrounded)**: when Firebase is configured, the app registers its FCM token with the verified Postbox server, and the server pushes new pending questions as data-only FCM messages that `PostboxFirebaseMessagingService` renders through the same notifier. Its best-effort state prefetch also reconciles the full pending queue.
72
72
73
-
The notification content is privacy-preserving (it does not include the question prompt); tapping it reopens the appand selects the relevant question if that request is still present in the latest observed state.
73
+
In addition to per-question notifications, every authoritative pending snapshot maintains one quiet, ongoing summary notification for the complete Android queue. The summary carries the pending count with Android's standard `setNumber` metadata and drives the launcher app-icon badge when the launcher supports notification badges. Launchers and OEMs control the presentation: some display the number and others display only a dot. Resolving the final pending question removes the summary and badge source.
74
74
75
-
On Android 13+, the app requests `POST_NOTIFICATIONS` and gates posting on the runtime permission. If permission is denied, notifications are disabled but the question workflow remains usable: loading, viewing, answering, and cancelling questions are not blocked.
75
+
All notification content is privacy-preserving and omits Question prompts. Tapping a per-question notification reopens the app and selects that Question if it is still present in the latest observed state; tapping the summary opens the app.
76
+
77
+
On Android 13+, the app requests `POST_NOTIFICATIONS` and gates posting on the runtime permission. If permission is denied—or launcher/channel badges are disabled—the notification-backed launcher badge is unavailable, but the question workflow remains usable: loading, viewing, answering, and cancelling Questions are not blocked.
0 commit comments