Skip to content

fix(tui): preserve config on save, surface orphaned auth credentials - #14275

Open
Societus wants to merge 1 commit into
NousResearch:mainfrom
Societus:fix/tui-config-preservation
Open

Societus wants to merge 1 commit into
NousResearch:mainfrom
Societus:fix/tui-config-preservation

Conversation

@Societus

Copy link
Copy Markdown
Contributor

Body

The TUI gateway writes config back to disk with raw yaml.safe_dump(), which strips comments and env-var templates like ${GLM_API_KEY}. Every time the TUI sets a display preference it silently destroys those parts of the user's config. This switches _save_cfg() to delegate to save_config() — the same atomic write path the CLI uses — so env-var templates, comments, and structure survive round-trips.

The second fix addresses orphaned credentials. When a custom provider is removed from config.yaml, its entries stay in auth.json. hermes auth list shows them (reads auth.json) but the interactive remove menu doesn't (reads config.yaml only). _get_custom_provider_names() now also scans auth.json for orphaned custom:* pool keys so they appear in the remove menu. Closes #14218.

Changes

  • tui_gateway/server.py: _save_cfg() delegates to save_config() with HERMES_HOME env var sync
  • hermes_cli/auth_commands.py: _get_custom_provider_names() merges orphaned auth.json entries

Testing

89 tests pass (TUI gateway server + auth commands). Config round-trip verified byte-identical on a 331-line config with custom_providers, mcp_servers, matrix config, and env-var templates.

…dentials

TUI gateway _save_cfg() used raw yaml.safe_dump() which stripped
comments, env-var templates, and didn't use atomic writes. Every TUI
preference change silently destroyed those parts of config.yaml.
Delegate to the existing save_config() from hermes_cli/config.py,
which handles comment preservation, env-var round-tripping, and
atomic writes via the same code path the CLI uses.

Also fixes NousResearch#14218: hermes auth stored credentials for custom providers
in auth.json, but removing the provider from config.yaml left orphaned
entries with no way to clean them up. The interactive remove menu now
merges auth.json custom:* pool keys with config.yaml providers so
orphans appear and can be removed.
@Societus

Copy link
Copy Markdown
Contributor Author

Initially thought this was the same issue as #14218 while investigating the TUI config destruction. Turns out the orphan problem has a separate root cause (provider removed from config.yaml, credentials stay in auth.json), but the config wipe cascade that #14276 prevents would actually mass-orphan credentials — a broken config.yaml plus any TUI interaction writes defaults to disk, stripping all custom_providers and leaving their auth.json entries stranded. The guard in #14276 blocks that write path so the broken config (custom_providers intact) stays on disk until repaired.

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/tui Terminal UI (ui-tui/ + tui_gateway/) comp/cli CLI entry point, hermes_cli/, setup wizard area/auth Authentication, OAuth, credential pools area/config Config system, migrations, profiles labels Apr 23, 2026
@alt-glitch

Copy link
Copy Markdown
Contributor

Competing with #14269 for the orphaned auth credentials fix (#14218). Also overlaps with #13357 (atomic config writes in TUI).

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for identifying the orphaned custom-pool cleanup gap. That auth issue still exists on current main, but the TUI config portion needs re-scoping before salvage.

Problems

  • Current _save_cfg() already uses atomic_config_write() at tui_gateway/server.py:1954-1957 (commit 123c6f3a2). The proposed save_config() replacement would not preserve arbitrary comments: save_config() performs a whole-file YAML serialization at hermes_cli/config.py:7202-7206; the comment-preserving helper is utils.py:296-305.
  • This PR adds no regression tests for the auth fix. The still-live path is _get_custom_provider_names() at hermes_cli/auth_commands.py:40-58, consumed by _pick_provider() at :633-647. Related #14269 has focused orphan-pool discovery and picker coverage worth retaining when salvaging.

Suggested changes

  • Keep and test the auth-only fix: seed an auth.json-only custom:* pool, assert it is offered by the picker, and verify it can be selected for removal.
  • Drop the stale TUI save hunk; handle comment preservation separately if it remains a required behavior.

This is an automated hermes-sweeper review.

Comment thread tui_gateway/server.py
@@ -340,15 +340,25 @@ def _load_cfg() -> dict:

def _save_cfg(cfg: dict):
global _cfg_cache, _cfg_mtime

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Current main has already replaced this path with atomic_config_write() at tui_gateway/server.py:1954-1957 (123c6f3a2). Please drop this stale substitution: save_config() still performs a whole-file YAML dump, so it does not preserve arbitrary existing comments.

@teknium1 teknium1 added sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 12, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools area/config Config system, migrations, profiles comp/cli CLI entry point, hermes_cli/, setup wizard comp/tui Terminal UI (ui-tui/ + tui_gateway/) P2 Medium — degraded but workaround exists sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Credential pool entries persist after custom_provider removal via hermes model — interactive remove menu doesn't show orphaned custom providers

3 participants