hermes(chat): observe-only enforcement and honest tool capabilities

Real traffic showed the first enforcement pass blocking core assistant
faculties: skills listing and the sandboxed Python classified as
unknown external side effects, browsing denied by default, with no
approval surface in the chat flow. Enforcement returns to observe-only
fleet-wide while the approvals UX and default grants are reworked, and
the capability map now tells the truth about the real toolset: the
Python sandbox is internal shell work, skills/todo/clarify/vision are
reads, browsing is network (medium), image generation writes an
artifact through the trusted broker. Unknown tools remain fail-closed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BvMSXH8VH2tMWXanb8SJdf
This commit is contained in:
jenkins 2026-08-24 10:46:54 -03:00
parent 4765f8da2a
commit 1793903f5e
3 changed files with 22 additions and 6 deletions

View File

@ -444,7 +444,7 @@ spec:
- {name: HUX_RUNTIME_ENABLED, value: "1"} - {name: HUX_RUNTIME_ENABLED, value: "1"}
# First rollout is observe-only until approval parking/resume is # First rollout is observe-only until approval parking/resume is
# connected to the upstream tool loop and proven live. # connected to the upstream tool loop and proven live.
- {name: HUX_TOOL_ENFORCEMENT, value: "1"} - {name: HUX_TOOL_ENFORCEMENT, value: "0"}
- {name: HUX_WORKER_KEY_FILE, value: /run/hermes-hux-worker/worker-key} - {name: HUX_WORKER_KEY_FILE, value: /run/hermes-hux-worker/worker-key}
- {name: HUX_SUBJECT_FILE, value: /run/hermes-hux-subject/subject} - {name: HUX_SUBJECT_FILE, value: /run/hermes-hux-subject/subject}
- {name: HUX_CONTEXT_KEY_FILE, value: /run/hermes-hux-context/context-key} - {name: HUX_CONTEXT_KEY_FILE, value: /run/hermes-hux-context/context-key}

View File

@ -26,14 +26,30 @@ EXACT = {
"memory": ToolPolicy("memory_write", "medium", False), "memory": ToolPolicy("memory_write", "medium", False),
"delegate_task": ToolPolicy("delegate", "high", False), "delegate_task": ToolPolicy("delegate", "high", False),
"terminal": ToolPolicy("shell", "high", True), "terminal": ToolPolicy("shell", "high", True),
"python": ToolPolicy("shell", "high", True), # The Python sandbox is isolated by design; it is internal shell work,
# unlike the real terminal above.
"python": ToolPolicy("shell", "medium", False),
"python_sandbox": ToolPolicy("shell", "medium", False),
# Core assistant faculties are reads, not side effects.
"skills": ToolPolicy("read_files", "low", False),
"clarify": ToolPolicy("read_files", "low", False),
"todo": ToolPolicy("read_files", "low", False),
"vision": ToolPolicy("read_files", "low", False),
# Browsing is the product; it is network, not an unknown side effect.
"browser": ToolPolicy("network", "medium", True),
"web": ToolPolicy("network", "medium", True),
"web_search": ToolPolicy("network", "medium", True),
# Image generation produces an artifact through the trusted broker.
"image_gen": ToolPolicy("artifact_write", "medium", False),
} }
PREFIXES = ( PREFIXES = (
(("web_", "browser_", "http_", "mcp_"), ToolPolicy("network", "high", True)), (("skill_", "skills_", "todo_", "clarify_"), ToolPolicy("read_files", "low", False)),
(("web_", "browser_", "http_", "mcp_"), ToolPolicy("network", "medium", True)),
(("send_", "mail_", "email_", "slack_", "discord_", "telegram_"), ToolPolicy("send_message", "high", True)), (("send_", "mail_", "email_", "slack_", "discord_", "telegram_"), ToolPolicy("send_message", "high", True)),
(("kubectl_", "flux_", "deploy_", "release_"), ToolPolicy("deploy", "high", True)), (("kubectl_", "flux_", "deploy_", "release_"), ToolPolicy("deploy", "high", True)),
(("image_", "video_", "vision_"), ToolPolicy("external_side_effect", "high", True)), (("image_",), ToolPolicy("artifact_write", "medium", False)),
(("video_", "vision_"), ToolPolicy("read_files", "low", False)),
(("artifact_",), ToolPolicy("artifact_write", "medium", False)), (("artifact_",), ToolPolicy("artifact_write", "medium", False)),
(("memory_",), ToolPolicy("memory_write", "medium", False)), (("memory_",), ToolPolicy("memory_write", "medium", False)),
(("delegate_", "subagent_"), ToolPolicy("delegate", "high", False)), (("delegate_", "subagent_"), ToolPolicy("delegate", "high", False)),

View File

@ -161,10 +161,10 @@ def test_context_key_handles_short_read(monkeypatch, tmp_path: Path):
("memory", "memory_write", "medium", False), ("memory", "memory_write", "medium", False),
("delegate_task", "delegate", "high", False), ("delegate_task", "delegate", "high", False),
("terminal", "shell", "high", True), ("terminal", "shell", "high", True),
("web_search", "network", "high", True), ("web_search", "network", "medium", True),
("send_email", "send_message", "high", True), ("send_email", "send_message", "high", True),
("kubectl_apply", "deploy", "high", True), ("kubectl_apply", "deploy", "high", True),
("image_generate", "external_side_effect", "high", True), ("image_generate", "artifact_write", "medium", False),
("artifact_create", "artifact_write", "medium", False), ("artifact_create", "artifact_write", "medium", False),
("memory_forget", "memory_write", "medium", False), ("memory_forget", "memory_write", "medium", False),
("subagent_spawn", "delegate", "high", False), ("subagent_spawn", "delegate", "high", False),