docs: organize project records
This commit is contained in:
@@ -17,7 +17,7 @@ contract here and in `RELEASE.md`.
|
||||
- Android local/cloud verification → **[docs/android-build-lane.md](docs/android-build-lane.md)**
|
||||
- Android emulator lanes → **[docs/android-emulator-testing.md](docs/android-emulator-testing.md)** — suggest the smallest relevant API 36 lanes; never run the full matrix automatically
|
||||
- `android_*` toolset + MCP → **[docs/mcp-tooling.md](docs/mcp-tooling.md)**
|
||||
- Follow-ups / deferred work / known gaps → **[TODO.md](TODO.md)** (the single home for "what's next" — never DEVLOG, never scattered code comments)
|
||||
- Follow-ups / deferred work / known gaps → **[docs/project/TODO.md](docs/project/TODO.md)** (the single home for "what's next" — never DEVLOG, never scattered code comments)
|
||||
|
||||
## Branch contract
|
||||
|
||||
|
||||
+2
-2
@@ -1279,7 +1279,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/), and this
|
||||
|
||||
- **Voice-exit chime firing on every Add-connection tap.** `ConnectionSwitchCoordinator.switchConnection` fires the `voiceStopCallback` unconditionally at step 3 (correct for connection-to-connection switches while voice is active), but `beginAddConnection` also routes through `switchConnection` to bind the placeholder Connection's auth store before the pair wizard runs — and `VoiceViewModel.exitVoiceMode()` was playing `sfxPlayer.playExit()` regardless of whether voice mode was actually on. Logcat confirmed the chime on every Add-connection FAB tap. Fix adds an idempotence guard at the top of `exitVoiceMode()`: early-return when `_uiState.value.voiceMode` is already false. Teardown is still safe to skip because every inner statement is null-guarded + try/catch-wrapped and would be a no-op on an already-stopped voice session; the only meaningful line is the `playExit()` SFX, which is what we're silencing.
|
||||
- **500 ms freeze on every Add-connection tap.** `ConnectionSwitchCoordinator.switchConnection` runs a `withTimeoutOrNull(AUTH_HYDRATE_TIMEOUT_MS = 500L)` block at step 10 to wait for the freshly-bound `AuthManager` to flip `AuthState` from `Loading` to `Paired`. The comment acknowledged Add-connection is the common path and the 500 ms was meant to be "imperceptible," but on-device it wasn't — the user perceived the delay (and the voice chime masking it) on every tap. The placeholder Connection created by `beginAddConnection` has `pairedAt == null` and an empty EncryptedSharedPreferences store, so `AuthState` will NEVER reach `Paired` — the 500 ms is pure stall. Fix short-circuits the hydrate wait when `target.pairedAt == null`: skip `withTimeoutOrNull` entirely for placeholders and log at DEBUG instead of the misleading "auth hydrate timeout" INFO. Real paired-to-paired switches still run the full hydrate wait because both sides have `pairedAt != null`.
|
||||
- **KDoc nested-comment trap in `ConnectionViewModel.relayReady` doc block.** A literal `/voice/*` path pattern inside the `relayReady` KDoc opened a nested block comment (Kotlin supports nested `/* */`, Java does not) whose `*/` then closed only the nested level — leaving the outer `/**` open for the remaining ~2200 lines of the file. Symptom: `MainActivity.kt:67` "Unresolved reference 'isReady'" plus ~50 cascading "Cannot infer type" errors across `PairedDevicesScreen`, `SettingsScreen`, `TerminalScreen`. Real errors (`Missing '}`, `Unclosed comment`) were the last two lines of `./gradlew compileGooglePlayDebugKotlin` output, easy to miss. Fix was a two-character rewrite: path patterns now wrapped in backticks AND `/*` → `/...` so the glob-looking character isn't in a block-comment position. Lesson logged in `DEVLOG.md` 2026-04-21; worth a sweep of other KDoc blocks for shell/regex-looking patterns before the next large diff.
|
||||
- **KDoc nested-comment trap in `ConnectionViewModel.relayReady` doc block.** A literal `/voice/*` path pattern inside the `relayReady` KDoc opened a nested block comment (Kotlin supports nested `/* */`, Java does not) whose `*/` then closed only the nested level — leaving the outer `/**` open for the remaining ~2200 lines of the file. Symptom: `MainActivity.kt:67` "Unresolved reference 'isReady'" plus ~50 cascading "Cannot infer type" errors across `PairedDevicesScreen`, `SettingsScreen`, `TerminalScreen`. Real errors (`Missing '}`, `Unclosed comment`) were the last two lines of `./gradlew compileGooglePlayDebugKotlin` output, easy to miss. Fix was a two-character rewrite: path patterns now wrapped in backticks AND `/*` → `/...` so the glob-looking character isn't in a block-comment position. Lesson logged in `docs/project/DEVLOG.md` 2026-04-21; worth a sweep of other KDoc blocks for shell/regex-looking patterns before the next large diff.
|
||||
|
||||
- **Orphan placeholder connections from abandoned Add-connection flows.** The `beginAddConnection` path pre-creates a placeholder Connection and switches to it before the pair wizard runs — so `applyPairingPayload` lands the token in the right auth store. Previously, cleanup of the placeholder was wired only to the explicit Cancel button and TopAppBar back arrow. System back (gesture back / predictive back) bypassed that branch, leaving the placeholder in the connection list forever. Two-part fix: (a) `PairScreen` now installs a `BackHandler` that routes system back through the same `onCancel` → `discardPlaceholderConnection` branch the explicit back arrow uses; (b) `ConnectionViewModel.init` sweeps for any existing orphans (tuple: `pairedAt == null && apiServerUrl.isBlank() && label == PLACEHOLDER_LABEL`) on cold start and removes them — the tuple cannot be produced by any real pairing, so the sweep is safe without a dry-run. If the active connection at startup points at an orphan, the sweep switches to the first surviving real connection before deleting. Fixes the "why does my chip say 'New connection…'" symptom on devices that were affected pre-fix.
|
||||
- **Pair flow now auto-starts the camera on Add connection.** `ConnectionWizard` gains an `autoStart: String?` param (currently only `"scan"` is honored). The Add-connection FAB on `ConnectionsSettingsScreen` passes it so the wizard fires the camera permission launcher on first composition instead of forcing users through the Method chooser — one obvious next step, one-tap flow. Re-pair surfaces intentionally leave `autoStart` null so the full Scan / Enter code / Show code chooser stays available there. The deep-link arg is plumbed through `Screen.Pair`'s route (`pair?connectionId=...&autoStart=...`) and `PairScreen`'s new `autoStart` param; unrecognized values fall through to the default Method step so future builds can add more targets without breaking old ones.
|
||||
@@ -2096,7 +2096,7 @@ picker.
|
||||
- **`CLAUDE.md`** — updated Git section with the new branching policy,
|
||||
added file-table entries for `hermes-relay-update`,
|
||||
`register_code_command`, and the expanded `install.sh`
|
||||
- **`TODO.md`** — captures open research questions around proper
|
||||
- **`docs/project/TODO.md`** — captures open research questions around proper
|
||||
Hermes plugin/skill/tool distribution
|
||||
- **`user-docs` vitepress site** — new "For AI Agents" copy-paste
|
||||
block on the home view, Feature Matrix component, two-track explainer,
|
||||
|
||||
+3
-3
@@ -269,10 +269,10 @@ canonical English reference material.
|
||||
|
||||
## Changelog & writing conventions
|
||||
|
||||
This is a **public repo** — `CHANGELOG.md`, `DEVLOG.md`, the README, and everything under `docs/` ship publicly. Keep them clean:
|
||||
This is a **public repo** — `CHANGELOG.md`, `docs/project/DEVLOG.md`, the README, and everything under `docs/` ship publicly. Keep them clean:
|
||||
|
||||
- **`CHANGELOG.md`** follows [Keep a Changelog](https://keepachangelog.com/) (Added / Changed / Fixed). Append your change to the `## [Unreleased]` block in the PR. Entries can carry detail while they accumulate, but at release-prep the version block is **condensed to crisp public bullets** (1–2 lines each) — the deep "how we debugged it" narrative belongs in commit messages and `DEVLOG.md`, not the public changelog.
|
||||
- **`DEVLOG.md`** is a factual engineering log — what changed, why, and how it was verified. Keep it depersonalized and third-person; it's a record, not a diary.
|
||||
- **`CHANGELOG.md`** follows [Keep a Changelog](https://keepachangelog.com/) (Added / Changed / Fixed). Append your change to the `## [Unreleased]` block in the PR. Entries can carry detail while they accumulate, but at release-prep the version block is **condensed to crisp public bullets** (1–2 lines each) — the deep "how we debugged it" narrative belongs in commit messages and `docs/project/DEVLOG.md`, not the public changelog.
|
||||
- **`docs/project/DEVLOG.md`** is a factual engineering log — what changed, why, and how it was verified. Keep it depersonalized and third-person; it's a record, not a diary.
|
||||
- **No non-public wording anywhere committed:** no personal names (attribute impersonally — identity lives in git history), no real server hostnames/IPs or internal deployment names, no AI/assistant process self-narration, no fork/branch plumbing in user-facing notes. Generic example IPs in setup docs are fine.
|
||||
|
||||
Release notes (`RELEASE_NOTES.md`, `app/src/main/assets/whats_new.txt`, `docs/play-store-listing.md`) are theme-framed and user-facing; see [RELEASE.md](RELEASE.md) §2 "Scrub for public distribution" for the full checklist.
|
||||
|
||||
+1
-1
@@ -924,7 +924,7 @@ gradlew promoteReleaseArtifact --from-track=internal --promote-track=production
|
||||
(This step was only needed as a retrofit for v0.1.0 — v0.1.1+ inherit
|
||||
the Download section automatically from `RELEASE_NOTES.md`.)
|
||||
- Confirm Play Console shows the new versionCode on the target track.
|
||||
- Update `DEVLOG.md` with a short entry for the release.
|
||||
- Update `docs/project/DEVLOG.md` with a short entry for the release.
|
||||
|
||||
## CI Behavior
|
||||
|
||||
|
||||
@@ -348,7 +348,7 @@ class BridgeCommandHandler(
|
||||
* the multiplexer. The two paths are fully independent.
|
||||
*
|
||||
* Caught by Bailey's on-device test 2026-04-14 — see the v0.4.1
|
||||
* "voice intent local dispatch loop" entry in ROADMAP.md.
|
||||
* "voice intent local dispatch loop" entry in docs/project/ROADMAP.md.
|
||||
*/
|
||||
suspend fun handleLocalCommand(envelope: Envelope): LocalDispatchResult {
|
||||
if (envelope.type != "bridge.command") {
|
||||
|
||||
+1
-1
@@ -73,7 +73,7 @@ private const val SWIPE_DISMISS_THRESHOLD_PX = 80f
|
||||
* progress" moment (pairing, long upload, a bridge action sequence). When first
|
||||
* reused, decouple it from [ConnectionStatusSnapshot] and rename to a generic
|
||||
* `StatusToast`. It also anchors [UpdateAvailableBanner]'s visual language + the
|
||||
* shared [ConnectionStepRow]/[StepGlyph] helpers. See TODO.md.
|
||||
* shared [ConnectionStepRow]/[StepGlyph] helpers. See docs/project/TODO.md.
|
||||
*
|
||||
* Rendered as a top-aligned overlay inside a `Box` — it slides down OVER the UI
|
||||
* without shifting layout. Pair it with `AnimatedVisibility(enter =
|
||||
|
||||
+1
-1
@@ -751,7 +751,7 @@ one-time pairing, the interactive PTY/TUI shell, client-side tool routing,
|
||||
auto-reconnect with TOFU cert pinning, server-side session management, the
|
||||
headless daemon, local diagnostics, and the optional Windows management tray.
|
||||
|
||||
What's next (see [ROADMAP.md](../ROADMAP.md#desktop-track) for the full track):
|
||||
What's next (see [docs/project/ROADMAP.md](../docs/project/ROADMAP.md#desktop-track) for the full track):
|
||||
|
||||
- Service installers — `install-service-{win,linux,mac}` to register the daemon with `sc.exe` / systemd user unit / `launchd` so it auto-starts on login.
|
||||
- Multi-client server-side routing — today a connected desktop client is single-slot; allow laptop + home-desktop + work-box attached simultaneously with per-client tool dispatch via a new hermes-agent `ContextVar`.
|
||||
|
||||
@@ -30,8 +30,8 @@ Status: **passed**
|
||||
|
||||
### Compared
|
||||
|
||||
- Source: `C:\Users\Bailey\.codex\generated_images\019f6640-e6dc-7c33-8aca-a1610e2a19f0\call_JzVlJKlG8KWTJRo2xup7oTlq.png`
|
||||
- Implementation: `C:\Users\Bailey\.codex\visualizations\2026\07\25\agent-drawer-audit\passport-qa-final.png`
|
||||
- Source: `<session-generated-reference>`
|
||||
- Implementation: `<session-visualization-artifact>`
|
||||
- Source size: 852 x 1846 px
|
||||
- Device viewport: Android, 1080 x 2340 px, font scale 1.0
|
||||
- State: Agent tab, Victor pinned profile, disconnected gateway
|
||||
@@ -105,11 +105,11 @@ final result: passed
|
||||
|
||||
## Assistant overlay
|
||||
|
||||
- Reference: `C:\Users\Bailey\.codex\generated_images\019fb003-68ea-7052-85c7-3745fa7e838e\call_jPwpDr9QfaCDA6k2c01StBYe.png`
|
||||
- Reference: `<session-generated-reference>`
|
||||
- Implementation captures:
|
||||
- `C:\Users\Bailey\.codex\visualizations\2026\07\29\019fb003-68ea-7052-85c7-3745fa7e838e\assistant-live-compact.png`
|
||||
- `C:\Users\Bailey\.codex\visualizations\2026\07\29\019fb003-68ea-7052-85c7-3745fa7e838e\assistant-live-expanded.png`
|
||||
- Combined comparison: `C:\Users\Bailey\.codex\visualizations\2026\07\29\019fb003-68ea-7052-85c7-3745fa7e838e\assistant-design-comparison.png`
|
||||
- `<session-visualization-artifact>`
|
||||
- `<session-visualization-artifact>`
|
||||
- Combined comparison: `<session-visualization-artifact>`
|
||||
- Device viewport: 1080 × 2340, portrait, Samsung SM-S938U
|
||||
- States reviewed: system assistant compact overlay and expanded overlay over a non-Hermes app
|
||||
|
||||
@@ -146,18 +146,18 @@ final result: blocked
|
||||
|
||||
## Appearance customization and visual assets
|
||||
|
||||
- Selected reference: `C:\Users\Bailey\.codex\generated_images\019fe6f7-920d-7be1-b287-608a0bc2ff49\exec-facb08cb-3d8f-400a-b6ff-6f1a11a74d95.png`
|
||||
- Selected reference: `<session-generated-reference>`
|
||||
- Reference pixels: 852 x 1843.
|
||||
- Final real-screen captures:
|
||||
- `C:\Users\Bailey\.codex\worktrees\af0f\hermes-relay\app\build\store-shots\05_themes.png`
|
||||
- `C:\Users\Bailey\.codex\worktrees\af0f\hermes-relay\app\build\store-shots\05_theme_customizer.png`
|
||||
- `C:\Users\Bailey\.codex\worktrees\af0f\hermes-relay\app\build\store-shots\08_appearance.png`
|
||||
- `app/build/store-shots/05_themes.png`
|
||||
- `app/build/store-shots/05_theme_customizer.png`
|
||||
- `app/build/store-shots/08_appearance.png`
|
||||
- Implementation pixels: 1080 x 2160, portrait Robolectric/Roborazzi capture of the production Compose screen at its 360 dp Android viewport.
|
||||
- Normalization: the selected reference was scaled to 1080 px wide and cropped to the same 2160 px viewport for the full-view comparison. The reference's taller aspect ratio remains visible as an expected viewport difference; the focused customizer capture verifies the below-fold editor content.
|
||||
- Comparison evidence:
|
||||
- Initial full-view comparison: `C:\Users\Bailey\.codex\visualizations\2026\08\09\019fe6f7-920d-7be1-b287-608a0bc2ff49\appearance-reference-v-current.png`
|
||||
- Final normalized full-view comparison: `C:\Users\Bailey\.codex\visualizations\2026\08\09\019fe6f7-920d-7be1-b287-608a0bc2ff49\appearance-reference-v-current-2.png`
|
||||
- Focused customizer comparison: `C:\Users\Bailey\.codex\visualizations\2026\08\09\019fe6f7-920d-7be1-b287-608a0bc2ff49\appearance-customizer-reference-v-current.png`
|
||||
- Initial full-view comparison: `<session-visualization-artifact>`
|
||||
- Final normalized full-view comparison: `<session-visualization-artifact>`
|
||||
- Focused customizer comparison: `<session-visualization-artifact>`
|
||||
- State: Hermes Relay dark preset, customizer expanded. The focused capture expands the real control by click and scrolls its Shape row into view.
|
||||
|
||||
### Comparison history
|
||||
@@ -187,15 +187,15 @@ final result: passed
|
||||
|
||||
## Conversation voice dock
|
||||
|
||||
- Reference: `C:\Users\Bailey\.codex\generated_images\019fba42-1e93-78e1-9cd6-6919fb52d5bc\exec-89feab69-9caf-4084-b107-6bff43e511d6.png`
|
||||
- Reference: `<session-generated-reference>`
|
||||
- Implementation captures:
|
||||
- `C:\Users\Bailey\.codex\visualizations\2026\07\31\019fba42-1e93-78e1-9cd6-6919fb52d5bc\voice-ui-audit\implemented_conversation_final.png`
|
||||
- `C:\Users\Bailey\.codex\visualizations\2026\07\31\019fba42-1e93-78e1-9cd6-6919fb52d5bc\voice-ui-audit\conversation_refined_expanded.png`
|
||||
- `C:\Users\Bailey\.codex\visualizations\2026\07\31\019fba42-1e93-78e1-9cd6-6919fb52d5bc\voice-ui-audit\focus_final_expanded.png`
|
||||
- Combined comparison: `C:\Users\Bailey\.codex\visualizations\2026\07\31\019fba42-1e93-78e1-9cd6-6919fb52d5bc\voice-ui-audit\voice-dock-design-comparison-final.png`
|
||||
- Expanded before/after comparison: `C:\Users\Bailey\.codex\visualizations\2026\07\31\019fba42-1e93-78e1-9cd6-6919fb52d5bc\voice-ui-audit\voice-expanded-before-after.png`
|
||||
- Entry transition recording: `C:\Users\Bailey\.codex\visualizations\2026\07\31\019fba42-1e93-78e1-9cd6-6919fb52d5bc\voice-ui-audit\voice_entry_transition.mp4`
|
||||
- Entry transition frame sequence: `C:\Users\Bailey\.codex\visualizations\2026\07\31\019fba42-1e93-78e1-9cd6-6919fb52d5bc\voice-ui-audit\voice_entry_transition_frames.png`
|
||||
- `<session-visualization-artifact>`
|
||||
- `<session-visualization-artifact>`
|
||||
- `<session-visualization-artifact>`
|
||||
- Combined comparison: `<session-visualization-artifact>`
|
||||
- Expanded before/after comparison: `<session-visualization-artifact>`
|
||||
- Entry transition recording: `<session-visualization-artifact>`
|
||||
- Entry transition frame sequence: `<session-visualization-artifact>`
|
||||
- Reference size: 853 x 1844 px
|
||||
- Device viewport: 1080 x 2340, portrait, Samsung SM-S938U
|
||||
- States reviewed: collapsed idle dock, expanded Tap-mode controls, collapsed and expanded Focus header, Focus-to-Conversation transition
|
||||
@@ -229,8 +229,8 @@ copying the mockup's illustrative content.
|
||||
6. Compared the original and refined expanded Conversation and Focus states together; the final panels remove metadata fragmentation, header truncation, and avatar bleed-through.
|
||||
7. Recorded a persisted-Focus voice entry, inspected the 30 fps frame sequence, and verified that Conversation appears first through a continuous composer expansion before Focus is offered as an explicit action.
|
||||
8. Re-audited the installed Standard-mode drawer in both presentations. The final Conversation and Focus captures are:
|
||||
- `C:\Users\Bailey\.codex\visualizations\2026\07\31\019fba42-1e93-78e1-9cd6-6919fb52d5bc\voice-ui-audit-standard\21-final-expanded.png`
|
||||
- `C:\Users\Bailey\.codex\visualizations\2026\07\31\019fba42-1e93-78e1-9cd6-6919fb52d5bc\voice-ui-audit-standard\24-final-focus-expanded.png`
|
||||
- `<session-visualization-artifact>`
|
||||
- `<session-visualization-artifact>`
|
||||
The route summary is now two clearly separated lines (`Standard mode · Victor` and `xAI TTS · Leo`), with duplicate provider/model aliases removed and configuration provenance left to Voice Settings.
|
||||
9. Verified the Conversation long-press menu on-device in `22-final-speak-menu.png`: completed assistant messages expose Copy, Quote in reply, and Speak response without stacking Android's text-selection toolbar over the app menu.
|
||||
10. Verified the connection footer remains present under the Conversation composer. Focus remains the only in-app voice presentation that hides it.
|
||||
@@ -242,13 +242,13 @@ final result: passed
|
||||
|
||||
## System voice overlay redesign
|
||||
|
||||
- Selected reference: `C:\Users\Bailey\.codex\generated_images\019fba42-1e93-78e1-9cd6-6919fb52d5bc\exec-6a606b04-58c3-4a6d-b11b-cd25f99a047d.png`
|
||||
- Selected reference: `<session-generated-reference>`
|
||||
- Source concepts:
|
||||
- `C:\Users\Bailey\.codex\generated_images\019fba42-1e93-78e1-9cd6-6919fb52d5bc\exec-31a5512a-9cb7-455a-b111-d5797ab09e93.png`
|
||||
- `C:\Users\Bailey\.codex\generated_images\019fba42-1e93-78e1-9cd6-6919fb52d5bc\exec-bbfd616e-3847-4a2e-bbd0-65deb5e4e98c.png`
|
||||
- `<session-generated-reference>`
|
||||
- `<session-generated-reference>`
|
||||
- Baseline captures:
|
||||
- `C:\Users\Bailey\.codex\visualizations\2026\07\31\019fba42-1e93-78e1-9cd6-6919fb52d5bc\voice-ui-audit-standard\29-current-overlay-expanded.png`
|
||||
- `C:\Users\Bailey\.codex\visualizations\2026\07\31\019fba42-1e93-78e1-9cd6-6919fb52d5bc\voice-ui-audit-standard\30-current-overlay-expanded.png`
|
||||
- `<session-visualization-artifact>`
|
||||
- `<session-visualization-artifact>`
|
||||
- Device viewport: 1080 x 2340, portrait, Samsung SM-S938U
|
||||
- States to review: collapsed system overlay and expanded system overlay over a non-Hermes app
|
||||
|
||||
+4
-4
@@ -267,7 +267,7 @@ not require an API endpoint or API bearer when dashboard chat is ready.
|
||||
|
||||
### 12. Android as a Hermes Platform/Channel — "Threads" (Shipped 2026-06-28; unified-session model 2026-06-29)
|
||||
|
||||
> **Status (2026-08-12):** SHIPPED as the `phone` platform plugin (`plugin/phone_platform.py`) — registered via `ctx.register_platform` with **no fork** (the ~16-file upstream change sketched below was avoided; the original research predates the open plugin-platform registry). Two-way reply is device-verified. Agent-facing entry is `send_message target=phone` (the stale `target=mobile:<device_id>` syntax below is superseded); standalone cron delivery uses the registered sender, and the adapter publishes its canonical home destination through upstream's channel directory. Live cron certification remains tracked in TODO.md.
|
||||
> **Status (2026-08-12):** SHIPPED as the `phone` platform plugin (`plugin/phone_platform.py`) — registered via `ctx.register_platform` with **no fork** (the ~16-file upstream change sketched below was avoided; the original research predates the open plugin-platform registry). Two-way reply is device-verified. Agent-facing entry is `send_message target=phone` (the stale `target=mobile:<device_id>` syntax below is superseded); standalone cron delivery uses the registered sender, and the adapter publishes its canonical home destination through upstream's channel directory. Live cron certification remains tracked in docs/project/TODO.md.
|
||||
>
|
||||
> **Decision (2026-06-29) — unified-session "Threads", not a separate surface:** the proactive agent↔phone conversation is **not** a separate app lane/tab/segment. It is a **source-tagged session inside the one Chat surface** — a **Thread** (`source=phone`). The three things distinguishing a Thread from a normal gateway chat are *session properties*, not a separate UI: (a) the agent can initiate a turn, (b) it rides the relay `proactive` transport and is relay-gated, (c) it's a standing/named DM. **Scrollback = the gateway session store** (same read path Chat uses); **live receive = the relay `proactive` push** (→ notification); **send = `proactive.reply`**. The local `ProactiveInboxStore` is demoted to a live-push cache + outbox (no parallel history). The Thread capability is surfaced in the **connection best-path/capability UI** (a relay-tier capability, like terminal/bridge/voice) and as a clean **Threads** entry (thread-spool icon, NOT a phone glyph) pinned atop the session drawer when active — never a connection-wizard step. Degrades cleanly: no relay plugin → no `source=phone` sessions → Chat is unchanged (standard-path-safe). This **supersedes the earlier "separate Agent lane / 4th nav segment" sketch** and folds in the "show chat source/platform attribution in Chat" goal in one stroke.
|
||||
>
|
||||
@@ -3240,7 +3240,7 @@ escalation remains reserved and reports disabled. The optional driver is not
|
||||
bundled or updated by Hermes-Relay, and Hermes forces driver telemetry off for
|
||||
every child process it starts. The legacy engine remains the default and the
|
||||
fail-closed fallback while the live Windows acceptance and remaining scope,
|
||||
redaction, and grant-bridge hardening gates tracked in `TODO.md` stay open.
|
||||
redaction, and grant-bridge hardening gates tracked in `docs/project/TODO.md` stay open.
|
||||
|
||||
**Second-phase refinement (2026-08-13).** CUA is the preferred/default setting
|
||||
for new structured-control sessions; the original Windows input path is named
|
||||
@@ -3743,7 +3743,7 @@ the session, duplicate submission, wrong-session events, or an arbitrary timer.
|
||||
Normal terminal delivery is unchanged, queued turns retain their existing
|
||||
ownership, Relay remains optional, and unmodified upstream compatibility is
|
||||
preserved. Physical certification across the reported device/network matrix
|
||||
remains tracked in `TODO.md`.
|
||||
remains tracked in `docs/project/TODO.md`.
|
||||
|
||||
---
|
||||
|
||||
@@ -4118,7 +4118,7 @@ visible without mislabeling their parent turn. Older Gateways remain usable
|
||||
but show Unavailable when no exact local terminal truth exists. Declarative
|
||||
Gateway scenarios cover all four upstream states, complete-snapshot
|
||||
disappearance, client-side profile isolation, and method-not-found; physical
|
||||
and current-host certification remains tracked in `TODO.md`. An upstream
|
||||
and current-host certification remains tracked in `docs/project/TODO.md`. An upstream
|
||||
profile field/filter or explicitly owned aggregate activity route would remove
|
||||
the remaining ambiguity for multi-profile clients.
|
||||
|
||||
|
||||
+1
-1
@@ -513,7 +513,7 @@ reply completes. A reaction overlays whatever else would show (including
|
||||
### Forthcoming behavior (designed, not yet rendered)
|
||||
|
||||
These are specified so authors can plan, but the renderer doesn't drive them
|
||||
yet — they're tracked in `TODO.md`. Authoring the clips/flags now is harmless.
|
||||
yet — they're tracked in `docs/project/TODO.md`. Authoring the clips/flags now is harmless.
|
||||
|
||||
- **`attention` reaction** — a one-shot when a notification arrives. Reserved: it
|
||||
needs a host event the pet doesn't yet receive (unlike `greet`/`done`, which
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
> **Purpose.** Detailed implementation plan for the v0.4 bridge feature expansion wave. Each work unit here is self-contained enough that an agent can pick it up and execute independently, including per-unit Agent briefs, file lists, acceptance criteria, and reference-implementation pointers.
|
||||
>
|
||||
> **Why this file exists.** The high-level [`ROADMAP.md`](../../ROADMAP.md) at the repo root lists the milestones for this wave as brief bullets; this file is where the scoping detail lives. While this plan is active, it's the source of truth for the agent team. Once every unit here has shipped, the plan file gets archived or deleted and the shipped items live on in [`CHANGELOG.md`](../../CHANGELOG.md) and [`DEVLOG.md`](../../DEVLOG.md).
|
||||
> **Why this file exists.** The high-level [`docs/project/ROADMAP.md`](../../docs/project/ROADMAP.md) lists the milestones for this wave as brief bullets; this file is where the scoping detail lives. While this plan is active, it's the source of truth for the agent team. Once every unit here has shipped, the plan file gets archived or deleted and the shipped items live on in [`CHANGELOG.md`](../../CHANGELOG.md) and [`docs/project/DEVLOG.md`](../../docs/project/DEVLOG.md).
|
||||
>
|
||||
> **Origin.** Compiled 2026-04-13 from a comparison pass against [raulvidis/hermes-android](https://github.com/raulvidis/hermes-android) plus prior research. Scope covers bridge-channel tool expansion, reliability patterns, and one documentation/skill addition — deferred and research-horizon items live in [`ROADMAP.md`](../../ROADMAP.md), not here.
|
||||
> **Origin.** Compiled 2026-04-13 from a comparison pass against [raulvidis/hermes-android](https://github.com/raulvidis/hermes-android) plus prior research. Scope covers bridge-channel tool expansion, reliability patterns, and one documentation/skill addition — deferred and research-horizon items live in [`docs/project/ROADMAP.md`](../../docs/project/ROADMAP.md), not here.
|
||||
>
|
||||
> **Related files.**
|
||||
> - [`ROADMAP.md`](../../ROADMAP.md) — milestone-level view of where this plan sits in the broader arc
|
||||
> - [`docs/project/ROADMAP.md`](../../docs/project/ROADMAP.md) — milestone-level view of where this plan sits in the broader arc
|
||||
> - [`CHANGELOG.md`](../../CHANGELOG.md) — cumulative release history
|
||||
> - [`DEVLOG.md`](../../DEVLOG.md) — session-by-session narrative log
|
||||
> - [`docs/project/DEVLOG.md`](../../docs/project/DEVLOG.md) — session-by-session narrative log
|
||||
> - [`CLAUDE.md`](../../CLAUDE.md) — project conventions every implementing agent should read first
|
||||
> - [`docs/spec.md`](../spec.md) — formal architecture spec
|
||||
> - [`docs/decisions.md`](../decisions.md) — architecture decision records (ADRs)
|
||||
@@ -30,7 +30,7 @@
|
||||
| **P** | Architectural pattern / reliability improvement, not a new tool. |
|
||||
| **Doc** | Documentation surface change. |
|
||||
|
||||
Longer-term / research / aspirational items live in [`ROADMAP.md`](../../ROADMAP.md), not in this plan.
|
||||
Longer-term / research / aspirational items live in [`docs/project/ROADMAP.md`](../../docs/project/ROADMAP.md), not in this plan.
|
||||
|
||||
**Effort sizing** (scope, not duration): **S** = trivial single-file change, **M** = multi-file change touching 2–4 layers, **L** = new subsystem or cross-cutting work.
|
||||
|
||||
|
||||
@@ -9,16 +9,16 @@
|
||||
> **Related files.**
|
||||
> - [`CLAUDE.md`](../../CLAUDE.md) — project conventions every implementing agent reads first
|
||||
> - [`docs/spec.md`](../spec.md) — protocol / voice surface reference
|
||||
> - [`ROADMAP.md`](../../ROADMAP.md) — where this pass sits in the broader arc
|
||||
> - [`docs/project/ROADMAP.md`](../../docs/project/ROADMAP.md) — where this pass sits in the broader arc
|
||||
> - [`docs/plans/2026-04-13-bridge-feature-expansion.md`](./2026-04-13-bridge-feature-expansion.md) — precedent for plan-file format
|
||||
> - [`DEVLOG.md`](../../DEVLOG.md) — append session entry on completion
|
||||
> - [`docs/project/DEVLOG.md`](../../docs/project/DEVLOG.md) — append session entry on completion
|
||||
> - Upstream reference: `~/.hermes/hermes-agent/tools/tts_tool.py` on hermes-host (`you@hermes-host`)
|
||||
|
||||
## How to use this file
|
||||
|
||||
1. **Bailey:** walk each work unit, mark status checkbox (`[x] Now` / `[x] Next` / `[x] Later` / `[x] Skip`). Leave inline notes to override scope.
|
||||
2. **Orchestrator agent:** creates the worktree + branch per [Worktree setup](#worktree-setup), then dispatches work units per the [Sequencing](#sequencing--parallelism) plan. The orchestrator owns the working tree; subagents are given narrow, self-contained tasks and asked to return diffs or land commits on the shared branch.
|
||||
3. **Session end:** run acceptance checklist, update `DEVLOG.md` + `CHANGELOG.md`, open one PR for the whole branch with all unit IDs in the body.
|
||||
3. **Session end:** run acceptance checklist, update `docs/project/DEVLOG.md` + `CHANGELOG.md`, open one PR for the whole branch with all unit IDs in the body.
|
||||
|
||||
## Worktree setup
|
||||
|
||||
@@ -56,7 +56,7 @@ cd ../hermes-android-voice
|
||||
| **Wave 2** | V2 | Serial | Extends `VoiceViewModel.stripMarkdown()` → must land before V3 because V3's coalesce logic runs against sanitized text. |
|
||||
| **Wave 3** | V3 | Serial | Chunking changes to `VoiceViewModel.kt` — conflicts with V4. |
|
||||
| **Wave 4** | V4 | Serial | Pipelining rewrite of `VoiceViewModel.startTtsConsumer()` — takes the output of V3's chunker as input. |
|
||||
| **Wave 5** | Doc1 | Serial | `DEVLOG.md` + `CHANGELOG.md` + `user-docs/` updates after code stabilizes. |
|
||||
| **Wave 5** | Doc1 | Serial | `docs/project/DEVLOG.md` + `CHANGELOG.md` + `user-docs/` updates after code stabilizes. |
|
||||
|
||||
**Shared-file hot-spot.** `VoiceViewModel.kt` is touched by V2, V3, and V4. These **must** serialize — do not parallelize them. The orchestrator should handle them in sequence (V2→V3→V4) as three commits from one agent session, not three concurrent subagents.
|
||||
|
||||
@@ -341,14 +341,14 @@ cd ../hermes-android-voice
|
||||
**Summary.** Capture the wave in the append-only log, bump CHANGELOG with an `[Unreleased]` entry, refresh user-docs voice-mode troubleshooting, update spec if the TTS pipeline section exists.
|
||||
|
||||
**Scope / Acceptance criteria.**
|
||||
- `DEVLOG.md`: append a 2026-04-16 session entry summarizing what shipped and the diagnosis chain that motivated it.
|
||||
- `docs/project/DEVLOG.md`: append a 2026-04-16 session entry summarizing what shipped and the diagnosis chain that motivated it.
|
||||
- `CHANGELOG.md`: `[Unreleased] — Changed` entry: "Voice output quality — switched to ElevenLabs flash streaming model, added client+relay text sanitization, coalesced short sentences, prefetched next sentence during playback, and swapped to ExoPlayer for gapless concatenation." Use conventional-changelog tone.
|
||||
- `user-docs/`: if there's a voice-mode page, add a "What changed in voice mode" note. If not, don't create one just for this.
|
||||
- `docs/spec.md`: if there's a voice-pipeline section, update the flow diagram or prose to reflect the prefetch + gapless architecture.
|
||||
- No entry in `ROADMAP.md` — the wave is complete, not milestoned.
|
||||
- No entry in `docs/project/ROADMAP.md` — the wave is complete, not milestoned.
|
||||
|
||||
**Files to touch.**
|
||||
- `DEVLOG.md`
|
||||
- `docs/project/DEVLOG.md`
|
||||
- `CHANGELOG.md`
|
||||
- `user-docs/*` (conditional)
|
||||
- `docs/spec.md` (conditional)
|
||||
|
||||
@@ -278,13 +278,13 @@
|
||||
**Summary.** Capture the wave. Unlike the voice-quality-pass docs pass, this one DOES update `user-docs/features/voice.md` because barge-in is a user-facing feature with a settings UI they need to discover.
|
||||
|
||||
**Scope.**
|
||||
- `DEVLOG.md`: append 2026-04-17 entry (second of the day) summarizing the barge-in stack.
|
||||
- `docs/project/DEVLOG.md`: append 2026-04-17 entry (second of the day) summarizing the barge-in stack.
|
||||
- `CHANGELOG.md`: add to `[Unreleased]` under an `### Added — Barge-in` section.
|
||||
- `docs/spec.md` Phase V section: reference the new barge-in architecture (duplex audio, VAD, AEC, resume).
|
||||
- `user-docs/features/voice.md`: add a new "## Barge-in (interrupt the agent)" section with screenshot placeholder, settings description, device compatibility note.
|
||||
|
||||
**Files to touch.**
|
||||
- `DEVLOG.md`, `CHANGELOG.md`, `docs/spec.md`, `user-docs/features/voice.md`.
|
||||
- `docs/project/DEVLOG.md`, `CHANGELOG.md`, `docs/spec.md`, `user-docs/features/voice.md`.
|
||||
|
||||
**Dependencies.** All B units committed.
|
||||
|
||||
|
||||
@@ -310,7 +310,7 @@ Add option (A) to R3's acceptance criteria: `handle_sessions_list` gains a loopb
|
||||
|
||||
**Root-level:**
|
||||
- `CHANGELOG.md` — new `[Unreleased]` entry under `### Added`: "Dashboard plugin with four tabs: Relay Management, Bridge Activity, Push Console (stub), Media Inspector" + brief bullet list of the three new relay routes.
|
||||
- `DEVLOG.md` — session entry for 2026-04-18 dashboard plugin work: Context, Decision summary, Implementation notes (one-liner per wave), Deferred (push console needs FCM).
|
||||
- `docs/project/DEVLOG.md` — session entry for 2026-04-18 dashboard plugin work: Context, Decision summary, Implementation notes (one-liner per wave), Deferred (push console needs FCM).
|
||||
- `README.md` — add one line under Quick Start mentioning the dashboard tab becomes available after gateway restart.
|
||||
- `CLAUDE.md` — add `plugin/dashboard/` to Repository Layout; add four Key Files entries for the dashboard plugin (manifest.json, plugin_api.py, src/index.jsx, dist/index.js one-liners).
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ Confirm exact invocation by reading `hermes_cli/main.py:1034` area (agent will d
|
||||
### Phase 4 — Polish + docs *(post-smoke)*
|
||||
- Update `~/.hermes/hermes-relay/README.md` with desktop install section.
|
||||
- Update hermes-relay `CHANGELOG.md` `[Unreleased]`.
|
||||
- Update hermes-relay `DEVLOG.md` with session summary.
|
||||
- Update hermes-relay `docs/project/DEVLOG.md` with session summary.
|
||||
- Bump version via `scripts/bump-version.sh 0.8.0-alpha`.
|
||||
- User-docs page in `user-docs/guide/desktop.md`.
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
## Integration sequence
|
||||
|
||||
1. Update ROADMAP.md with the alpha.6 scope + deferred items.
|
||||
1. Update docs/project/ROADMAP.md with the alpha.6 scope + deferred items.
|
||||
2. Launch 6 parallel agents (A–F) with isolated file ownership.
|
||||
3. I integrate cli.ts + desktop_tool.py after all agents report.
|
||||
4. Expand `npm run smoke` to cover new subcommands.
|
||||
|
||||
@@ -262,7 +262,7 @@ Tool calls must appear live without leaving voice mode.
|
||||
### Wave 7 - Documentation and operator guidance
|
||||
|
||||
- Update `user-docs/features/voice.md`.
|
||||
- Update `TODO.md` to mark the realtime-agent TODO as planned/linked.
|
||||
- Update `docs/project/TODO.md` to mark the realtime-agent TODO as planned/linked.
|
||||
- Add troubleshooting for auth/session binding, provider disconnect fallback, and why tools still run through Hermes.
|
||||
- Add DEVLOG entry after implementation lands.
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ Design target:
|
||||
data, side effects, and durable transcript state
|
||||
- avoid hard-coding OpenAI WebRTC details into Android voice UX or broker core
|
||||
|
||||
This is tracked in `TODO.md` under **Pluggable Realtime Agent media
|
||||
This is tracked in `docs/project/TODO.md` under **Pluggable Realtime Agent media
|
||||
transports**.
|
||||
|
||||
### 3. Map OpenAI Wire Events to Normalized Events
|
||||
|
||||
@@ -143,7 +143,7 @@ Owns: `plugin/dashboard/**`.
|
||||
|
||||
### Coordinator — docs (this doc + the rest)
|
||||
`docs/plans/2026-06-20-structured-media-channel.md` (Q3 plan — design only, not built here),
|
||||
`docs/decisions.md` entry, `TODO.md` follow-ups + retirement note, `DEVLOG.md`, `CHANGELOG`.
|
||||
`docs/decisions.md` entry, `docs/project/TODO.md` follow-ups + retirement note, `docs/project/DEVLOG.md`, `CHANGELOG`.
|
||||
|
||||
---
|
||||
|
||||
@@ -154,4 +154,4 @@ Owns: `plugin/dashboard/**`.
|
||||
unchanged; with the seam patched out / absent, no exception reaches a turn.
|
||||
- Clean UI/UX: the transport badge + ladder read clearly; the injected-context audit shows the
|
||||
exact server-side block.
|
||||
- Docs updated; retirement tracked in `TODO.md`.
|
||||
- Docs updated; retirement tracked in `docs/project/TODO.md`.
|
||||
|
||||
@@ -135,7 +135,7 @@ A small bottom sheet that is the single place the per-surface truth + the explai
|
||||
|
||||
The **plugin secure proxy** (the "Secure proxy — Not advertised" row) is a **stub today**: the Android side models it (`Endpoint.kt` `ProxyEndpoint`, `plugin_proxy` role, `hasSecureProxy()`), and `isEncryptedOverlayRoute()` already treats it as encrypted — but **the relay has no proxy-forward implementation, pairing never emits a `plugin_proxy` candidate, and no cert/pin is generated.** Enabling it end-to-end is the unbuilt **Phase 4** of `2026-06-18-native-secure-routes.md` (relay HTTP-forward routes + `RELAY_SSL_*` cert + pairing emission; ~2–3 wk).
|
||||
|
||||
**Implication for this plan:** the indicator must **not block** on the proxy. We design the wording/placement so that *when* a `plugin_proxy` route is advertised it slots in as a 🔒 **TLS (pinned)** route automatically (it already would, via `isEncryptedOverlayRoute`). Until then it stays honestly "Not advertised." Recommend a separate spike to stand it up + test on the server (tracked in `TODO.md`), independent of this UX work.
|
||||
**Implication for this plan:** the indicator must **not block** on the proxy. We design the wording/placement so that *when* a `plugin_proxy` route is advertised it slots in as a 🔒 **TLS (pinned)** route automatically (it already would, via `isEncryptedOverlayRoute`). Until then it stays honestly "Not advertised." Recommend a separate spike to stand it up + test on the server (tracked in `docs/project/TODO.md`), independent of this UX work.
|
||||
|
||||
---
|
||||
|
||||
@@ -187,7 +187,7 @@ New bottom sheet; per-surface rows + explainer + TOFU/keystore lines + docs link
|
||||
New user-docs page + the four conflation edits + TOFU documentation.
|
||||
|
||||
### Spike — stand up & test the plugin secure proxy · L (separate, not blocking)
|
||||
Phase 4 of `2026-06-18-native-secure-routes.md`. Tracked in `TODO.md`.
|
||||
Phase 4 of `2026-06-18-native-secure-routes.md`. Tracked in `docs/project/TODO.md`.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Triage of all 13 open GitHub issues (multi-agent code-verified pass + adversarial
|
||||
cross-check), grouped into workstreams that land on `dev` via worktree feature
|
||||
branches before the next releases. Owner-only actions (GitHub comments/closures,
|
||||
labels, Play Console, on-device checks) are tracked in `TODO.md` — automation
|
||||
labels, Play Console, on-device checks) are tracked in `docs/project/TODO.md` — automation
|
||||
never posts to GitHub on the owner's behalf.
|
||||
|
||||
## Verdict summary
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Research snapshot mapping OpenAI's realtime voice offering (as of July 2026)
|
||||
onto the hermes-relay realtime agent, to scope next-release-candidate work.
|
||||
Companion TODO items live under "OpenAI realtime provider — next-RC roadmap"
|
||||
in `TODO.md`.
|
||||
in `docs/project/TODO.md`.
|
||||
|
||||
## Repo starting point
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ as a collaborator. This continues that pattern.
|
||||
Run `./gradlew lint` once before the PR.
|
||||
(Use `--no-daemon`; never pipe gradle through `tail` — it masks the exit code.)
|
||||
- **Conventional Commits, one commit per extracted controller.** `--no-ff` PR into
|
||||
`dev` at the end. Update `DEVLOG.md`.
|
||||
`dev` at the end. Update `docs/project/DEVLOG.md`.
|
||||
- **If a cluster is too entangled** to extract without logic changes, STOP, leave it
|
||||
in place, and report — open the PR with the completed steps rather than forcing it.
|
||||
|
||||
@@ -111,7 +111,7 @@ change, defer it and report** — Steps 1–4 stand on their own.
|
||||
`ProfileController` extracted (Step 5 optional).
|
||||
- `compileSideloadDebugKotlin` + `compileSideloadDebugUnitTestKotlin` green; focused
|
||||
slice passes; `./gradlew lint` clean; `ArchitectureBoundaryTest` green.
|
||||
- `DEVLOG.md` updated. One PR (`feature/connectionviewmodel-decomposition` → `dev`,
|
||||
- `docs/project/DEVLOG.md` updated. One PR (`feature/connectionviewmodel-decomposition` → `dev`,
|
||||
`--no-ff`). Worktree removed.
|
||||
- **Report:** `ConnectionViewModel` line-count before/after, what moved where, any
|
||||
cluster left in place + why, and any deferred cleanups noted.
|
||||
|
||||
@@ -102,7 +102,7 @@ Advanced users can narrow or extend this through `~/.hermes/desktop-control.json
|
||||
### Phase 0 — Research Pack + Tech Decision (Ready Now)
|
||||
- Port this enhanced plan into repo `docs/plans/`.
|
||||
- Add ADR for Tauri choice + CLI fallback.
|
||||
- Update `ROADMAP.md` and `desktop/README.md`.
|
||||
- Update `docs/project/ROADMAP.md` and `desktop/README.md`.
|
||||
- Define Easy/Standard/Advanced tiers and default blocklist.
|
||||
|
||||
### Phase 1 — Tool Schema + Server Registration
|
||||
@@ -182,6 +182,6 @@ Do not ship until the user can instantly understand from the UI whether Hermes i
|
||||
|
||||
**Brief goal prompt for Codex (copy-paste ready):**
|
||||
|
||||
"Read the enhanced plan at docs/plans/desktop-control-computer-use-enhanced.md. Start by completing Phase 0: port the enhancements into the repo, add the Tauri decision ADR, and update ROADMAP.md. Then implement Phase 1 tool schemas while ensuring full backward compatibility with the existing desktop CLI. Focus on keeping the CLI as the primary surface and Tauri as the optional polished tray/overlay experience. Make the default pairing flow seamless for Easy-tier users."
|
||||
"Read the enhanced plan at docs/plans/desktop-control-computer-use-enhanced.md. Start by completing Phase 0: port the enhancements into the repo, add the Tauri decision ADR, and update docs/project/ROADMAP.md. Then implement Phase 1 tool schemas while ensuring full backward compatibility with the existing desktop CLI. Focus on keeping the CLI as the primary surface and Tauri as the optional polished tray/overlay experience. Make the default pairing flow seamless for Easy-tier users."
|
||||
|
||||
**Current pairing/settings parity goal prompt:** use `docs/plans/2026-05-17-desktop-android-pairing-parity.md` instead for the next tray UI pass.
|
||||
|
||||
@@ -14,7 +14,7 @@ contract test (Plan C).
|
||||
## Working rules
|
||||
|
||||
- One branch off `dev`: `feature/upstream-relay-isolation`. Conventional Commits, one logical
|
||||
commit per step. `--no-ff` PR into `dev` at the end. Update `DEVLOG.md`.
|
||||
commit per step. `--no-ff` PR into `dev` at the end. Update `docs/project/DEVLOG.md`.
|
||||
- Do **NOT** run a full gradle assemble or `adb install` (on-device builds are Bailey's via
|
||||
Android Studio). DO verify with `./gradlew lint` and focused unit tests.
|
||||
- If the real code contradicts this plan, **stop and report** rather than guessing.
|
||||
@@ -85,7 +85,7 @@ renamed/removed routes, misses only runtime-auth regressions. Note the tradeoff
|
||||
|
||||
## Acceptance
|
||||
|
||||
- ADR in `docs/decisions.md`; `DEVLOG.md` updated.
|
||||
- ADR in `docs/decisions.md`; `docs/project/DEVLOG.md` updated.
|
||||
- `network/` split into `upstream|relay|shared`; all imports updated; `./gradlew lint` clean.
|
||||
- `ArchitectureBoundaryTest` exists, is in the CI explicit `--tests` list, and passes.
|
||||
- Contract job exists, runs without the bootstrap, asserts route existence on pinned vanilla
|
||||
|
||||
@@ -4227,7 +4227,7 @@ Expected new keyless cold start: client ~+1–2s after first DataStore emission,
|
||||
|
||||
## 2026-05-19 — Experimental Realtime Hermes Voice Agent
|
||||
|
||||
**Plan.** [docs/plans/2026-05-19-realtime-hermes-voice-agent.md](docs/plans/2026-05-19-realtime-hermes-voice-agent.md) — add a switchable Android voice engine that brokers a realtime provider session (OpenAI first, xAI ready) while keeping Hermes as authority for profiles, sessions, memory, tool execution, Android bridge safety, confirmations, and cancellation. Stable `Hermes chat + voice output` remains the default and is untouched.
|
||||
**Plan.** [`2026-05-19-realtime-hermes-voice-agent.md`](../plans/2026-05-19-realtime-hermes-voice-agent.md) — add a switchable Android voice engine that brokers a realtime provider session (OpenAI first, xAI ready) while keeping Hermes as authority for profiles, sessions, memory, tool execution, Android bridge safety, confirmations, and cancellation. Stable `Hermes chat + voice output` remains the default and is untouched.
|
||||
|
||||
**Surface added.**
|
||||
|
||||
@@ -4384,7 +4384,7 @@ Post-fix smoke: Victor called `desktop_terminal("hostname")` → returned `{"std
|
||||
|
||||
## 2026-04-23 — Desktop CLI thin-client v0.1 (`@hermes-relay/cli`)
|
||||
|
||||
**Context.** The broader ask from the vault's [Desktop Client.md](../../../SynologyDrive/-Vault-/Axiom-Vault/3.%20System/Projects/Hermes-Relay/Desktop%20Client.md) decomposes into two independent pieces: (A) "one Node binary with CLI + TUI modes that talks to a remote Hermes over WSS" and (B) "per-tool dispatch routing so local tools run on the client while the brain stays on the server." This session ships **A** — with CLI mode specifically — and defers B to a separate hermes-agent PR on `fork/tool-relay`. The two are decoupled: the CLI consumes the existing `tui` WSS channel and `tui_gateway` subprocess shape without any server-side change.
|
||||
**Context.** An earlier private design note decomposed the desktop-client work into two independent pieces: (A) "one Node binary with CLI + TUI modes that talks to a remote Hermes over WSS" and (B) "per-tool dispatch routing so local tools run on the client while the brain stays on the server." This session ships **A** — with CLI mode specifically — and defers B to a separate hermes-agent PR on `fork/tool-relay`. The two are decoupled: the CLI consumes the existing `tui` WSS channel and `tui_gateway` subprocess shape without any server-side change.
|
||||
|
||||
### Architecture decision — same channel, different renderer
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# Project records
|
||||
|
||||
Public project-planning and engineering records live here so the repository
|
||||
root stays focused on entrypoints, build metadata, and release contracts.
|
||||
|
||||
- [`TODO.md`](TODO.md) — the canonical home for deferred work and known gaps.
|
||||
- [`ROADMAP.md`](ROADMAP.md) — high-level product and release direction.
|
||||
- [`DEVLOG.md`](DEVLOG.md) — factual engineering history and verification notes.
|
||||
|
||||
Keep these files depersonalized and public-safe. User-facing release history
|
||||
continues to live in the root [`CHANGELOG.md`](../../CHANGELOG.md).
|
||||
@@ -1,6 +1,6 @@
|
||||
# Hermes-Relay Roadmap
|
||||
|
||||
> Where Hermes-Relay is headed. Short, high-level, grouped by release milestone. For detailed implementation plans of active work see [`docs/plans/`](docs/plans/); for shipped work see [`CHANGELOG.md`](CHANGELOG.md); for the session-by-session narrative see [`DEVLOG.md`](DEVLOG.md).
|
||||
> Where Hermes-Relay is headed. Short, high-level, grouped by release milestone. For detailed implementation plans of active work see [`docs/plans/`](../plans/); for shipped work see [`CHANGELOG.md`](../../CHANGELOG.md); for the session-by-session narrative see [`DEVLOG.md`](DEVLOG.md).
|
||||
|
||||
## Vision
|
||||
|
||||
@@ -8,29 +8,29 @@ Native Android companion for the [Hermes agent platform](https://github.com/Nous
|
||||
|
||||
## Shipped
|
||||
|
||||
- **v0.3.0** — Bridge channel (sideload), voice mode, notification companion, two build flavors, full safety rails system. [CHANGELOG](CHANGELOG.md#030---2026-04-13)
|
||||
- **v0.2.0** — Voice mode foundation, terminal preview, TOFU cert pinning, Paired Devices screen. [CHANGELOG](CHANGELOG.md)
|
||||
- **v0.3.0** — Bridge channel (sideload), voice mode, notification companion, two build flavors, full safety rails system. [CHANGELOG](../../CHANGELOG.md#030---2026-04-13)
|
||||
- **v0.2.0** — Voice mode foundation, terminal preview, TOFU cert pinning, Paired Devices screen. [CHANGELOG](../../CHANGELOG.md)
|
||||
- **v0.1.0** — Chat, sessions, QR pairing, encrypted storage, Play Store submission.
|
||||
|
||||
### Desktop track (parallel lane to Android) — **experimental**
|
||||
|
||||
Release tags: `cli-v*` (separate cadence from Android `android-v*` and Plugin `plugin-v*`). Historical alpha prereleases used `desktop-v*`, and the installer/updater keep a migration fallback. Curl-installed prebuilt binaries (no Node required); Windows first, macOS / Linux same release. Workflows: [`ci-desktop.yml`](.github/workflows/ci-desktop.yml) + [`release-cli.yml`](.github/workflows/release-cli.yml).
|
||||
Release tags: `cli-v*` (separate cadence from Android `android-v*` and Plugin `plugin-v*`). Historical alpha prereleases used `desktop-v*`, and the installer/updater keep a migration fallback. Curl-installed prebuilt binaries (no Node required); Windows first, macOS / Linux same release. Workflows: [`ci-desktop.yml`](../../.github/workflows/ci-desktop.yml) + [`release-cli.yml`](../../.github/workflows/release-cli.yml).
|
||||
|
||||
**Shipped (2026-04-23 — first tagged release `desktop-v0.3.0-alpha.1`):**
|
||||
|
||||
- **`@hermes-relay/cli` v0.1** — Node thin-client at [`desktop/`](desktop/). Remote chat + pair + status + tools subcommands over the relay's `tui` WSS channel. Shares `~/.hermes/remote-sessions.json` with the Android client (pair once, both work).
|
||||
- **`@hermes-relay/cli` v0.1** — Node thin-client at [`desktop/`](../../desktop/). Remote chat + pair + status + tools subcommands over the relay's `tui` WSS channel. Shares `~/.hermes/remote-sessions.json` with the Android client (pair once, both work).
|
||||
- **v0.2 — resilience + pairing UX** — multi-endpoint pairing (ADR 24: `--pair-qr` probes LAN/Tailscale/Public, strict-priority within-tier race, 4s timeout, 60s cache), reconnect-on-drop state machine (1s→30s exp backoff, 5min on 429, gate re-check post-sleep), TOFU cert pinning via pre-WS TLS probe (SPKI sha256, `sha256/<base64>` OkHttp-compatible).
|
||||
- **v0.2 — UX polish** — bare `hermes-relay` → `shell` (full Hermes CLI over PTY with `clear; exec hermes` after tmux settles); contextual connect banner (`Connected via LAN (plain) — server 0.6.0`); `status` surfaces grants + TTL + endpoint role from `auth.ok`; new `devices` subcommand talking to relay `GET/DELETE/PATCH /sessions` over HTTP.
|
||||
- **Phase B — client-side tool routing** — server-side `plugin/relay/channels/desktop.py` + `plugin/tools/desktop_tool.py` register `desktop_read_file` / `_write_file` / `_terminal` / `_search_files` / `_patch` via `tools.registry` (mirror of `android_*` pattern — **zero hermes-agent core change**). Client-side `DesktopToolRouter` attaches to the `desktop` channel, dispatches under a 30s AbortController, heartbeats `desktop.status` every 30s. One-time per-URL consent gate + `--no-tools` kill-switch.
|
||||
- **`hermes-relay daemon`** — headless WSS + tool router that keeps desktop tools serving without a visible shell. Fails closed on missing stored consent (`--allow-tools` escape hatch with an explicit `--token`). JSON-line logs by default, auto-human on TTY. Inherits transport's reconnect state machine; `setImmediate(exit)` to flush final log line before process dies.
|
||||
- **Pre-release hardening** — `hermes-relay doctor` (local diagnostic report, human + `--json`, no token leakage); `uninstall.{sh,ps1}` (3-tier: default keeps session store, `--purge` wipes it with cross-surface warning, `--service` stub); interactive first-run prompts (`resolveFirstRunUrl` — auto-picks single stored session, numbered picker for multiple, welcome banner for fresh install); version-aware install (`upgrading X → Y` readback pre-install, post-install confirmation).
|
||||
- **Self-setup skill** — [`skills/devops/hermes-relay-desktop-setup/SKILL.md`](skills/devops/hermes-relay-desktop-setup/SKILL.md) lets any Hermes agent install, pair, and troubleshoot the CLI with **live local diagnostics** via `desktop_terminal` (can read the user's Node version, PATH, binary location directly — something the Android setup skill can't match).
|
||||
- **Self-setup skill** — [`skills/devops/hermes-relay-desktop-setup/SKILL.md`](../../skills/devops/hermes-relay-desktop-setup/SKILL.md) lets any Hermes agent install, pair, and troubleshoot the CLI with **live local diagnostics** via `desktop_terminal` (can read the user's Node version, PATH, binary location directly — something the Android setup skill can't match).
|
||||
|
||||
**Shipped — `desktop-v0.3.0-alpha.6` (seamless-local dev pass, done 2026-04-23):** Plan at [`docs/plans/2026-04-23-desktop-alpha-6-seamless-local.md`](docs/plans/2026-04-23-desktop-alpha-6-seamless-local.md). Nine features across six parallel agent workstreams, all opt-in: workspace-awareness envelope + active-editor signal (#1+#8), `hermes-relay update` self-update subcommand (#2), `desktop_open_in_editor` tool + interactive patch approval with unified-diff rendering (#3+#4), conversation picker on connect (#5), clipboard bridge + screenshot handlers (#9+#12), and a `hermes` alias so muscle-memory works without the `-relay` suffix (#13). Integration day: 2026-04-23.
|
||||
**Shipped — `desktop-v0.3.0-alpha.6` (seamless-local dev pass, done 2026-04-23):** Plan at [`docs/plans/2026-04-23-desktop-alpha-6-seamless-local.md`](../plans/2026-04-23-desktop-alpha-6-seamless-local.md). Nine features across six parallel agent workstreams, all opt-in: workspace-awareness envelope + active-editor signal (#1+#8), `hermes-relay update` self-update subcommand (#2), `desktop_open_in_editor` tool + interactive patch approval with unified-diff rendering (#3+#4), conversation picker on connect (#5), clipboard bridge + screenshot handlers (#9+#12), and a `hermes` alias so muscle-memory works without the `-relay` suffix (#13). Integration day: 2026-04-23.
|
||||
|
||||
**Active — `desktop-v0.3.0-alpha.7` (native image paste):** Plan at [`docs/plans/2026-04-23-desktop-alpha-7-native-paste.md`](docs/plans/2026-04-23-desktop-alpha-7-native-paste.md). Two-repo workstream: client slash commands `/paste` (clipboard), `/screenshot` (primary display), `/image <path>` (file) land in `hermes-relay chat`, each echoes a one-line feedback and attaches the image to the next `prompt.submit` so the vision-capable model sees it in the same turn — parity with Claude Desktop's paste UX minus OS-level Ctrl+V (terminals don't pipe image bytes to stdin). Client half is new `desktop/src/chatAttach.ts` + slash-command branches in `desktop/src/commands/chat.ts`. Server half is ONE new `@method("image.attach.bytes")` on the fork's `tui_gateway/server.py` (branch `feat/image-attach-bytes` → merged to `axiom`); the fork's existing `_enrich_with_attached_images` already handles multimodal payload plumbing and session-scoped image state, so this release is almost entirely about bridging client-captured bytes to server-side state that's been there for months. Relay channel unchanged — `tui` is a transparent RPC forwarder. Graceful fallback when hermes-host hasn't been updated yet: client catches `method not found`, prints a pointer at the axiom rollout, REPL stays alive.
|
||||
**Active — `desktop-v0.3.0-alpha.7` (native image paste):** Plan at [`docs/plans/2026-04-23-desktop-alpha-7-native-paste.md`](../plans/2026-04-23-desktop-alpha-7-native-paste.md). Two-repo workstream: client slash commands `/paste` (clipboard), `/screenshot` (primary display), `/image <path>` (file) land in `hermes-relay chat`, each echoes a one-line feedback and attaches the image to the next `prompt.submit` so the vision-capable model sees it in the same turn — parity with Claude Desktop's paste UX minus OS-level Ctrl+V (terminals don't pipe image bytes to stdin). Client half is new `desktop/src/chatAttach.ts` + slash-command branches in `desktop/src/commands/chat.ts`. Server half is ONE new `@method("image.attach.bytes")` on the fork's `tui_gateway/server.py` (branch `feat/image-attach-bytes` → merged to `axiom`); the fork's existing `_enrich_with_attached_images` already handles multimodal payload plumbing and session-scoped image state, so this release is almost entirely about bridging client-captured bytes to server-side state that's been there for months. Relay channel unchanged — `tui` is a transparent RPC forwarder. Graceful fallback when hermes-host hasn't been updated yet: client catches `method not found`, prints a pointer at the axiom rollout, REPL stays alive.
|
||||
|
||||
**Active — desktop control / computer-use:** Enhanced plan at [`docs/plans/desktop-control-computer-use-enhanced.md`](docs/plans/desktop-control-computer-use-enhanced.md); earlier MVP implementation record at [`docs/plans/desktop-computer-use-mvp.md`](docs/plans/desktop-computer-use-mvp.md). Windows now has the first Tauri tray/overlay app as the primary Easy/Standard install surface: pair, start/pause daemon, Devices/Revoke, Task Log, Settings, overlay status chip, emergency stop, and bundled CLI sidecar. The existing CLI and daemon remain the primary advanced/headless surface. `desktop_computer_*` schemas are registered on the normal desktop tool channel but advertised only behind the explicit experimental computer-use flag. Host input still requires desktop-tool consent plus a visible, task-scoped assist/control grant; there is no unrestricted or silent mouse/keyboard automation.
|
||||
**Active — desktop control / computer-use:** Enhanced plan at [`docs/plans/desktop-control-computer-use-enhanced.md`](../plans/desktop-control-computer-use-enhanced.md); earlier MVP implementation record at [`docs/plans/desktop-computer-use-mvp.md`](../plans/desktop-computer-use-mvp.md). Windows now has the first Tauri tray/overlay app as the primary Easy/Standard install surface: pair, start/pause daemon, Devices/Revoke, Task Log, Settings, overlay status chip, emergency stop, and bundled CLI sidecar. The existing CLI and daemon remain the primary advanced/headless surface. `desktop_computer_*` schemas are registered on the normal desktop tool channel but advertised only behind the explicit experimental computer-use flag. Host input still requires desktop-tool consent plus a visible, task-scoped assist/control grant; there is no unrestricted or silent mouse/keyboard automation.
|
||||
|
||||
**Desktop control UX direction:** Tauri v2 (Rust + static web UI) is the native shell for the polished Easy-tier experience: tray icon, always-visible overlay chip, task log, settings, and one-click pause/emergency stop. Easy tier pairs once, shows a connected/observing chip, and exposes Devices / Revoke / Task Log / Settings / Emergency Stop from the tray. Standard tier adds full tray management; Advanced tier remains CLI + daemon + JSON policy (`~/.hermes/desktop-control.json`) for operators. The default policy baseline blocks password managers, credential prompts, banking/payment/crypto surfaces, OS security/admin settings, and private-key/token material until locally overridden.
|
||||
|
||||
@@ -64,7 +64,7 @@ Moving the Play Store listing from a personal account to the DUNS-verified Axiom
|
||||
|
||||
## Next — v0.4: Bridge feature expansion
|
||||
|
||||
Detailed plan: [`docs/plans/2026-04-13-bridge-feature-expansion.md`](docs/plans/2026-04-13-bridge-feature-expansion.md).
|
||||
Detailed plan: [`docs/plans/2026-04-13-bridge-feature-expansion.md`](../plans/2026-04-13-bridge-feature-expansion.md).
|
||||
|
||||
Expands the bridge channel's tool surface substantially, ports reliability patterns from the broader Hermes-Android ecosystem, and ships a per-app playbook skill so the agent has ready-made procedures for common apps out of the box.
|
||||
|
||||
@@ -84,16 +84,16 @@ Expands the bridge channel's tool surface substantially, ports reliability patte
|
||||
|
||||
Small follow-ons to v0.4 deliberately deferred to keep the v0.4.0 release surface focused.
|
||||
|
||||
**Unattended access mode** *(sideload-only).* ~~Opt-in toggle on the Bridge tab that acquires `FULL_WAKE_LOCK + ACQUIRE_CAUSES_WAKEUP`, raises `SCREEN_OFF_TIMEOUT` to max while active, and requests `KeyguardManager.requestDismissKeyguard()` so the agent can drive the device while the user is away.~~ **SHIPPED in v0.4.1** — see [`CHANGELOG.md`](CHANGELOG.md#041---unreleased). Final shape: opt-in toggle on the Bridge tab (sideload-only) that acquires `SCREEN_BRIGHT_WAKE_LOCK | ACQUIRE_CAUSES_WAKEUP | ON_AFTER_RELEASE` per bridge action, calls `KeyguardManager.requestDismissKeyguard()` via the registered MainActivity host, and reports `keyguard_blocked` (HTTP 423) when a credential lock blocks the action. Hard-bounded by the existing bridge auto-disable timer; persistent foreground-service notification + amber "Unattended ON" status-overlay chip stay visible while active; first-enable shows a scary dialog explaining the security model and credential-lock limitation. The original spec mentioned a WiFi-disconnect failsafe — rejected during implementation because Tailscale / VPN invalidates the "leaving WiFi = leaving LAN" assumption; the existing relay-disconnect detection (master toggle drops on disconnect → `UnattendedAccessManager.release()`) plus the auto-disable timer cover that surface.
|
||||
**Unattended access mode** *(sideload-only).* ~~Opt-in toggle on the Bridge tab that acquires `FULL_WAKE_LOCK + ACQUIRE_CAUSES_WAKEUP`, raises `SCREEN_OFF_TIMEOUT` to max while active, and requests `KeyguardManager.requestDismissKeyguard()` so the agent can drive the device while the user is away.~~ **SHIPPED in v0.4.1** — see [`CHANGELOG.md`](../../CHANGELOG.md#041---unreleased). Final shape: opt-in toggle on the Bridge tab (sideload-only) that acquires `SCREEN_BRIGHT_WAKE_LOCK | ACQUIRE_CAUSES_WAKEUP | ON_AFTER_RELEASE` per bridge action, calls `KeyguardManager.requestDismissKeyguard()` via the registered MainActivity host, and reports `keyguard_blocked` (HTTP 423) when a credential lock blocks the action. Hard-bounded by the existing bridge auto-disable timer; persistent foreground-service notification + amber "Unattended ON" status-overlay chip stay visible while active; first-enable shows a scary dialog explaining the security model and credential-lock limitation. The original spec mentioned a WiFi-disconnect failsafe — rejected during implementation because Tailscale / VPN invalidates the "leaving WiFi = leaving LAN" assumption; the existing relay-disconnect detection (master toggle drops on disconnect → `UnattendedAccessManager.release()`) plus the auto-disable timer cover that surface.
|
||||
|
||||
**Voice intent local dispatch loop.** The v0.4 voice intent handler builds `bridge.command` envelopes and routes them through the `ChannelMultiplexer` → WSS → relay → back-to-phone path, which the relay correctly rejects with `ignoring unexpected bridge.command from phone` (the wire protocol is server→phone only by design). Voice intents are phone-local, so the dispatch should be local: extend `BridgeCommandHandler` with a `handleLocalCommand(envelope)` entry point that runs the existing `when(path)` dispatch + the full Tier 5 safety check pipeline (blocklist → destructive verb modal → action executor) in-process, and have `RealVoiceBridgeIntentHandler.dispatch()` call it instead of `multiplexer.send()`. Single source of truth for "bridge command → action" preserved; safety modals still fire for destructive verbs; no WSS round-trip for an action that's happening on the same device. Caught by Bailey's on-device test 2026-04-14 after the multiplexer-wiring fix unblocked the dispatch path.
|
||||
|
||||
**~~Tiered permission checklist with JIT permission errors~~ — shipped on `feature/tiered-permissions` (v0.4.1).** See [CHANGELOG.md](CHANGELOG.md) under `[Unreleased] → v0.4.1 Bridge fast-follows` for the landed surface. Original scope:
|
||||
**~~Tiered permission checklist with JIT permission errors~~ — shipped on `feature/tiered-permissions` (v0.4.1).** See [CHANGELOG.md](../../CHANGELOG.md) under `[Unreleased] → v0.4.1 Bridge fast-follows` for the landed surface. Original scope:
|
||||
|
||||
- Tiered checklist with sideload-only sections gated on `BuildFlavor.SIDELOAD` (Core bridge / Notification companion / Voice & camera / Sideload features), Optional pills, runtime-permission launchers, ON_RESUME re-probes — done.
|
||||
- JIT permission-denied surfacing — bridge tool error envelope carries canonical `code` + `permission` aliases, Python `ResolveResult` types in `plugin/tools/resolve_result.py`, agent-tool wrappers upgrade `permission_denied` responses to structured LLM-readable envelopes, voice-mode JIT chip deep-links to `Settings.ACTION_APPLICATION_DETAILS_SETTINGS` for the running package — done.
|
||||
|
||||
**Voice intent → server session sync.** ✅ **Shipped 2026-04-16** — see [CHANGELOG `[Unreleased]`](CHANGELOG.md#unreleased) for the implementation. Picked option (d) (not in the original menu): synthesize OpenAI-format `assistant` (with `tool_calls`) + `tool` (with `tool_call_id`) message pairs from local voice-intent traces and pass them under a new `messages` field on the existing `/v1/runs` and `/api/sessions/{id}/chat/stream` payloads. LLMs are trained on this exact shape so they read it as natural conversation history rather than a system-prompt side note (lower retry risk than option (b)). Zero server changes (option (a) avoided), no double-dispatch (option (c) avoided). Idempotency via a `syncedToServer` flag on each trace.
|
||||
**Voice intent → server session sync.** ✅ **Shipped 2026-04-16** — see [CHANGELOG `[Unreleased]`](../../CHANGELOG.md#unreleased) for the implementation. Picked option (d) (not in the original menu): synthesize OpenAI-format `assistant` (with `tool_calls`) + `tool` (with `tool_call_id`) message pairs from local voice-intent traces and pass them under a new `messages` field on the existing `/v1/runs` and `/api/sessions/{id}/chat/stream` payloads. LLMs are trained on this exact shape so they read it as natural conversation history rather than a system-prompt side note (lower retry risk than option (b)). Zero server changes (option (a) avoided), no double-dispatch (option (c) avoided). Idempotency via a `syncedToServer` flag on each trace.
|
||||
|
||||
**Original problem statement (preserved for context):** Voice intents currently dispatch in-process (good for latency) and append a **local-only** trace to chat history (good for visual continuity), but the server-side session never sees them — so the gateway LLM has no memory of prior voice actions when the user follows up via text or voice. Symptom: user says "open Chrome" via voice (works), then says "did that work?" → LLM responds "I have no prior context for what you're asking about". Caught by Bailey's on-device test 2026-04-14: "The chat is resetting on voice or with our tools?" — actually voice intents bypass chat entirely, but the user-visible effect is the same.
|
||||
|
||||
@@ -117,7 +117,7 @@ Shape subject to change. Each theme needs a separate design + plan pass before i
|
||||
|
||||
### Desktop thin-client — Phase B (client-side tool routing)
|
||||
|
||||
v0.1 ships a remote-chat CLI. Phase B is the bigger win: **per-tool dispatch routing** so file/terminal/browser tools run against the user's machine while state tools (memory, skills, sessions, cron) stay on the server. Design detailed in the vault under `Axiom-Vault/3. System/Projects/Hermes-Relay/Desktop Client.md`. Key insertion point is hermes-agent `model_tools.py::handle_function_call()` (~line 517) — before `registry.dispatch()`, consult a session-scoped routing table populated by a relay handshake extension where the client advertises which tools it can service. Isomorphic to how `android_*` tools already flow through the `bridge.command` channel. Proposed branch: `fork/tool-relay` on the hermes-agent fork; upstream issue to open before merging. Blocked on: (a) the handshake extension in `plugin/relay/auth.py` to carry the advertised-tools list, (b) a new `desktop.command` channel mirroring `bridge.command` semantics, (c) the upstream PR conversation.
|
||||
v0.1 ships a remote-chat CLI. Phase B is the bigger win: **per-tool dispatch routing** so file/terminal/browser tools run against the user's machine while state tools (memory, skills, sessions, cron) stay on the server. An earlier private design note supplied the initial decomposition. Key insertion point is hermes-agent `model_tools.py::handle_function_call()` (~line 517) — before `registry.dispatch()`, consult a session-scoped routing table populated by a relay handshake extension where the client advertises which tools it can service. Isomorphic to how `android_*` tools already flow through the `bridge.command` channel. Proposed branch: `fork/tool-relay` on the hermes-agent fork; upstream issue to open before merging. Blocked on: (a) the handshake extension in `plugin/relay/auth.py` to carry the advertised-tools list, (b) a new `desktop.command` channel mirroring `bridge.command` semantics, (c) the upstream PR conversation.
|
||||
|
||||
### Observability & introspection
|
||||
- Real-time accessibility event streaming for reactive workflows (`android_events`, `android_event_stream`)
|
||||
@@ -154,6 +154,6 @@ Dedicated **"Hermes Phone"** — a device (or phone ROM) that boots straight int
|
||||
|
||||
New ideas enter via: direct proposals in GitHub issues, comparison passes against similar projects, community feedback from users and contributors, or internal research that turns into a shipped prototype.
|
||||
|
||||
Active work waves (like the v0.4 bridge feature expansion above) get their detailed implementation plans in [`docs/plans/`](docs/plans/). When a plan wave ships, its plan file is archived or removed and the items migrate into [`CHANGELOG.md`](CHANGELOG.md).
|
||||
Active work waves (like the v0.4 bridge feature expansion above) get their detailed implementation plans in [`docs/plans/`](../plans/). When a plan wave ships, its plan file is archived or removed and the items migrate into [`CHANGELOG.md`](../../CHANGELOG.md).
|
||||
|
||||
Have an idea? [Open an issue](https://github.com/Codename-11/hermes-relay/issues/new) — every one is read.
|
||||
@@ -276,4 +276,4 @@ keeping route ownership explicit:
|
||||
`webui` as a rich-chat prompt hint; upstream removed that unused path at the
|
||||
verified `b20cc5f` snapshot. Hermes has no stable `android` or mobile platform
|
||||
hint, so Android must not claim Desktop parity or invent one. The upstream
|
||||
platform-hint follow-up is tracked in `TODO.md`.
|
||||
platform-hint follow-up is tracked in `docs/project/TODO.md`.
|
||||
|
||||
@@ -15,6 +15,6 @@ request under `/docs/`. The meta refresh and visible link provide a no-script
|
||||
fallback to the guide root. Privacy compatibility pages identify
|
||||
`https://hermes-relay.dev/privacy.html` as canonical.
|
||||
|
||||
Removal is tracked in the repository root `TODO.md`. Do not delete this shim
|
||||
Removal is tracked in the repository root `docs/project/TODO.md`. Do not delete this shim
|
||||
solely because the first fixed release has shipped; honor the documented
|
||||
compatibility window for older Play and sideload installations.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
name: hermes-relay
|
||||
# Temporary v1 shim for Hermes installers that reject manifests the runtime supports; see TODO.md.
|
||||
# Temporary v1 shim for Hermes installers that reject manifests the runtime supports; see docs/project/TODO.md.
|
||||
manifest_version: 1
|
||||
api_version: 1
|
||||
version: 1.11.1
|
||||
|
||||
@@ -160,7 +160,7 @@ BRIEF="${WTDIR}/ISSUE-BRIEF.md"
|
||||
echo "## Definition of done"
|
||||
echo
|
||||
echo "- The fix passes the verification above (write the failing test first where the surface is CI-gateable)."
|
||||
echo "- Update CHANGELOG \`[Unreleased]\`, and DEVLOG.md at end of session; park any follow-ups in TODO.md."
|
||||
echo "- Update CHANGELOG \`[Unreleased]\`, and docs/project/DEVLOG.md at end of session; park any follow-ups in docs/project/TODO.md."
|
||||
echo "- Feature branches target \`dev\` (never straight to \`main\`); merge with --no-ff."
|
||||
echo
|
||||
echo "## Issue body"
|
||||
|
||||
@@ -15,7 +15,7 @@ metadata:
|
||||
|
||||
# Hermes-Relay Desktop CLI Setup
|
||||
|
||||
> **Experimental.** The desktop CLI at `desktop/` is a preview-grade thin client. Pairing, chat, shell (PTY pipe to the host), and local tool routing (`desktop_terminal` / `desktop_read_file` / `desktop_write_file` / `desktop_search_files` / `desktop_patch`) all work end-to-end. Daemon mode, multi-client routing, and code-signed binaries are the v1.0 polish — see the [ROADMAP](https://github.com/Codename-11/hermes-relay/blob/main/ROADMAP.md#desktop-track-parallel-lane-to-android--experimental).
|
||||
> **Experimental.** The desktop CLI at `desktop/` is a preview-grade thin client. Pairing, chat, shell (PTY pipe to the host), and local tool routing (`desktop_terminal` / `desktop_read_file` / `desktop_write_file` / `desktop_search_files` / `desktop_patch`) all work end-to-end. Daemon mode, multi-client routing, and code-signed binaries are the v1.0 polish — see the [ROADMAP](https://github.com/Codename-11/hermes-relay/blob/main/docs/project/ROADMAP.md#desktop-track-parallel-lane-to-android--experimental).
|
||||
|
||||
The [Hermes-Relay](https://github.com/Codename-11/hermes-relay) desktop CLI (`hermes-relay`) is a thin client that gives you remote access to a Hermes agent running on another machine. It pipes a full PTY shell (with the agent's native Ink TUI), streams structured chat events for scripting, and — uniquely — lets the remote agent execute tools **on your local machine** (read files, run shell commands, search the filesystem) through a round-trip over the same WSS relay the Android client uses. The agent brain stays on the host; your laptop is the hands.
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ While inside the shell/TUI session (bare `hermes-relay`, the default mode), `Ctr
|
||||
- **[Local tool routing](./tools.md)** — 23 agent-callable tools: file I/O, unified-diff patching, ripgrep, shell + PowerShell exec, process control, a background-job API, archive/transfer, clipboard, screenshot, and editor-launcher. Strict consent gate per relay URL; non-TTY stdin fails closed. The experimental computer-use family is off by default and has a separate persistent enablement switch.
|
||||
- **[Self-update](./subcommands.md#hermes-relay-update)** — `hermes-relay update` polls GitHub Releases, semver-compares, and verifies SHA256. POSIX and Windows CLI-only installs replace the standalone binary; a detected Windows UI installation updates the complete CLI+UI bundle and restores the processes that were running.
|
||||
- **[Surface plugins](./subcommands.md#hermes-relay-plugins)** — install, update, and launch terminal dashboard plugins from the CLI. The first built-in plugin is [Herm](https://github.com/liftaris/herm), installed as `herm-tui` and resumed with `herm -c`.
|
||||
- **[Workspace awareness](./subcommands.md#hermes-relay-workspace)** — on connect, the client advertises `cwd`, `git_root`, `git_branch`, `repo_name`, `hostname`, `platform`, `active_shell` to the relay so the agent knows which repo you're in. Client-side capability shipped in alpha.6; server-side prompt-context consumption is on the way (see [ROADMAP.md](https://github.com/Codename-11/hermes-relay/blob/main/ROADMAP.md#desktop-track-parallel-lane-to-android--experimental)).
|
||||
- **[Workspace awareness](./subcommands.md#hermes-relay-workspace)** — on connect, the client advertises `cwd`, `git_root`, `git_branch`, `repo_name`, `hostname`, `platform`, `active_shell` to the relay so the agent knows which repo you're in. Client-side capability shipped in alpha.6; server-side prompt-context consumption is on the way (see [docs/project/ROADMAP.md](https://github.com/Codename-11/hermes-relay/blob/main/docs/project/ROADMAP.md#desktop-track-parallel-lane-to-android--experimental)).
|
||||
- **[Conversation picker](./subcommands.md#hermes-relay-shell)** — on first or fresh attach, choose from recent server-side Hermes conversations with first-prompt previews before the TUI starts.
|
||||
- **[TUI session continuity](./subcommands.md#hermes-relay-sessions)** — bare `hermes-relay` resumes the active/default tmux session, replays recent scrollback, and `sessions list/resume/new/kill` gives explicit control when you need it.
|
||||
- **[Editor tool + interactive patch approval](./tools.md#desktop-open-in-editor-and-interactive-patches)** — agent calls `desktop_open_in_editor(path, line, col)` to open `$VISUAL` / `$EDITOR` / VSCode / Cursor / Sublime / nvim. Agent-proposed patches render as colored unified diffs with `y`/`n`/`e`/`r` prompts.
|
||||
|
||||
@@ -436,7 +436,7 @@ hermes-relay workspace --json # machine-readable
|
||||
Fields detected via parallel `git rev-parse` / `git status --porcelain=v1 --branch` calls under a 2 s total budget: `cwd`, `git_root`, `git_branch`, `git_status_summary` (staged / modified counts), `repo_name`, `hostname`, `platform`, `arch`, `active_shell`. Active-editor hints (`active_editor`) detect VSCode / Cursor via `$VSCODE_IPC_HOOK_CLI` + `TERM_PROGRAM`, or poll tmux's `display-message -p "#{pane_current_path}:#{pane_current_command}"` if `--watch-editor` is on.
|
||||
|
||||
::: tip Server-side consumption
|
||||
The client-side workspace envelope shipped in alpha.6. Server-side prompt-context injection (so the agent reads "Active desktop workspace: machine=X · repo=Y · branch=Z" every turn) is on the way — see [ROADMAP.md](https://github.com/Codename-11/hermes-relay/blob/main/ROADMAP.md#desktop-track-parallel-lane-to-android--experimental). Until then, the envelope is captured by the relay as ephemeral session metadata; you can ask the agent about it explicitly via tool calls.
|
||||
The client-side workspace envelope shipped in alpha.6. Server-side prompt-context injection (so the agent reads "Active desktop workspace: machine=X · repo=Y · branch=Z" every turn) is on the way — see [docs/project/ROADMAP.md](https://github.com/Codename-11/hermes-relay/blob/main/docs/project/ROADMAP.md#desktop-track-parallel-lane-to-android--experimental). Until then, the envelope is captured by the relay as ephemeral session metadata; you can ask the agent about it explicitly via tool calls.
|
||||
:::
|
||||
|
||||
## `hermes-relay logo`
|
||||
|
||||
Reference in New Issue
Block a user