Browser conversation

Read qualified messages, explicitly sign notes or replies, and retain your own key and canonical records. Readers need no native installation. Open an operator’s configured address; host instructions describe setup. For saved files without a host or key, use the archive reader.

Join and write

  1. Trust this site before loading a key: its code can read the secret and sign as you. Never load an issuer’s or another person’s key.
  2. Under Identity, choose Open saved key, or Create identity → Save key file. Check that a new key file actually exists and confirm it was saved. The file is unencrypted; anyone holding it can sign as you.
  3. Copy public identifier and give the operator your V.…H3 identifier, never the secret. Enrollment separately grants reading and writer acceptance.
  4. Under Connection, confirm the complete-channel trust statement and Connect. Remote use requires trusted HTTPS/WSS. Loopback alone does not isolate other users of the machine.
  5. Choose Reply on a message or New note. The single composer keeps the exact target under Reply target; a new note has none. Inspect your text, then Sign and save. Status distinguishes local save, emission, and settled exchange. None promises permanent remote retention.

Identity and Connection stay in their fixed sections. Menu → Access and evidence shows acquired current grants. A writer without reading can create a root note; a reader without writer acceptance cannot sign through this UI. The host can change either grant without replacing the running policy. Withdrawals change current selection, not retained copies.

A draft retains its original target through refreshes. If that target leaves the current view or writer acceptance disappears, signing is disabled but the draft stays. Cancel before choosing another target.

Keep and return

The secret stays in page memory, not browser storage. Return by opening the saved key. Identity → Close participant and forget loaded key waits for operation and store closure, then releases the key even if cleanup fails. JavaScript cannot promise erasure of prior memory copies; page termination is not waitable settlement.

Records persist in origin-local OPFS under issuer and participant key. Keep one tab per participant. Storage failure does not fall back to volatile memory. Clearing site data loses unexported records; browser storage is not a backup.

Menu → Export / import exports an ordinary ZIP containing:

No secret is included. Keep the separate key file and inspect exports before sharing. Unzip an export for the archive reader. To restore at a configured host, open your saved key and import the exported .lace files. Import validates bytes; connected exchange still follows policy. Native import uses joinery --state STATE import records.

A key file is exactly one canonical &.<b64a>.H3 line ending in LF, with no BOM, CR, spaces, or envelope. The format does not distinguish issuer and browser keys.

Interpretation

Qualified selection owns grants, fields, currentness, exposure, and source composition. Local presentation captures inputs once and evaluates them through Lace on one unchanged private snapshot. JavaScript does not rank grants or implement another ACL. Incomplete results are errors, not empty conversations. Current evidence cannot establish global freshness.

Signing uses device-declared Unix epoch seconds and the browser’s IANA timezone. Neither proves creation time. Numeric ordering remains exact text; display uses human-readable dates, labeled UTC fallback for unknown zones, and “unavailable” for dates outside the browser’s range. Details retain exact fields and identifiers. “You” identifies the loaded key, not a verified person. Text and patches are inert; see the reply convention.

Build and checks

The host serves index.html, app.mjs, policy.mjs, export.mjs, generated runtime/ bundles, the four exact definitions, and config.json containing issuer, scope, and endpoint: "iltp". URLs are relative, preserving a hosted path prefix. Missing configuration fails rather than creating a local identity. Source decoding preserves exact UTF-8 bytes for compiler validation.

After building the host and assets, run from the joinery directory:

timeout 55s uv run --script tests/browser_conversation.py
timeout 55s uv run --script tests/browser_conversation_correctness.py
timeout 55s uv run --script tests/browser_conversation_ui.py