Skip to content

feat(app): embed isolated Hermes profile sessions - #220

Open
Cyb3rb1ade wants to merge 41 commits into
youssofal:mainfrom
Cyb3rb1ade:codex/embedded-hermes-agent-selection-pr
Open

feat(app): embed isolated Hermes profile sessions#220
Cyb3rb1ade wants to merge 41 commits into
youssofal:mainfrom
Cyb3rb1ade:codex/embedded-hermes-agent-selection-pr

Conversation

@Cyb3rb1ade

@Cyb3rb1ade Cyb3rb1ade commented Aug 2, 2026

Copy link
Copy Markdown

What

  • adds Hermes profile selection in Settings and saved session/agent selection in the native MTPLX UI
  • lets a selected profile accept a first prompt immediately and creates the new Hermes agent on first send
  • launches an MTPLX-owned hermes -p <profile> serve --isolated sidecar for the selected profile
  • connects through authenticated gateway RPC for session discovery, creation, resume, prompt streaming, tools, and approval prompts
  • persists profile/session selection without changing shared Hermes routing
  • includes the approved design and implementation notes

Isolation and lifecycle guarantees

  • applies endpoint, key, and model overrides only to the MTPLX-owned sidecar process
  • leaves the Root Gateway, Telegram routing, and foreign Hermes processes untouched
  • preserves the selected profile config.yaml and .env byte-identically
  • keeps externally active sessions visible but read-only and offers a fresh session instead
  • records exact process identity and ownership before teardown or orphan cleanup
  • fails closed for ambiguous routing, ownership, request IDs, and approvals
  • restores normal behavior by ending only the marked MTPLX sidecar when switching profiles or exiting MTPLX

Validation

  • swift test --scratch-path /tmp/mtplx-hermes-textfield-tests --filter Hermes: 134 passed, 0 failed
  • swift test --scratch-path /tmp/mtplx-hermes-textfield-tests: 663 executed, 1 skipped, 0 failed
  • swift build --scratch-path /tmp/mtplx-hermes-textfield-build --product MTPLXApp: passed with Xcode-beta
  • uv build --wheel --out-dir dist: passed
  • scripts/fresh_venv_smoke.sh: passed
  • git diff --check upstream/main...HEAD: passed
  • required Python selection: 251 passed, 2 failed because upstream tests still expect the former Qwen default while current upstream/main uses Ornith; this PR changes no Python or Python-test files

Scope

This branch is rebuilt directly on current upstream/main and contains only the Hermes app integration, its Swift tests, and the corresponding design/plan documents. Retrieval, embeddings, reranking, packaged-runtime, and local build-environment commits are deliberately excluded.

@Cyb3rb1ade
Cyb3rb1ade requested a review from youssofal as a code owner August 2, 2026 00:27

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8f99a7279e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +968 to +972
HermesOrphanSidecarScanner.isVerifiedPostLaunchIdentity(
identity,
spec: spec,
profileName: profile.name,
hermesHome: hermesHome

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Validate console entrypoints against the executable install

When hermes is a Python console script resolved from PATH or the explicitly searched ~/.local/bin, its script entrypoint is normally outside the profile-data directory ~/.hermes (and may itself be a symlink). Passing hermesHome here makes isVerifiedPostLaunchIdentity reject that otherwise valid process, so startup reaches the readiness sentinel and is then killed with “process identity could not be verified.” Validate against the resolved executable/installation location rather than the Hermes data home.

Useful? React with 👍 / 👎.

Comment on lines +199 to +200
while process.isRunning && Date() < termDeadline {
Thread.sleep(forTimeInterval: 0.05)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Move sidecar termination waits off the main actor

When a sidecar takes time to honor SIGTERM, this polling loop blocks for up to 2 seconds, followed by another 0.5 seconds after SIGKILL. HermesAgentStore is @MainActor and invokes stop() synchronously from overlay shutdown and profile switching, so closing Hermes or changing profiles can freeze the entire app UI for the full timeout; perform the wait asynchronously or on a background executor.

Useful? React with 👍 / 👎.

Comment on lines +1929 to +1931
private static func stderrSecrets(for spec: HermesServeLaunchSpec) -> [String] {
Array(Set(spec.environment.values + [spec.token]))
.filter { !$0.isEmpty }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Redact only secret-bearing environment values

On every sidecar startup failure, this treats every inherited and generated environment value as a secret. The launch environment always contains one-character values such as HERMES_YOLO_MODE=0/1 and HERMES_MTPLX_SHOW_REASONING=0/1, so every matching digit in stderr is replaced with [redacted]; ordinary values such as HOME, PATH, and the model name are also erased. This can make the only startup diagnostic unusable, so restrict the redaction list to actual credentials and tokens.

Useful? React with 👍 / 👎.

Hermes gives a profile's persisted model.provider precedence over
HERMES_INFERENCE_PROVIDER, so an embedded launch could inherit an
unrelated provider (for example openai-codex). Set
HERMES_TUI_PROVIDER=custom in the launch env dict, the
processEnvironment lane, the dotenv profile, and the shell export
block, and pin the override in the env and dotenv tests.
The Hermes CLI writes base_url: '' for provider profiles without a
custom endpoint (for example openai-codex). The routing parser rejected
the quoted empty scalar, failed the whole model block, and marked the
profile unavailable — disabling it in the picker and hiding its
sessions. A quoted empty string is now a valid empty scalar and an
empty base_url is treated the same as an omitted one. Regression test
pins the openai-codex profile shape.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant