Skip to content

feat(desktop): route remote bot actions by connection - #90006

Merged
7 commits merged into
NousResearch:mainfrom
saralilyb:fix/remote-bot-routing
Aug 23, 2026
Merged

feat(desktop): route remote bot actions by connection#90006
7 commits merged into
NousResearch:mainfrom
saralilyb:fix/remote-bot-routing

Conversation

@saralilyb

@saralilyb saralilyb commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • make Bot Mode operations connection-bound instead of relying on the active
    gateway
  • open a remote Bot's single hidden canonical forever-chat directly without
    switching Desktop's chrome/API home
  • preserve the complete remote Bot context menu while routing edits, groups,
    duplication, new chats, routines, and deletion to the captured owner
  • keep ordinary visible history in the global Sessions sidebar, which already
    aggregates connected gateways
  • intentionally omit the removed per-bot hidden-session browser

Safety and compatibility

  • validates immutable (connectionId, profile, targetProfile) ownership before
    reads and mutations
  • preserves backend aliases across response matching, deletion teardown, and
    nested profile maps
  • adopts an existing hidden Bot Chat before minting; transient lookup/resume
    failures never fork the forever-chat
  • protects default profiles and performs connection-qualified deletion teardown
  • routes remote group plumbing and direct messages through immutable owners
  • isolates same-named profiles, session ownership, transcript caches, routines,
    and Bot metadata by connection and profile
  • preserves the last committed Bot metadata generation across failed successor
    writes
  • keeps legacy sole-local behavior while failing closed for ambiguous sources

Verification

Exact code from signed merge head ddc78217fdc1a34a4b91c6f78362b20d8415aa43
was reconciled with current main 603d5651b31f0c46d18138946d8c4009fdf2c3d4
and verified locally:

  • 394/394 Bot Mode Node tests
  • 333/333 affected renderer tests across 19 files
  • 88/88 Electron routing and registry tests
  • complete renderer, Electron, and E2E TypeScript typechecks
  • git diff --check
  • added-line credential/private-key scan: no findings
  • packaged successfully with hermes desktop --build-only

Manual test plan

  • Click a thin remote Bot row and confirm its canonical Bot Chat opens while
    the launch connection remains Desktop's home
  • Confirm the remote row has Pin/Hide, Edit, Groups, Duplicate, New Chat,
    and permitted Delete actions
  • Confirm ordinary remote history remains available in global Sessions
  • Confirm canonical default cannot be deleted

Carry immutable connection and profile ownership through Bot Mode actions,
session hydration, transcript loading, new chats, and profile deletion.
Keep same-named local and remote profiles isolated, preserve the full context
menu, and migrate Bot metadata to connection-qualified storage.

Add adversarial routing, alias, migration, cache, and compatibility coverage.
@alt-glitch alt-glitch added type/feature New feature or request comp/desktop Electron desktop app (apps/desktop/*) area/sessions Session lifecycle, resume, persistence, history P3 Low — cosmetic, nice to have sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Aug 19, 2026

@andrexibiza andrexibiza left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed exact head 9b7ab9d65aeda7c535e0a91e5a1c0d951cb48180 against current main 13ce0c5c675e843af70d19c9e5144249cd51c8d1. There were no prior review submissions or PR discussion on this head.

The architectural direction is right: Bot Mode should carry an immutable (connectionId, profile, targetProfile) owner through reads and mutations instead of borrowing whichever gateway happens to be foregrounded. The source-qualified selection/cache keys, captured session owner route, route-aware transcript backfill, fail-closed requestForBot, and source-bound profile/session/routine operations are all aligned with the multi-source architecture that landed in #89719 and the active-profile correction in #89902.

I would not merge this head yet. I found two class-level blockers and one narrower argument-rewrite bug.

1. targetProfile is preserved on the route, but several Bot metadata/canonical-chat paths still interpret backend responses with the Desktop-facing profile name

connection-registry.ts explicitly defines targetProfile as the backend profile when a registry route maps the Desktop profile name, and this PR correctly proves scalar request routing with shapes like:

{ connectionId: 'remote-a', profile: 'worker', targetProfile: 'backend-worker' }

But the Bot consumer does not consistently cross that alias boundary:

  • prepareBotSource() calls requestForBot(bot, 'profiles.list', {}), then selects profile.name === bot.name.
  • ensureBotMetadata() does the same.
  • openBotCanonicalChat() sends preferred_session_ids: { [name]: pinned }; scopedBotParams() rewrites top-level profile/name/clone_from, but not profile-keyed nested maps.

For worker -> backend-worker, the request is delivered to the correct connection, but the returned profile row is named backend-worker, so both metadata readers miss it. The exact pin lookup is likewise keyed as worker instead of backend-worker. That can drop the durable Bot ui_meta/canonical-chat pointer, make Edit/Groups hydrate an empty view, and drive canonical-chat recovery toward a new session even though the existing backend-owned Bot Chat is healthy.

The remote-DM code already uses route.targetProfile || profile correctly, so this is not a product-model ambiguity; it is an incomplete translation boundary.

Required fix: establish one logical-profile ↔ backend-profile translation seam and use the backend identity when matching returned profile rows and building profile-keyed payloads. Please add executable coverage for a non-identity alias through (a) Bot metadata hydration/Edit, (b) canonical pin reuse via preferred_session_ids, and (c) context-menu mutation—not only the scalar remote-DM/request cases.

2. The v2 Bot metadata transaction can delete the last known-good committed v2 state after migration

commitBotMetaV2() currently performs:

remove(commit marker)
set(bot-meta-v2, next snapshot)
set(commit marker, true)

and on any error removes both the marker and bot-meta-v2.

That is safe enough during the initial v1 -> v2 migration, because v1 still represents the current rollback state. It is not failure-atomic for later normal edits after v2 has become authoritative. v1 is intentionally retained as one-version rollback data and is no longer advanced with every source-scoped Bot edit.

Concrete failure shape:

  1. Migration succeeds; committed v2 contains state B while v1 is older state A.
  2. More remote/local scoped edits land in v2 (state C).
  3. A later saveBotMeta() attempts state D; the new v2 write or final marker write fails (disk-full/storage failure).
  4. The catch path deletes the v2 snapshot and marker.
  5. On restart, migrateBotMeta() correctly refuses markerless v2 and falls back to stale v1 state A.

So one failed successor write can erase the previous valid v2 generation and roll back unrelated Bot metadata changes across the whole plugin, rather than merely rejecting the failed edit. The existing failure tests prove initial-migration rollback, but not preservation of a previously committed v2 generation.

Required fix: make v2 updates copy-on-write/generation-based (or otherwise restore the previous committed v2 snapshot) so the last known-good generation remains authoritative until a complete successor is committed. Add a regression that starts from marker=true + committed v2 B, fails the next commit, reloads, and proves B survives unchanged.

3. cli.exec alias rewriting is value-global instead of position/semantic-aware

scopedBotParams() maps every argv element exactly equal to the logical profile name to targetProfile:

argv: params.argv.map(arg => arg === logical ? target : arg)

That rewrites user payload as well as the profile operand. Example:

profile describe worker --text worker

becomes:

profile describe backend-worker --text backend-worker

so a description whose literal text equals the logical Bot name is silently changed. Please rewrite only the command positions that actually carry profile identity (or avoid the CLI compatibility path for profile mutations where a typed RPC exists), and pin that with a regression.

Interlocks / provenance

  • #89719, salvaging #88325 by @dokterdok, is the foundation: explicit (connection, profile) Desktop routing and retained background gateways. This PR is a complementary Bot Mode consumer/closure slice and should preserve that provenance rather than being described as re-originating multi-source routing.
  • #89902 by @teknium1 fixed the active-profile session-resolution half of blank Bot threads. This PR's captured owner route is the stronger generalization for cross-connection opens; retain the #89902 regression while composing it.
  • #89916 by @frizikk remains the adjacent “other side of the shape”: filesystem/Git artifact facades can still discard connectionId and route a remote-owned resource to local. #90006 does not duplicate or close that bug; together they establish the same principle: once a resource/session/Bot has a qualified owner, downstream facades must not reduce it to foreground profile state.
  • #89252 / #89860 are the gateway-side analogue: transport owner, runtime profile, and persistence owner are separate dimensions. profile and targetProfile should likewise remain distinct here instead of becoming incidentally interchangeable.

CI / re-review gate

The author reports substantial focused validation (312 Bot Mode Node tests, 280 renderer tests, 58 registry tests, typechecks), but the connector returns no PR-triggered workflow runs for this exact head yet, so there is no hosted exact-head matrix to treat as a receipt.

Re-review gate for me: close the alias-response/nested-map hole, preserve the previous committed v2 generation across a failed successor write, make cli.exec remapping semantic, then run the exact-head Desktop/renderer/electron matrix. I did not find a reason to reject the core immutable-owner-route architecture; the blockers are where that route is translated or persisted.

Preserve current upstream Desktop and Bot Mode behavior while carrying the
connection-bound remote Bot routing implementation forward without rewriting
the signed feature commit.
@saralilyb

Copy link
Copy Markdown
Contributor Author

Thanks for the detailed review. I preserved the immutable-owner architecture and addressed each requested blocker on signed merge head 723dbda0414ce2d8fdc86283b76302537d91b724:

  1. Alias translation: added one backendTargetProfile seam used for profiles.list response matching, metadata hydration, capability scope, canonical-chat pin reuse, and nested preferred_session_ids maps. Non-identity alias tests cover Edit hydration, context-menu mutation, and existing-chat reuse.
  2. v2 failure atomicity: successor commits now retain and restore the previous committed v2 snapshot/marker on failure. The regression starts with committed B, fails D, reloads, and proves B survives.
  3. Semantic CLI rewriting: only --profile values and the profile operand in profile <command> <operand> are rewritten; payload text equal to the logical Bot name remains literal.

The merge also closes adjacent connection-bound edge cases found during fail-closed review: focused-owner ambiguity, local-recipient DMs while remote-active, same-name post-delete navigation, source-scoped legacy-delete rejection, and registered local/SSH deletion teardown.

Exact-head verification against current main 13ce0c5c675e843af70d19c9e5144249cd51c8d1:

  • 350/350 Bot Mode Node tests
  • 288/288 affected renderer tests
  • 86/86 Electron routing/registry tests
  • renderer + Electron + E2E TypeScript typechecks
  • successful hermes desktop --build-only

The branch was updated by a signed merge commit; the original signed feature commit was not rewritten. The PR is now conflict-free.

@andrexibiza andrexibiza left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed exact current head 723dbda0414ce2d8fdc86283b76302537d91b724 against current main 13ce0c5c675e843af70d19c9e5144249cd51c8d1.

Conflict status: verified clear

GitHub reports this head as mergeable: true. The current base is the merge base, and the branch is 2 commits ahead / 0 behind. The merge commit is signature-verified and has the prior reviewed feature head plus current main as its two parents. There are no unresolved inline review threads.

Original code blockers: closed

  1. Alias translation: one backendTargetProfile seam now drives backend response matching and nested profile-keyed requests. prepareBotSource(), ensureBotMetadata(), and openBotCanonicalChat() use the backend identity, including preferred_session_ids. Executable regressions cover non-identity Edit hydration/save, context-menu/group mutation routing, and canonical-pin reuse.
  2. v2 metadata failure atomicity: commitBotMetaV2() captures the previously committed snapshot/marker and restores them when a successor commit fails. The regression starts from committed B, fails D, reloads, and proves B remains authoritative.
  3. Semantic CLI rewriting: rewriteCliProfileOperands() rewrites only --profile values and the profile <command> <operand> identity slot. The regression preserves literal payload text in profile describe worker --text worker.

I do not see a remaining implementation blocker from my prior review.

Completion blockers still open

  • The required hosted exact-head matrix has not run. The three PR-triggered workflows for this SHA — CI run 32261267598, Docker run 32261265397, and Nix run 32261264672 — all completed as action_required, and each currently has zero jobs. That is an approval-gated non-run, not a green receipt. GitHub correspondingly reports mergeable_state: blocked.
  • The PR's own final-build manual plan still leaves two items unchecked: remote Edit Profile display and rejection of canonical default deletion.

So the branch is conflict-free and the three code blockers are repaired, but all completion blockers are not yet closed. I am not approving this head until the workflows are approved/run and green and those two final-build checks are recorded.

Preserve the connection-bound Bot and session routing implementation while
adopting upstream's modular Desktop API split and all changes through
b2057c1.
Carry the verified connection-bound routing branch through the remaining
upstream changes at fe2752a without rewriting prior signed commits.
@saralilyb

Copy link
Copy Markdown
Contributor Author

Updated the branch through current main fe2752a05db5ef426a8346b230e19005711ccdf0 with signed merge head a946169533c1bb11b8bdaf5b7da3708185a2b237.

Upstream split the former monolithic src/hermes.ts into src/api/*; the routing changes now compose with that structure rather than restoring the monolith:

  • api/client.ts: connection/profile scope primitives
  • api/sessions.ts: ambient, explicit remote, and explicit-local session ownership
  • api/profiles.ts: scoped deletion and default-profile guards
  • use-session-actions: connection-qualified runtime close and REST deletion

A fail-closed review caught two initial porting regressions (lost ambient/explicit-local tags and profile-only deletion); both received red-green tests and passed re-review.

Exact latest-head verification:

  • 350/350 Bot Mode Node tests
  • 324/324 affected renderer tests across 18 files
  • 86/86 Electron routing/registry tests
  • renderer + Electron + E2E TypeScript typechecks
  • successful hermes desktop --build-only

The PR is conflict-free. No prior signed commit was rewritten.

Adopt upstream's one-hidden-forever-chat model and remove the per-bot hidden
session browser while preserving connection-bound remote Bot opening, the full
remote action menu, same-name isolation, and global Sessions navigation.
Carry the reviewed hybrid Bot routing branch through current main at
4a5b6dd without rewriting prior signed commits.
Carry the reviewed hybrid routing branch through current main at 603d565,
preserving fresh room-session identity and prior signed history.
@saralilyb

Copy link
Copy Markdown
Contributor Author

Reworked the branch to align with current Bot Mode's one-forever-chat contract while preserving the missing multi-connection affordances.

The per-bot hidden-session browser is removed. Ordinary visible history stays in global Sessions; remote Bot rows now directly open their source-owned canonical chat and retain the full source-bound action menu.

The reconciliation also includes current upstream canonical adoption/no-fork behavior, group clarify/approval handling, fresh room-session identity, and fail-closed routing for aliases, deletion teardown, group plumbing, DMs, metadata, and cancellation.

Current signed head: ddc78217fdc1a34a4b91c6f78362b20d8415aa43 on main 603d5651b31f0c46d18138946d8c4009fdf2c3d4.

Verification: 394 Bot, 333 renderer, 88 Electron tests; all Desktop typechecks; clean diff/security scan; successful build-only package.

@novaflash82

Copy link
Copy Markdown

Verified live on the packaged Windows Desktop v0.20.4 with a token-authenticated WSL remote gateway while the app-managed local gateway remains Primary.

Current behavior after registering the remote source:

  • The remote default profile appears exactly once as a source-qualified Bot row; the same-named local row also remains exactly once.
  • Cross-connection @ autocomplete and routing work: selecting the remote handle delivers the turn to the remote profile's canonical hidden Bot Chat, and Desktop relays the attributed response notification.
  • Clicking the remote Bot row does not open that Bot Chat. It only shows: Stay in this chat and @<qualified-handle> to message them. Gateway stays on this device.
  • The remote row never becomes a rich/editable row and exposes no context menu or visible actions control.
  • Therefore the user cannot open the remote Bot conversation, choose Edit Profile, or change its avatar/title/description from Desktop.
  • The limitations persist after a full Desktop restart even though the encrypted connection, roster row, autocomplete entry, and routed messaging all remain healthy.

This matches the manual-test gaps listed in this PR. In particular, acceptance should verify:

  1. Clicking a thin remote row opens that source's canonical Bot Chat without changing Desktop's home gateway.
  2. Right-click and/or the visible actions control exposes the remote Bot actions.
  3. Edit Profile routes metadata and avatar asset writes through the immutable (connectionId, profile, targetProfile) owner; it must never mutate a same-named local profile as fallback.
  4. The remote avatar/title/description refresh in the roster and survive Desktop restart.
  5. Mention routing remains operational and same-named local/remote rows remain source-qualified and deduplicated.

Related but separate: #89304 tracks presenting a remote agent as a normal linked Profile in the profile switcher. The behavior above is specifically about the already-rendered remote Bot row and its advertised Bot Mode operations.

andrexibiza added a commit to andrexibiza/hermes-agent that referenced this pull request Aug 21, 2026
Make explicit registry qualification authoritative: only a current exact ID is accepted, while blank, malformed, unknown, or retired claims fail closed without endpoint inference. Restrict genuinely unqualified legacy descriptors to the shared full-envelope URL/Cloud/SSH matcher, reject zero or multiple matches, normalize SSH host/user identity, and prove remote-primary restoration keeps the exact (connectionId, profile) tuple.

Closes NousResearch#90048.

Prior work by @teknium1 in NousResearch#89719 and NousResearch#88922, @andrexibiza in NousResearch#90913, and @AndreasG78 in NousResearch#90048 (comment) shaped this implementation. @saralilyb's NousResearch#90006 remains downstream consumer context; the production stopgap is credited but excluded because registry primary does not prove route ownership.

Copy link
Copy Markdown
Contributor

Collision/interlock note: #90198 is the surviving owner of registry route identity and is now published at exact head 9773a3dd37530024df2d915d2e1e2339ecc6153d. This PR remains the broader @saralilyb-owned consumer for remote bot action routing; none of its ownership/action work was copied into #90198.

Merge order: land #90198 first after its hosted gates, then rebase #90006 and consume the exact-ID/current-registry contract. Please do not add a second resolver or primary-as-owner heuristic here. Prior work by @saralilyb in #90006 is explicitly credited in #90048 and #90198.

Copy link
Copy Markdown
Contributor

Topology / composition decision after review of #90198:

#90198 is the surviving authority for Desktop connection identity. This branch may own connection-scoped profile deletion, teardown ordering, and the deletion gate, but it must not infer or validate source identity independently.

Before landing, compose on #90198 and make every connectionId entering dispatchRegistryApiRequest(), registryConnectionKind(), ensureRegistryBackend(), and connection-scoped teardown come from the canonical resolvedConnectionId() contract:

  • explicit qualification is current exact registry ID or fail closed;
  • only descriptors with no connectionId property may enter compatibility inference;
  • legacy inference uses the shared full URL/cloud/SSH envelope and requires one unique match;
  • no primary-selection, URL-only, user@host, or registry-order fallback.

The deletion gate then authorizes mutation of the already-resolved object; it is not an identity resolver. Keep #90913 closed and import the #90198 implementation rather than copying its matcher into this PR.

@saralilyb

Copy link
Copy Markdown
Contributor Author

Seen and agreed. I’ll keep #90006 downstream of #90198 and wait for the resolver owner to merge before updating this branch.

After it lands, I’ll rebase #90006 and consume connection-route-identity.ts / resolvedConnectionId() as the sole connection-identity authority for dispatchRegistryApiRequest(), registryConnectionKind(), ensureRegistryBackend(), and connection-scoped teardown. This branch will retain the connection-scoped action, deletion authorization, and teardown behavior, without adding a second matcher or any primary, endpoint-only, user@host, or registry-order fallback.

I’ll run the exact-head Desktop, renderer, Electron, typecheck, and packaging matrix after composition and report the resulting head and receipts here.

teknium1 pushed a commit that referenced this pull request Aug 23, 2026
Make explicit registry qualification authoritative: only a current exact ID is accepted, while blank, malformed, unknown, or retired claims fail closed without endpoint inference. Restrict genuinely unqualified legacy descriptors to the shared full-envelope URL/Cloud/SSH matcher, reject zero or multiple matches, normalize SSH host/user identity, and prove remote-primary restoration keeps the exact (connectionId, profile) tuple.

Closes #90048.

Prior work by @teknium1 in #89719 and #88922, @andrexibiza in #90913, and @AndreasG78 in #90048 (comment) shaped this implementation. @saralilyb's #90006 remains downstream consumer context; the production stopgap is credited but excluded because registry primary does not prove route ownership.
@teknium1 teknium1 closed this pull request by merging all changes into NousResearch:main in e132e11 Aug 23, 2026
@teknium1

Copy link
Copy Markdown
Contributor

Landed via #92731 (merge commit e132e11) — thank you @saralilyb, this was substantial work and your commits are preserved in the history.

What survived intact: the immutable (connectionId, profile) owner capture, requestForBot routing, backend profile aliasing, group session owners, connection-qualified deletion, focused-owner atoms, remote roster merge, and the Electron/sdk/store changes.

What we reconciled onto current main rather than restoring: canonical Bot Chat resolution stayed name-identity (the 'Bot Chat' registry row — pointer pins were removed on main after repeated fork incidents) and fail-closed on lookup errors (#92692), now consulted on the bot's own source via your owner routes, so remote bots get the same no-fork guarantees. The renderer-side remote DM delivery was superseded by the message_agent tool architecture (#91802/#91915: the composer middleware identifies mentions, the agent owns delivery) and was not ported.

#90198 landed first as the connection-identity authority, per the agreement in this thread. Closing this as landed.

pull Bot pushed a commit to Penguinjanator/luna-hermes-agent that referenced this pull request Aug 23, 2026
…ciled with name-identity + fail-closed canonical resolution

Salvage of saralilyb's remote-bot routing work onto current main:
- kept: immutable (connectionId, profile) owner capture, requestForBot
  routing, backendTargetProfile aliasing, group session owners,
  connection-qualified deletion, focused-owner atoms, remote roster
  merge, Electron profile-delete routing, sdk/store/transcript changes
- reconciled: canonical Bot Chat resolution stays NAME-identity (the
  'Bot Chat' registry row) and FAIL-CLOSED on lookup errors — now
  consulted on the bot's own source via the captured owner route, so
  remote bots get the same no-fork guarantees
- dropped: pointer-pin plumbing (preferredSessionIds, saveBotMeta chat
  writes, pin verification) — superseded by name-identity on main;
  renderer-side remote DM delivery (deliverRemoteRosterMentions /
  pollRemoteDmReply / ensureRemoteCanonicalChat) — superseded by the
  message_agent tool architecture (NousResearch#91802/NousResearch#91915: middleware identifies,
  never delivers); pointer-era test files deleted on main
- openStoredBotChat/createCanonicalChat: remote opens keep Desktop's
  chrome home (keepAllProfilesScope: true on routed opens); local bots
  keep the measured workspace re-home
- prepareBotSource: capability gate only — routed RPCs never require
  activation authority
prmartinow pushed a commit to prmartinow/hermes-agent that referenced this pull request Aug 26, 2026
Make explicit registry qualification authoritative: only a current exact ID is accepted, while blank, malformed, unknown, or retired claims fail closed without endpoint inference. Restrict genuinely unqualified legacy descriptors to the shared full-envelope URL/Cloud/SSH matcher, reject zero or multiple matches, normalize SSH host/user identity, and prove remote-primary restoration keeps the exact (connectionId, profile) tuple.

Closes NousResearch#90048.

Prior work by @teknium1 in NousResearch#89719 and NousResearch#88922, @andrexibiza in NousResearch#90913, and @AndreasG78 in NousResearch#90048 (comment) shaped this implementation. @saralilyb's NousResearch#90006 remains downstream consumer context; the production stopgap is credited but excluded because registry primary does not prove route ownership.
prmartinow pushed a commit to prmartinow/hermes-agent that referenced this pull request Aug 26, 2026
…ciled with name-identity + fail-closed canonical resolution

Salvage of saralilyb's remote-bot routing work onto current main:
- kept: immutable (connectionId, profile) owner capture, requestForBot
  routing, backendTargetProfile aliasing, group session owners,
  connection-qualified deletion, focused-owner atoms, remote roster
  merge, Electron profile-delete routing, sdk/store/transcript changes
- reconciled: canonical Bot Chat resolution stays NAME-identity (the
  'Bot Chat' registry row) and FAIL-CLOSED on lookup errors — now
  consulted on the bot's own source via the captured owner route, so
  remote bots get the same no-fork guarantees
- dropped: pointer-pin plumbing (preferredSessionIds, saveBotMeta chat
  writes, pin verification) — superseded by name-identity on main;
  renderer-side remote DM delivery (deliverRemoteRosterMentions /
  pollRemoteDmReply / ensureRemoteCanonicalChat) — superseded by the
  message_agent tool architecture (NousResearch#91802/NousResearch#91915: middleware identifies,
  never delivers); pointer-era test files deleted on main
- openStoredBotChat/createCanonicalChat: remote opens keep Desktop's
  chrome home (keepAllProfilesScope: true on routed opens); local bots
  keep the measured workspace re-home
- prepareBotSource: capability gate only — routed RPCs never require
  activation authority
prmartinow pushed a commit to prmartinow/hermes-agent that referenced this pull request Aug 26, 2026
…mote-bots

feat(desktop): remote bots open their own Bot Chat without re-homing Desktop (salvage NousResearch#90006)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/sessions Session lifecycle, resume, persistence, history blocked Waiting on external dependency or decision comp/desktop Electron desktop app (apps/desktop/*) P3 Low — cosmetic, nice to have sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants