[GH-ISSUE #3320] [Bug] Hermes setup fails to register REA through an aliased MCP server table #1190

Closed
opened 2026-10-15 18:31:52 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @coygeek on GitHub (Oct 14, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/3320

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Setup, packaging, or upgrade

Observed behavior

Approved Hermes setup cannot add REA when a valid YAML configuration defines its MCP server table through an alias. Setup accepts the configuration, passes preflight, and plans an update and its backup, but the approved apply exits 1 with status: "needs_human", Hermes status: "failed", reason: "write", and no applied actions. It suggests checking file permissions even though the same writable file supports backup creation and an equivalent explicit-mapping configuration succeeds.

The original configuration remains unchanged, and its .rea.backup matches the original bytes. With the same setup command in a fresh disposable home, replacing only the mcp_servers alias with its equivalent explicit mapping returns ready, exit 0, and an aligned Hermes registration. Both inputs were executed through the public CLI. No Hermes process was started; these observations concern REA's configuration transaction.

Reproduction

  1. Prepare a clean checkout and install the locked dependencies and built runtime:
git clone https://github.com/morluto/rea.git rea-hermes-alias-repro
cd rea-hermes-alias-repro
git checkout 8dde6370d0809ad04cda3342d4e6f290f48aa063
npm ci
npm run build:cached
  1. Run the following command from the repository root. It creates every configuration input inline in a disposable home, excludes ambient client-location overrides, and does not change the real user configuration:
python3 - <<'PYCODE'
import json
import os
from pathlib import Path
import subprocess
import tempfile

with tempfile.TemporaryDirectory() as directory:
    home = Path(directory) / "home"
    folder = home / ".hermes"
    folder.mkdir(parents=True)
    config = folder / "config.yaml"
    original = 'server_defaults: &servers\n  other:\n    command: other-server\nmcp_servers: *servers\n'
    config.write_text(original)
    environment = {
        "PATH": os.environ["PATH"],
        "HOME": str(home),
        "HOPPER_LAUNCHER_PATH": str(home / "absent-hopper"),
    }
    command = ["node", "scripts/rea.mjs", "setup", "--client", "hermes", "--skill=false", "--yes", "--json"]
    process = subprocess.run(command, env=environment, capture_output=True, text=True)
    report = json.loads(process.stdout)
    print(json.dumps({"exit": process.returncode, "status": report["status"], "clientStatus": report["clients"]["hermes"]["status"], "reason": report["clients"]["hermes"].get("reason"), "appliedActions": report["appliedActions"], "remediation": report.get("remediation")}))
    print("original preserved:", config.read_text() == original)
    print("backup matches:", Path(str(config) + ".rea.backup").read_text() == original)
PYCODE
  1. Observe the failed registration, unchanged original configuration, and exact backup shown under Relevant output or evidence.

  2. Repeat step 2 in a fresh disposable home with only the original assignment replaced by the following value. This is the equivalent explicit-mapping control that returned ready, exit 0, and an aligned Hermes registration:

original = 'server_defaults: &servers\n  other:\n    command: other-server\nmcp_servers:\n  other:\n    command: other-server\n'

The control's complete YAML input is:

server_defaults: &servers
  other:
    command: other-server
mcp_servers:
  other:
    command: other-server

Expected behavior

Setup should add an enabled REA entry to the accepted Hermes YAML configuration, preserve the other server and existing defaults, create a backup, and verify registration. An aliased mapping accepted by the configuration reader should not prevent approved registration. docs/client-configuration.md:226-230 promises an enabled Hermes registration while preserving comments and unrelated settings. docs/installation.md:59-60 promises preserved entries, backups, atomic replacement, and verified results.

Impact and scope

Impact is P2, supported. Users with an aliased Hermes MCP table cannot register REA through setup. The original configuration and backup remain intact, so this is a bounded onboarding failure. No analysis engine or running client is required to reproduce it.

A workaround is available. Replacing only the mcp_servers alias with its equivalent explicit mapping was executed in a fresh home and made setup succeed. The defaults and other-server settings can remain unchanged.

REA version

6.4.0 (main at 8dde6370d0)

Runtime and platform

Node.js 26.10.0 on macOS 27.0.1, using the built source-checkout CLI. The reproduction record does not specify the architecture.

Target and artifact context

Synthetic Hermes config.yaml with server_defaults: &servers, an unrelated other server using command: other-server, and mcp_servers: *servers. The configuration and exact .rea.backup were read back after failure. No binary target, analysis engine, or running Hermes client is required.

Interface

CLI

Earliest failure stage

Setup or provider admission

Relevant output or evidence

The executed CLI reproduction prints:

{"exit": 1, "status": "needs_human", "clientStatus": "failed", "reason": "write", "appliedActions": [], "remediation": "Agent configuration could not be updated. Check file permissions, then rerun setup."}
original preserved: True
backup matches: True

A separate executed call to the bundled YAML editor on the accepted failing fixture reports Expected YAML collection at mcp_servers. Remaining path: rea before a file can be published. The public CLI transaction failure is the primary evidence; the editor call and equivalent-mapping control corroborate it.

Typed outcome or recovery expected

Run setup on the aliased-table fixture. It must write and verify an enabled REA registration while preserving the resolved other-server and defaults settings and an exact backup. Repeat setup to verify idempotence. Keep the explicit-mapping control passing. Merely relabeling the permissions remediation or accepting a plan without applying it does not restore registration.

Analysis or suspected cause

Source-derived reasoning: src/application/SetupClientConfiguration.ts:282-302 serializes the approved update and reduces serialization exceptions to a write failure. src/application/HermesConfigurationYaml.ts:326-354 performs the edit, including document.setIn at line 351. The reader resolves the alias into a mapping, while the editor attempts to descend into the aliased mcp_servers node. The executed editor error and explicit-mapping control support this explanation; the source locators identify the transaction and edit boundaries.

Additional context

  • #2514, closed as completed, concerns comment-only and marker-only YAML rejected as an invalid root; this accepted nonempty mapping fails during alias editing.
  • #2515, closed as completed, concerns unrelated integer keys changing during successful YAML writes; this registration write fails and preserves the original bytes.
  • #1633, open, concerns Hermes first-run version warnings after configuration creation; this failure occurs in REA's registration transaction without starting Hermes.
  • #1521, closed as completed, concerns selecting the wrong sticky profile; this failure occurs in the correctly selected configuration file.
  • #1606, closed as completed, concerns valid environment overrides disappearing during a successful registration update; this alias-triggered update fails before publishing a configuration change.
Originally created by @coygeek on GitHub (Oct 14, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/3320 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Setup, packaging, or upgrade ### Observed behavior Approved Hermes setup cannot add REA when a valid YAML configuration defines its MCP server table through an alias. Setup accepts the configuration, passes preflight, and plans an update and its backup, but the approved apply exits 1 with `status: "needs_human"`, Hermes `status: "failed"`, `reason: "write"`, and no applied actions. It suggests checking file permissions even though the same writable file supports backup creation and an equivalent explicit-mapping configuration succeeds. The original configuration remains unchanged, and its `.rea.backup` matches the original bytes. With the same setup command in a fresh disposable home, replacing only the `mcp_servers` alias with its equivalent explicit mapping returns `ready`, exit 0, and an aligned Hermes registration. Both inputs were executed through the public CLI. No Hermes process was started; these observations concern REA's configuration transaction. ### Reproduction 1. Prepare a clean checkout and install the locked dependencies and built runtime: ```sh git clone https://github.com/morluto/rea.git rea-hermes-alias-repro cd rea-hermes-alias-repro git checkout 8dde6370d0809ad04cda3342d4e6f290f48aa063 npm ci npm run build:cached ``` 2. Run the following command from the repository root. It creates every configuration input inline in a disposable home, excludes ambient client-location overrides, and does not change the real user configuration: ```bash python3 - <<'PYCODE' import json import os from pathlib import Path import subprocess import tempfile with tempfile.TemporaryDirectory() as directory: home = Path(directory) / "home" folder = home / ".hermes" folder.mkdir(parents=True) config = folder / "config.yaml" original = 'server_defaults: &servers\n other:\n command: other-server\nmcp_servers: *servers\n' config.write_text(original) environment = { "PATH": os.environ["PATH"], "HOME": str(home), "HOPPER_LAUNCHER_PATH": str(home / "absent-hopper"), } command = ["node", "scripts/rea.mjs", "setup", "--client", "hermes", "--skill=false", "--yes", "--json"] process = subprocess.run(command, env=environment, capture_output=True, text=True) report = json.loads(process.stdout) print(json.dumps({"exit": process.returncode, "status": report["status"], "clientStatus": report["clients"]["hermes"]["status"], "reason": report["clients"]["hermes"].get("reason"), "appliedActions": report["appliedActions"], "remediation": report.get("remediation")})) print("original preserved:", config.read_text() == original) print("backup matches:", Path(str(config) + ".rea.backup").read_text() == original) PYCODE ``` 3. Observe the failed registration, unchanged original configuration, and exact backup shown under Relevant output or evidence. 4. Repeat step 2 in a fresh disposable home with only the `original` assignment replaced by the following value. This is the equivalent explicit-mapping control that returned `ready`, exit 0, and an aligned Hermes registration: ```python original = 'server_defaults: &servers\n other:\n command: other-server\nmcp_servers:\n other:\n command: other-server\n' ``` The control's complete YAML input is: ```yaml server_defaults: &servers other: command: other-server mcp_servers: other: command: other-server ``` ### Expected behavior Setup should add an enabled REA entry to the accepted Hermes YAML configuration, preserve the other server and existing defaults, create a backup, and verify registration. An aliased mapping accepted by the configuration reader should not prevent approved registration. `docs/client-configuration.md:226-230` promises an enabled Hermes registration while preserving comments and unrelated settings. `docs/installation.md:59-60` promises preserved entries, backups, atomic replacement, and verified results. ### Impact and scope Impact is P2, supported. Users with an aliased Hermes MCP table cannot register REA through setup. The original configuration and backup remain intact, so this is a bounded onboarding failure. No analysis engine or running client is required to reproduce it. A workaround is available. Replacing only the `mcp_servers` alias with its equivalent explicit mapping was executed in a fresh home and made setup succeed. The defaults and other-server settings can remain unchanged. ### REA version 6.4.0 (main at 8dde6370d0809ad04cda3342d4e6f290f48aa063) ### Runtime and platform Node.js 26.10.0 on macOS 27.0.1, using the built source-checkout CLI. The reproduction record does not specify the architecture. ### Target and artifact context Synthetic Hermes `config.yaml` with `server_defaults: &servers`, an unrelated `other` server using `command: other-server`, and `mcp_servers: *servers`. The configuration and exact `.rea.backup` were read back after failure. No binary target, analysis engine, or running Hermes client is required. ### Interface CLI ### Earliest failure stage Setup or provider admission ### Relevant output or evidence The executed CLI reproduction prints: ```text {"exit": 1, "status": "needs_human", "clientStatus": "failed", "reason": "write", "appliedActions": [], "remediation": "Agent configuration could not be updated. Check file permissions, then rerun setup."} original preserved: True backup matches: True ``` A separate executed call to the bundled YAML editor on the accepted failing fixture reports `Expected YAML collection at mcp_servers. Remaining path: rea` before a file can be published. The public CLI transaction failure is the primary evidence; the editor call and equivalent-mapping control corroborate it. ### Typed outcome or recovery expected Run setup on the aliased-table fixture. It must write and verify an enabled REA registration while preserving the resolved other-server and defaults settings and an exact backup. Repeat setup to verify idempotence. Keep the explicit-mapping control passing. Merely relabeling the permissions remediation or accepting a plan without applying it does not restore registration. ### Analysis or suspected cause Source-derived reasoning: `src/application/SetupClientConfiguration.ts:282-302` serializes the approved update and reduces serialization exceptions to a write failure. `src/application/HermesConfigurationYaml.ts:326-354` performs the edit, including `document.setIn` at line 351. The reader resolves the alias into a mapping, while the editor attempts to descend into the aliased `mcp_servers` node. The executed editor error and explicit-mapping control support this explanation; the source locators identify the transaction and edit boundaries. ### Additional context - [#2514](https://github.com/morluto/rea/issues/2514), closed as completed, concerns comment-only and marker-only YAML rejected as an invalid root; this accepted nonempty mapping fails during alias editing. - [#2515](https://github.com/morluto/rea/issues/2515), closed as completed, concerns unrelated integer keys changing during successful YAML writes; this registration write fails and preserves the original bytes. - [#1633](https://github.com/morluto/rea/issues/1633), open, concerns Hermes first-run version warnings after configuration creation; this failure occurs in REA's registration transaction without starting Hermes. - [#1521](https://github.com/morluto/rea/issues/1521), closed as completed, concerns selecting the wrong sticky profile; this failure occurs in the correctly selected configuration file. - [#1606](https://github.com/morluto/rea/issues/1606), closed as completed, concerns valid environment overrides disappearing during a successful registration update; this alias-triggered update fails before publishing a configuration change.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#1190
No description provided.