Skip to content

feat(plugins): support session-owned execution and isolated viewers - #103690

Closed
Zeus-Deus wants to merge 14 commits into
NousResearch:mainfrom
Zeus-Deus:feat/plugin-session-capabilities
Closed

Zeus-Deus wants to merge 14 commits into
NousResearch:mainfrom
Zeus-Deus:feat/plugin-session-capabilities

Conversation

@Zeus-Deus

@Zeus-Deus Zeus-Deus commented Sep 5, 2026 •

Copy link
Copy Markdown

Consented native setup follow-up

Adds a generic, profile-bound setup gate to the existing enable/install paths (CLI, Desktop RPC, REST, composite selection and packs). Plugins declare a package-root setup.py; explicit consent binds the canonical key, selected home and setup revision. Cancel/failure preserves enablement, and no setup runs during discovery or tool execution. No Realms-specific core branch or new model tool.

Desktop supports review, busy, cancel, failure and retry. Canonical-key collisions and revision changes cannot substitute another setup target; synchronous REST test loops and already-reaped subprocess cleanup are covered.

Latest verification after integrating upstream and the concurrent status-stack change:

  • Prerequisite-only warning-strict setup/identity lane: 38 passed, 0 failed.
  • Combined prerequisite + Realms checkout: 511 backend tests passed; full Desktop suite 9,509 passed, 6 skipped; TypeScript and native DEV build passed. Lanes overlap; do not sum them.
  • Actual isolated DEV Desktop: explicit review, Enter/Space on Cancel, permissions failure without enablement, retry installing the checksum-pinned driver in the selected profile, fresh session/runtime adoption, private terminal exit propagation, Cua capture and retained approval denial. This is supplementary consumer acceptance, not a claim that the plugin is bundled here.
  • Public diff/commit-message scan and screenshot privacy inspection passed. Production settings and other user profiles were not changed. Native Windows/macOS and Nix execution were not rerun locally.

Setup is trusted plugin code, not a sandbox. Saved enablement does not hot-reload cached conversations; restart the owning backend to activate. CI for this follow-up is tracked on the current head; older CI results below are historical.

What does this PR do?

Lets trusted plugins own session-specific execution and desktop UI without mutating the process environment, patching Hermes internals, or treating the focused chat as the owner of every session.

The concrete consumer is an external private-desktop plugin: each session needs its own terminal/Cua environment and lifetime, while the desktop provides a status badge and an isolated viewer. The compositor, driver containment, streaming protocol, viewer authentication and plugin implementation stay outside Hermes. This PR adds the generic extension points only; it does not bundle that plugin or add a core model tool.

Related work

No issue is automatically closed. There is partial overlap with #51596 and #56782 (gateway slash-command provenance), #82776 (ambient gateway ContextVars), and #85314 (lifecycle payload consistency). This change needs explicit CLI/desktop/gateway ownership before a lazy session's first turn, plus execution leases and desktop viewers; it does not replace those PRs' other goals. The shared command/lifecycle contract should be reconciled during review rather than landing competing APIs silently.

Type of Change

  • New feature (additive plugin APIs)

Changes Made

  • Trusted identity and lifecycle: publish on_session_identity before lazy desktop/TUI create/resume returns; propagate distinct runtime, durable conversation, task and profile/home identities through existing hooks. Preserve resources across turn end and expose actual runtime finalization.
  • Slash commands: opt-in keyword context across CLI, messaging gateway and desktop/TUI, while retaining legacy handler(raw_args) callbacks and profile-scoped discovery.
  • Execution: immutable, profile-scoped registrations and revocable leases in hermes_cli/session_execution.py; exact environment set/unset and argv prefixes through local foreground, background/PTY and Cua child paths. No process-global environment mutation. Shell startup cannot override registered routing; readonly conflicts abort before user commands.
  • Computer use: private driver/runtime support, explicit desktop-only targeting and live input prohibition. Preserve existing approvals and bounded manifest bytes. Policy refusals remain non-retry denials rather than escalation hints. Close/reap owned daemon resources, including startup-failure paths.
  • Desktop: session-owned status-stack/tile/list contributions; explicit REST connection/profile scope; transient isolated preview actions and owned native viewer windows. No app preload, Node, ambient browser cookies or permission grants in viewers; stale contexts, unsafe URLs and lifecycle races fail closed.
  • Documentation and regression tests: public API examples and behavior tests are included. Ordinary unregistered host behavior remains the default.

How to Test

Fresh verification on this branch, based directly on upstream main at 006b1beb00d9:

Check Result
All changed Python test files via canonical runner, --file-retries 0 -W error -j 2 204 passed, 0 failed
Terminal/file/local/process-registry/computer-use regression lane, canonical runner, no retries 1,221 passed, 0 failed, 32 skipped
Changed desktop contribution/viewer tests 41 passed across 12 files
Renderer, Electron and E2E TypeScript projects npm run typecheck passed
Desktop production build npm run build passed, including assert-dist-built
Ruff, changed-file ESLint and whitespace checks Passed
Independent desktop and Python review, followed by focused re-review of reproduced fixes Passed; reviewed source hashes match the final tree

The Python lane uses real imports and temporary Hermes homes, actual shells/PTYs, native plugin discovery, lifecycle dispatch and inert protocol children. The desktop suite covers per-session ownership, first-open consent, viewer lifecycle and permission boundaries. Reproduction commands for the desktop lane are in apps/desktop/docs/plugin-session-viewers.md; backend commands/contracts are in docs/session-execution-context-api.md and docs/session-hook-identity-api.md.

The external consumer's real Linux compositor/Cua integration suite was also rerun against this upstream-based host: 112 passed, 0 failed, 5 environment-gated skips. That separate consumer is not bundled in this PR, so this is supplementary local evidence, not an in-tree CI gate. Earlier assembled development-app tests exercised dual sessions, Watch/takeover/return and locked-screen operation; those were on the original companion build, not a fresh full-GUI rerun of this port.

Lanes overlap; do not sum them. A broader 128-file plugin/lifecycle lane returned 1,933 passed, 16 failed, 3 skipped. All 16 failures (Hindsight and FAL provider fixtures) reproduced on the untouched upstream base, with an identical failing-test set. The one additional observer test initially rejected additive identity fields; it now checks the preserved semantic fields and unknown-identity defaults and passes warning-strict. The entire upstream suite and native Windows/macOS acceptance were not rerun. Existing platform/environment skips are not counted as passes.

CI follow-up

Commit fa6e9ac63155 explicitly rejects private runtime/desktop ownership validation when POSIX UID support is unavailable, without disabling generic execution routing or bypassing ownership checks. Added capability-loss regressions and native Windows coverage; independent review passed.

GitHub CI run 33984737693 passed, including the All required checks pass gate:

  • Full Python suite: 45,086 passed, 0 failed, 442 skipped.
  • Python E2E: 63 passed, 7 skipped.
  • Native Windows lane: 174 passed, 1 skipped, 1,567 deselected, including both new private-ownership cases.
  • Windows-footgun lint, JS/TS, macOS, docs, Docker builds and Nix checks passed. Skipped jobs are not claimed as executed.

The earlier Relay finalizer timeout also reproduced intermittently on the untouched upstream base, with native Relay installed and retries disabled. No Relay code, test timeout, assertion, or retry policy was changed to obtain this green run; the pre-existing scheduling-sensitive test remains outside this feature fix. Local expanded warning-strict resource-lifecycle tests were not universally green and are not represented by the hosted CI results above.

Boundaries

  • Registration is trusted cooperative routing, not an OS sandbox. External launchers own containment and already-running terminal children.
  • Viewer actions do not implement a remote tunnel or attach gateway credentials.
  • Electron does not offer a supported per-window Linux app class here. Native viewers use a locked, host-prefixed title and inactive reveal; no global app identity change.
  • No new runtime dependencies, global driver installation, default plugin activation, user configuration changes or bundled private-desktop implementation.

Checklist

  • Read the contributing guide and searched related PRs; overlap is called out above.
  • Conventional commit; only this feature's changes, directly on upstream (no personal-fork ancestry).
  • Added behavioral tests and reran relevant suites on Linux.
  • Updated API documentation; no configuration keys or model-tool schemas added.
  • Considered cross-platform impact; native acceptance limitations are explicit.
  • Checked the public diff for credentials, private paths, session identifiers and unrelated data. Test credentials are inert fixtures only.
  • Entire repository suite and native Windows/macOS tests run locally (not claimed).

@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/plugins Plugin system and bundled plugins comp/desktop Electron desktop app (apps/desktop/*) comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard comp/gateway Gateway runner, session dispatch, delivery comp/tui Terminal UI (ui-tui/ + tui_gateway/) comp/tools Tool registry, model_tools, toolsets tool/terminal Terminal execution and process management sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state labels Sep 5, 2026
@Enough1122

Copy link
Copy Markdown

AI code review — automated review for reference; please use your judgment.

Summary: Very large PR (86 files): plugin hooks/commands now carry dispatch-owned session identity (profile-scoped, never ambient), plus session-scoped child-process execution routing and isolated desktop viewers. Focused review on the security-sensitive core below; UI/electron/test files skimmed.

Findings (Non-blocking):

  • hermes_cli/plugins_command.py:21 — invoke_plugin_command forwards only opted-in kwargs, leaves awaitables to the caller, and never retries a handler TypeError (could have mutated state). All three choices are correct.
  • hermes_cli/session_hook_context.py:12 — hook_profile_scope correctly resets the home override in finally, and agent_session_identity degrades to None fields (never a sibling session's identity) for legacy agents. The None-identity path relies on downstream hooks tolerating profile=None; worth a grep to confirm no Path(None) lurks, but tests cover the main flows.
  • hermes_cli/session_execution.py:38 — _runtime_identity enforces owned private dir (uid + 0o077 mask) and command_prefix requires absolute paths with no shell text. Good. Socket path length guard (104 bytes, under the 108 Linux limit) in cua_backend_daemon.py is a nice touch.
  • tools/computer_use/cua_backend.py:104 — permission env keys are stripped from the inherited env and re-applied authoritatively (sanitize_cua_child_env), so a session context can't smuggle CUA_DRIVER_DANGEROUSLY_BYPASS_APPROVALS in. Correct design; keep that authoritative-keys list in sync if new permission knobs are added.
  • run_agent.py:388 — reset_session_state rotates _plugin_session_identity with stored_session_id set to the current session; confirm that semantic (stored == live right after reset) matches what consumers expect, since it differs from a resumed session where stored/live diverge.

Verdict: Non-blocking. Security design looks sound (no ambient identity, no env inheritance for secrets/permissions); remaining items are verification nits.

@Zeus-Deus

Copy link
Copy Markdown
Author

Follow-up draft: #104567 proposes Realms as an optional plugin, disabled by default. Merge #103690 first; the plugin draft depends on these generic APIs and will need rebasing/retesting afterward. This PR remains generic and can merge independently of the plugin proposal.

Every other section in the composer status stack is self-delimiting:
status groups carry a caret + icon + label header, the billing wall and
session control bring their own chrome. A plugin's contribution is raw
content with none of that, and the slot also inset it by 4px where the
rest of the stack uses 8px. Under another section it therefore read as
that section's footnote rather than as its own status.

Align the row with the stack's gutter and give it one hairline, only when
a section actually precedes it -- a lone plugin row keeps no stray line
above it, and sections that already have headers are not divided by a
line they do not need.
@Zeus-Deus

Copy link
Copy Markdown
Author

Superseded by #104567, which now carries these generic plugin session surfaces (execution targets, session hook identity, plugin setup and Desktop session viewers) as one core PR on current main. The Realms plugin that used them ships as a standalone plugin: https://github.com/Zeus-Deus/hermes-realms. Closing this one so there is a single place to review.

@Zeus-Deus Zeus-Deus closed this Sep 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard comp/desktop Electron desktop app (apps/desktop/*) comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins comp/tools Tool registry, model_tools, toolsets comp/tui Terminal UI (ui-tui/ + tui_gateway/) P3 Low — cosmetic, nice to have sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state tool/terminal Terminal execution and process management type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants