{"repo":"NousResearch/hermes-agent","public_id":"7058","display_label":"UTF-8 encoding fixes for Windows config/file reads","summary":"Multiple bug reports and fixes addressing UTF-8 encoding issues when reading config files, dashboard assets, and other I/O on Windows. Changes add explicit encoding declarations across CLI, web server, and config handling code.","subsystem":"hermes_cli","counts":{"members":7,"open_issues":0,"open_issues_distinct":0,"open_prs":0,"closed_issues":2,"merged_prs":2,"attempt_prs":3},"landed_fix":{"status":"merged_to_main","basis":"structural","pr":7174},"resolution":{"state":"partially_resolved","by":"pr-45937"},"freshness":{"state":"verified","last_verified_at":"2026-06-14T09:31:05+00:00","is_stale":false},"grouping":{"backbone":"STRUCTURAL_PARTIAL","link_density":0.2552380952380952},"fix_edges":[{"issue_number":7018,"pr_number":7174,"tier":"verified","basis":"superseded_ref","confidence":0.9,"recoverable_from_timeline":false},{"issue_number":7024,"pr_number":7174,"tier":"verified","basis":"superseded_ref","confidence":0.9,"recoverable_from_timeline":false},{"issue_number":7058,"pr_number":7174,"tier":"verified","basis":"superseded_ref","confidence":0.9,"recoverable_from_timeline":false},{"issue_number":45932,"pr_number":45937,"tier":"verified","basis":"closing_ref","confidence":0.95,"recoverable_from_timeline":true}],"members":[{"kind":"issue","number":7058,"title":"[Bug]: Failed to load config.yml in Windows","url":null,"state":"closed"},{"kind":"issue","number":45932,"title":"[Bug]消息网关 启动不了 咋解决?","url":null,"state":"closed"},{"kind":"pr","number":7063,"title":"fix(cli): Specify UTF-8 encoding when opening config file","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#7174","number":7174}],"category":"merged_via","implication":"superseded"},"merged":false},{"kind":"pr","number":7174,"title":"fix: four small CLI/config fixes (Bucket K salvage)","url":null,"state":"merged","close_reason":{"category":"merged","implication":"superseded"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["agent/rate_limit_tracker.py","agent/smart_model_routing.py","cli.py","hermes_cli/gateway.py"]},{"kind":"pr","number":13593,"title":"fix(encoding): add UTF-8 encoding for Windows compatibility (#7537, #8901, #7058)","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#13986","number":13986}],"category":"superseded_by_pr","implication":"superseded"},"merged":false,"is_fix_pr":true,"fix_tier":"suggested","fix_detail_withheld":true},{"kind":"pr","number":45937,"title":"fix: read dashboard spa assets as utf-8","url":null,"state":"merged","close_reason":{"category":"merged","implication":"superseded"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["hermes_cli/web_server.py","tests/hermes_cli/test_web_server.py"],"fix_hunks":[{"file":"hermes_cli/web_server.py","hunks":["@@ -10625,7 +10625,7 @@ def _serve_index(prefix: str = \"\"):\n         ``__HERMES_AUTH_REQUIRED__`` flag lets the SPA pick the right\n         auth scheme for /api/pty and /api/ws (ticket vs token).\n         \"\"\"\n-        html = _index_path.read_text()\n+        html = _index_path.read_text(encoding=\"utf-8\")\n         chat_js = \"true\" if _DASHBOARD_EMBEDDED_CHAT_ENABLED else \"false\"\n         gated = bool(getattr(app.state, \"auth_required\", False))\n         gated_js = \"true\" if gated else \"false\"","@@ -10675,7 +10675,7 @@ async def serve_css(filename: str, request: Request):\n         ):\n             return JSONResponse({\"error\": \"not found\"}, status_code=404)\n         prefix = _normalise_prefix(request.headers.get(\"x-forwarded-prefix\"))\n-        css = css_path.read_text()\n+        css = css_path.read_text(encoding=\"utf-8\")\n         if prefix:\n             for asset_dir in (\"/fonts/\", \"/fonts-terminal/\", \"/ds-assets/\", \"/assets/\"):\n                 css = css.replace(f\"url({asset_dir}\", f\"url({prefix}{asset_dir}\")"]},{"file":"tests/hermes_cli/test_web_server.py","hunks":["@@ -1857,6 +1857,45 @@ def test_path_traversal_dotdot_blocked(self):\n         if resp.status_code == 200:\n             assert \"FastAPI\" not in resp.text  # Should not serve the actual source\n \n+    def test_spa_assets_are_read_as_utf8(self, monkeypatch, tmp_path):\n+        from fastapi import FastAPI\n+        from starlette.testclient import TestClient\n+        import hermes_cli.web_server as ws\n+\n+        dist = tmp_path / \"web_dist\"\n+        assets = dist / \"assets\"\n+        assets.mkdir(parents=True)\n+        index_path = dist / \"index.html\"\n+        css_path = assets / \"app.css\"\n+        index_path.write_text(\"<html><head></head><body>cafe cafe</body></html>\", encoding=\"utf-8\")\n+        css_path.write_text(\"body::before { content: 'cafe'; }\", encoding=\"utf-8\")\n+\n+        original_read_text = Path.read_text\n+        seen_encodings = {}\n+\n+        def tracking_read_text(path_self, *args, **kwargs):\n+            if path_self == index_path:\n+                seen_encodings[\"index\"] = kwargs.get(\"encoding\")\n+            elif path_self == css_path:\n+                seen_encodings[\"css\"] = kwargs.get(\"encoding\")\n+            return original_read_text(path_self, *args, **kwargs)\n+\n+        monkeypatch.setattr(ws, \"WEB_DIST\", dist)\n+        monkeypatch.setattr(Path, \"read_text\", tracking_read_text)\n+        spa_app = FastAPI()\n+        ws.mount_spa(spa_app)\n+        spa_client = TestClient(spa_app)\n+\n+        index_resp = spa_client.get(\"/chat\")\n+        assert index_resp.status_code == 200\n+        assert \"cafe cafe\" in index_resp.text\n+\n+        css_resp = spa_client.get(\"/assets/app.css\", headers={\"x-forwarded-prefix\": \"/hermes\"})\n+        assert css_resp.status_code == 200\n+        assert \"content: 'cafe';\" in css_resp.text\n+\n+        assert seen_encodings == {\"index\": \"utf-8\", \"css\": \"utf-8\"}\n+\n     def test_set_model_main_nous_applies_gateway_defaults(self, monkeypatch):\n         \"\"\"Switching the main provider to Nous calls apply_nous_managed_defaults\n         (mirroring the CLI's post-model-selection Tool Gateway routing) and\n"]}]},{"kind":"pr","number":46017,"title":"fix(web_server): use UTF-8 encoding for dashboard reads on Windows","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#45937","number":45937}],"category":"duplicate_of","implication":"duplicate"},"merged":false}],"trust":{"default_tier":"verified","includes_suggested":false}}