Repository navigation
Hermes integration treats external config changes as whole-file conflicts and risks destructive clobber on replace #3989
Description
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
- Have a valid
~/.hermes/config.yamlcontaining sibling providers (e.g.,commandcode-oauth,opencode-zen) and an auxiliary vision model configuration. - Open the OpenCodex dashboard at http://127.0.0.1:10100/ and navigate to the Integrations tab.
- Observe that Hermes reports
state: "conflict"with reasonunowned-keyorforeign-editinstead of recognizing the sibling configuration as independent unowned content. - Clicking the integration presents a modal offering to Replace/Restore the configuration from a snapshot.
- If the operator confirms the replace, the entire
config.yamlis 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
lidge-jun commentedon Sep 8, 2026
리뷰 · 우선순위 58 / 80
이 이슈는 Hermes Agent 설정 파일(
~/.hermes/config.yaml)을 OpenCodex 대시보드 Integrations가 파일 전체 소유물처럼 취급해서, 사용자가 넣은 다른 provider·주석·보조 모델이 있으면 conflict로 잠그고 “Replace”로 통째 덮어쓸 위험이 있다는 보고입니다. 지금devHEAD(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다. 이슈만 따로 패치할 이유는 없다
메인테이너의 판단이 필요한 지점
help wanted등을 붙일지, 아니면 PR 트래킹만으로 충분한지너의 추천
새 패치를 이 이슈에 붙이지 말고 #3990을 ready·CI 마감 후
dev에 머지하세요. 머지되면 Closes로 이 이슈를 닫으면 됩니다. 중복 수정 PR이 오면 close-don't-rebase로 #3990에 모으세요.이 댓글은 grok-bot이 작성했습니다
feat(integrations): support source-preserving YAML for Hermes Agent (l…
feat(integrations): support source-preserving YAML for Hermes Agent (l…
lidge-jun commentedon Sep 8, 2026
Fixed on
dev.INTEGRATION_CLIENTS.hermesnow declaressourcePreservingYaml: { path: ["providers", "opencodex"] }at
src/integrations/registry.ts:193, soclassifyIntegrationscopes ownership to that subtree.Sibling providers, comments, and auxiliary models in a shared
~/.hermes/config.yamlno longertrigger a
foreign-edit/unowned-keywhole-file conflict or the destructive Replace prompt.This landed via #4030 as
a0e794d1d("feat(integrations): support source-preserving YAML forHermes Agent (#3989)"), carrying your commit from #3990 with
git cherry-pick -x. The issue wassimply 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
conflicton a build from currentdev, please reopen with thestate/reasonJSON and yourocxversion.feat(integrations): support source-preserving YAML for Hermes Agent (l…