Skip to content

Hermes integration treats external config changes as whole-file conflicts and risks destructive clobber on replace #3989

Closed

Description

@rrmlima

Client or integration

Other

Area

Dashboard

Summary

Hermes Agent is an autonomous multi-provider agent whose configuration (~/.hermes/config.yaml) typically hosts multiple providers (e.g., Command Code, OpenCode, local models, auxiliary vision models) alongside user comments and runtime settings.

In src/clients/config-export.ts, the Hermes export is documented with the clear design invariant:
"Hermes ~/.hermes/config.yaml. We emit ONLY the provider entry — never model.default — because hijacking the user's main model is not what a connect action asks for."

However, in src/integrations/registry.ts, hermes was registered without sourcePreservingYaml: { path: ["providers", "opencodex"] }. Consequently, whenever an operator edits ~/.hermes/config.yaml to configure sibling providers, auxiliary models, or comments, classifyIntegration treats the modification as a whole-file conflict (foreign-edit or unowned-key).

In the dashboard UI, this locks the integration toggle and presents a destructive restore prompt ("Replace") warning that the file will be replaced from a previous snapshot. If confirmed, the user loses all non-OpenCodex providers and customized settings.

Reproduction

  1. Have a valid ~/.hermes/config.yaml containing sibling providers (e.g., commandcode-oauth, opencode-zen) and an auxiliary vision model configuration.
  2. Open the OpenCodex dashboard at http://127.0.0.1:10100/ and navigate to the Integrations tab.
  3. Observe that Hermes reports state: "conflict" with reason unowned-key or foreign-edit instead of recognizing the sibling configuration as independent unowned content.
  4. Clicking the integration presents a modal offering to Replace/Restore the configuration from a snapshot.
  5. If the operator confirms the replace, the entire config.yaml is overwritten by the snapshot, discarding all external providers and settings.

Version

@bitkyc08/opencodex 2.47.0 (and dev commit 2ee9019)

Operating system

Ubuntu 24.04 LTS (Linux 6.8.0-134-generic x86_64)

Provider and model

N/A (Client integrations subsystem)

Logs or error output

{
  "clientId": "hermes",
  "state": "conflict",
  "installed": true,
  "configPath": "/root/.hermes/config.yaml",
  "reason": "unowned-key",
  "snapshotCount": 0,
  "retentionDegraded": false
}

Screenshots and supporting files

Observed in dashboard Integrations table: Hermes row enters conflict state with foreign-edit / unowned-key, locking ordinary toggle and requiring a destructive full-file restore.

Redacted configuration

model:
  default: meituan/LongCat-2.0:free
providers:
  commandcode-oauth:
    models: [ ... ]
  opencode-zen:
    models: [ ... ]
  opencodex:
    api: http://127.0.0.1:10100/v1
    api_key: ${OPENCODEX_HERMES_API_KEY}

Checks

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

Activity

  1. added
    bugSomething isn't working
    account-poolOAuth, credentials, Codex pool, quota, failover, plans
    guiDashboard, tray, settings UI
    on Sep 8, 2026
  2. lidge-jun commented on Sep 8, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 58 / 80

    이 이슈는 Hermes Agent 설정 파일(~/.hermes/config.yaml)을 OpenCodex 대시보드 Integrations가 파일 전체 소유물처럼 취급해서, 사용자가 넣은 다른 provider·주석·보조 모델이 있으면 conflict로 잠그고 “Replace”로 통째 덮어쓸 위험이 있다는 보고입니다. 지금 dev HEAD(4d4629024)를 보면 원인 설명과 코드가 맞습니다. src/clients/config-export.ts의 Hermes 생성기는 “provider 항목만 넣고 model.default는 건드리지 않는다”고 명시합니다. 그런데 src/integrations/registry.ts의 hermes 스펙에는 OMP에 있는 sourcePreservingYaml이 없습니다. OMP는 providers.opencodex만 패치하고, DSH는 llm-pi-ai.providers.opencodex만 패치합니다. Hermes만 같은 YAML인데 whole-document 분류로 남아, sibling 키가 unowned-key / foreign-edit가 됩니다. 재현 JSON의 state: "conflict", reason: "unowned-key"는 그 경로와 일치합니다.

    왜 지금 중요한가. Hermes는 이슈 본문대로 multi-provider가 기본에 가깝습니다. conflict 모달의 Replace는 스냅샷으로 파일 전체를 되돌리므로, OpenCodex 연결을 “고치려다” Command Code·Zen·비전 모델·주석을 지울 수 있습니다. 대시보드 Integrations UX와 export 불변조건이 어긋난 상태입니다. types.ts/config.ts 대분할과는 무관하고, preview 배포 이슈도 아닙니다. 수정은 새 프로토콜이 아니라 레지스트리에 OMP와 같은 source-preserving 선언을 추가하는 쪽입니다.

    이미 수정 PR이 있습니다. #3990(feat(integrations): support source-preserving YAML for Hermes Agent)이 정확히 hermes에 sourcePreservingYaml: { path: ["providers", "opencodex"] }를 넣고, 상태/writer 회귀와 docs를 고치며 이 이슈를 Closes로 가리킵니다. 따라서 이 이슈에서 별도 설계 토론을 길게 열 필요는 낮고, #3990의 draft·CI·체크리스트를 마감하는 쪽이 본선입니다. 2.47.0에서 관측했다는 버전 메모는 HEAD 2.48.0에서도 hermes 레지스트리 누락이 그대로라 유효합니다.

    경로 src/integrations/registry.ts (hermes 항목) - HEAD에 sourcePreservingYaml 없음이 이슈 원인과 일치한다
    경로 src/clients/config-export.ts (Hermes provider-only emit) - export 불변조건과 registry 소유 범위가 어긋난 상태다
    경로 대시보드 Integrations Replace 모달 - conflict + confirmDrift 경로가 파일 전체 복원이라 파괴적이다. source-preserving으로 conflict가 사라지면 모달 자체가 안 떠야 한다
    경로 이슈 재현 unowned-key - sibling provider를 “우리 조각 밖”으로 본 결과로 해석하는 것이 맞다
    경로 #3990 - 이 이슈의 직접 수정 PR이며 아직 draft다. 이슈만 따로 패치할 이유는 없다

    메인테이너의 판단이 필요한 지점

    • #3990이 머지되기 전에 이슈에 help wanted 등을 붙일지, 아니면 PR 트래킹만으로 충분한지
    • Replace로 이미 설정을 잃어버린 사용자에게 복구 안내(스냅샷/백업)를 이슈에 남길지
    • Hermes 외에 같은 YAML whole-document 함정(OpenClaw 등)을 후속으로 볼지(지금은 Hermes path가 OMP와 같아 우선순위가 명확)

    너의 추천
    새 패치를 이 이슈에 붙이지 말고 #3990을 ready·CI 마감 후 dev에 머지하세요. 머지되면 Closes로 이 이슈를 닫으면 됩니다. 중복 수정 PR이 오면 close-don't-rebase로 #3990에 모으세요.

    이 댓글은 grok-bot이 작성했습니다

  3. lidge-jun commented on Sep 8, 2026

    @lidge-jun
    Owner

    Fixed on dev.

    INTEGRATION_CLIENTS.hermes now declares sourcePreservingYaml: { path: ["providers", "opencodex"] }
    at src/integrations/registry.ts:193, so classifyIntegration scopes ownership to that subtree.
    Sibling providers, comments, and auxiliary models in a shared ~/.hermes/config.yaml no longer
    trigger a foreign-edit / unowned-key whole-file conflict or the destructive Replace prompt.

    This landed via #4030 as a0e794d1d ("feat(integrations): support source-preserving YAML for
    Hermes Agent (#3989)"), carrying your commit from #3990 with git cherry-pick -x. The issue was
    simply never closed alongside it.

    Thank you for the report — naming the missing registry field is what made this a one-line fix.

    Closing as fixed. If a multi-provider Hermes config still reports conflict on a build from current
    dev, please reopen with the state / reason JSON and your ocx version.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    account-poolOAuth, credentials, Codex pool, quota, failover, plansbugSomething isn't workingguiDashboard, tray, settings UI

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions