Add deep links for chats and messages #4

Open
opened 2026-08-21 08:28:48 +00:00 by kayg · 2 comments
Owner

Goal

Support stable deep links that open Hermternal to a chat and, where possible, a specific message.

Proposed routes

  • hermternal://chat/<durable-session-id>
  • hermternal://chat/<durable-session-id>/message/<message-id>

Also support universal HTTPS links later if a canonical web origin is available.

Behavior

  • Cold launch: restore auth, load/cache the target transcript, resume the durable session, then scroll to and briefly highlight the target message.
  • Warm launch: switch immediately from cache and reconcile in the background.
  • Invalid, deleted, or unauthorized targets show a clear recoverable error; never fall back silently to another chat.
  • Add Copy Link to Chat and Copy Link to Message context-menu actions.

Data prerequisite

Current cached ChatMessage.id values are locally generated UUIDs. Define and persist a stable server-backed message identity before message-level links ship.

Acceptance

Links work from Finder/Terminal and across cold/warm launches without exposing credentials in the URL.

## Goal Support stable deep links that open Hermternal to a chat and, where possible, a specific message. ## Proposed routes - `hermternal://chat/<durable-session-id>` - `hermternal://chat/<durable-session-id>/message/<message-id>` Also support universal HTTPS links later if a canonical web origin is available. ## Behavior - Cold launch: restore auth, load/cache the target transcript, resume the durable session, then scroll to and briefly highlight the target message. - Warm launch: switch immediately from cache and reconcile in the background. - Invalid, deleted, or unauthorized targets show a clear recoverable error; never fall back silently to another chat. - Add **Copy Link to Chat** and **Copy Link to Message** context-menu actions. ## Data prerequisite Current cached `ChatMessage.id` values are locally generated UUIDs. Define and persist a stable server-backed message identity before message-level links ship. ## Acceptance Links work from Finder/Terminal and across cold/warm launches without exposing credentials in the URL.
Author
Owner

Design-session details to carry into implementation:

  • The same link must resolve on a future iOS app as well as macOS.
  • Links must remain unambiguous if multiple Hermes gateway backends exist.
  • An HTTPS universal link such as https://<gateway-host>/m/<sessionID>/<messageID> encodes the backend in its own host, so backend disambiguation comes for free, and universal links behave identically on macOS and iOS. The cost is that the gateway must serve /.well-known/apple-app-site-association and both apps need the Associated Domains entitlement. Issue #4 already anticipated HTTPS links as a later step; this is supporting evidence for promoting that step, not a new direction.
  • The locally generated UUID problem identified under Data prerequisite has been partially addressed: commits b944320 and 4d52e68 made ids deterministic, derived from sessionID plus role plus text plus an occurrence counter. This is stable across projections and relaunches but is still client-derived, not server-backed. Whether the gateway exposes a per-message id is still unverified.
Design-session details to carry into implementation: - The same link must resolve on a future iOS app as well as macOS. - Links must remain unambiguous if multiple Hermes gateway backends exist. - An HTTPS universal link such as `https://<gateway-host>/m/<sessionID>/<messageID>` encodes the backend in its own host, so backend disambiguation comes for free, and universal links behave identically on macOS and iOS. The cost is that the gateway must serve `/.well-known/apple-app-site-association` and both apps need the Associated Domains entitlement. Issue #4 already anticipated HTTPS links as a later step; this is supporting evidence for promoting that step, not a new direction. - The locally generated UUID problem identified under Data prerequisite has been partially addressed: commits `b944320` and `4d52e68` made ids deterministic, derived from sessionID plus role plus text plus an occurrence counter. This is stable across projections and relaunches but is still client-derived, not server-backed. Whether the gateway exposes a per-message id is still unverified.
Author
Owner

Correction to the preceding design note: do not treat HTTPS universal links as the recommended direction. The two requirements are that the same link resolve on a future iOS app as well as macOS, and that links remain unambiguous when multiple Hermes gateway backends exist.

Resolution chosen: extend the existing custom scheme so the gateway is the authority component, for example hermternal://<gateway-host>/chat/<session-id>/message/<message-id>. This disambiguates backends with no server-side work, and custom schemes resolve correctly on both macOS and iOS — Obsidian, Craft, and others ship this pattern. Issue #4's existing custom-scheme choice stands; the only change is adding the gateway to the path.

The earlier discussion that custom schemes are “second-class” on iOS was overstated. The narrower tradeoffs are no graceful fallback when the app is not installed, often no auto-linkification in plain-text contexts such as Mail and Notes, and the scheme can be claimed by any app because it is not domain-verified. None is disqualifying for a self-hosted tool. HTTPS universal links remain a possible later enhancement exactly as #4 already states, not a replacement.

Data prerequisite status: commits b944320 and 4d52e68 made ids deterministic, derived from sessionID + role + text + occurrence, stable across projections and relaunches. They remain client-derived rather than server-backed; whether the gateway exposes a per-message id is unverified.

Correction to the preceding design note: do not treat HTTPS universal links as the recommended direction. The two requirements are that the same link resolve on a future iOS app as well as macOS, and that links remain unambiguous when multiple Hermes gateway backends exist. Resolution chosen: extend the existing custom scheme so the gateway is the authority component, for example `hermternal://<gateway-host>/chat/<session-id>/message/<message-id>`. This disambiguates backends with no server-side work, and custom schemes resolve correctly on both macOS and iOS — Obsidian, Craft, and others ship this pattern. Issue #4's existing custom-scheme choice stands; the only change is adding the gateway to the path. The earlier discussion that custom schemes are “second-class” on iOS was overstated. The narrower tradeoffs are no graceful fallback when the app is not installed, often no auto-linkification in plain-text contexts such as Mail and Notes, and the scheme can be claimed by any app because it is not domain-verified. None is disqualifying for a self-hosted tool. HTTPS universal links remain a possible later enhancement exactly as #4 already states, not a replacement. Data prerequisite status: commits `b944320` and `4d52e68` made ids deterministic, derived from sessionID + role + text + occurrence, stable across projections and relaunches. They remain client-derived rather than server-backed; whether the gateway exposes a per-message id is unverified.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/hermternal-apple#4
No description provided.