Summary
skill_creator's prompt names node_exec and npm_exec, but the agent can no longer call either. It carries a twelve-tool belt and, by the fleet prompt guard's measure, names none of the tools it can actually call.
Found while triaging #6486. Verified at 0f1ecc9d28d85289ee3f87ade13156be02ffbd28.
The failing guard, and why it matters
crates/openhuman-core/src/agent/registry/agents/fleet_prompt_tests.rs:344-368:
test agent::registry::agents::fleet_prompt_tests::every_prompt_names_at_least_one_tool_it_can_call ... FAILED
assertion `left == right` failed: agents that carry tools but whose prompt names none of them
left: ["tools_agent", "tool_maker", "skill_creator", "critic", "archivist", "skill_setup"]
right: ["tools_agent", "tool_maker", "critic", "archivist", "skill_setup"]
skill_creator has joined the silent set. The test's own docstring states the defect it exists to catch:
An agent with a belt must be told about at least one tool on it.
Catches a belt narrowed out from under its prompt, which otherwise reads as an improvement: the tool bytes fall and nothing else moves.
That is what has happened.
The mechanism
skill_creator carries a large named belt (registry/agents/skill_creator/agent.toml): shell, file_read, file_write, git_operations, node_exec, npm_exec, python_exec, grep, glob, list, edit, apply_patch, …
Its prompt (prompt.md) backticks exactly two tool names: node_exec and npm_exec — both on that belt.
The guard's predicate is can_call(def, name, &universe) && prompt.contains("{name}") (fleet_prompt_tests.rs:361), and can_call (:130-143) returns false when is_withheld_from(&def.id, tool) — i.e. when the tool has been withheld into a toolpack for that agent, reachable only via use_skill (tools/toolpacks/ops.rs:134-140).
So the two tools the prompt names as directly callable are no longer directly callable, and no other tool on the belt is named. The prompt and the belt have come apart.
Impact: the model is instructed to call tools it cannot call, and is told nothing about the ones it can. The failure mode is a wasted turn and a confused recovery, not an error — which is exactly why it needs a test rather than a bug report from a user.
Likely origin
skill_creator's belt and prompt last changed in a63c2b885 — PR #6436, hermes-prompt-diet (2026-09-22). A prompt-size reduction is precisely the shape the guard's docstring predicts: "the tool bytes fall and nothing else moves."
This is a recurrence, not a novelty. The same pattern has been seen before in this repo: a byte win that concealed a capability loss, visible only by diffing the name lists rather than the totals. That argues for a name-list diff as a standing step in any prompt-diet change, not just a fix here.
I have not bisected to confirm #6436 is the exact commit that flipped it — the belt/prompt last-touch is circumstantial, and the withholding could equally have been introduced by a toolpack change on the other side.
The fix that must NOT be applied
fleet_prompt_tests.rs:332 carries an allowlist:
const NAMES_NO_TOOL: &[&str] = &["tools_agent", "tool_maker", "critic", "archivist"];
Adding skill_creator to it would make the suite pass and silence the one assertion in it that is doing its job. The guard is not wrong; the prompt/belt pairing is. Flagging explicitly because that is the cheapest-looking fix and it is the wrong one.
Suggested resolution
Either:
- update the prompt to name tools
skill_creator can actually call (and describe the packed ones as reachable via use_skill, if that is the intent); or
- un-withhold
node_exec/npm_exec for skill_creator if they were packed by accident.
Which one depends on whether the withholding was deliberate — a question for whoever owns the toolpack split.
Reproduction
RUST_MIN_STACK=67108864 cargo test --manifest-path Cargo.toml \
-p openhuman --lib -- every_prompt_names_at_least_one_tool_it_can_call
Fails deterministically on a clean checkout of main, including in isolation. Note that no CI lane on main runs this test — see #6486 and #5021 — which is why it has gone unnoticed. It sits in a sibling module of a scope ci-lite.yml does cover (agent::registry::agents::loader::), which makes the area look covered when it is not.
Summary
skill_creator's prompt namesnode_execandnpm_exec, but the agent can no longer call either. It carries a twelve-tool belt and, by the fleet prompt guard's measure, names none of the tools it can actually call.Found while triaging #6486. Verified at
0f1ecc9d28d85289ee3f87ade13156be02ffbd28.The failing guard, and why it matters
crates/openhuman-core/src/agent/registry/agents/fleet_prompt_tests.rs:344-368:skill_creatorhas joined the silent set. The test's own docstring states the defect it exists to catch:That is what has happened.
The mechanism
skill_creatorcarries a large named belt (registry/agents/skill_creator/agent.toml):shell,file_read,file_write,git_operations,node_exec,npm_exec,python_exec,grep,glob,list,edit,apply_patch, …Its prompt (
prompt.md) backticks exactly two tool names:node_execandnpm_exec— both on that belt.The guard's predicate is
can_call(def, name, &universe) && prompt.contains("{name}")(fleet_prompt_tests.rs:361), andcan_call(:130-143) returns false whenis_withheld_from(&def.id, tool)— i.e. when the tool has been withheld into a toolpack for that agent, reachable only viause_skill(tools/toolpacks/ops.rs:134-140).So the two tools the prompt names as directly callable are no longer directly callable, and no other tool on the belt is named. The prompt and the belt have come apart.
Impact: the model is instructed to call tools it cannot call, and is told nothing about the ones it can. The failure mode is a wasted turn and a confused recovery, not an error — which is exactly why it needs a test rather than a bug report from a user.
Likely origin
skill_creator's belt and prompt last changed ina63c2b885— PR #6436,hermes-prompt-diet(2026-09-22). A prompt-size reduction is precisely the shape the guard's docstring predicts: "the tool bytes fall and nothing else moves."This is a recurrence, not a novelty. The same pattern has been seen before in this repo: a byte win that concealed a capability loss, visible only by diffing the name lists rather than the totals. That argues for a name-list diff as a standing step in any prompt-diet change, not just a fix here.
I have not bisected to confirm #6436 is the exact commit that flipped it — the belt/prompt last-touch is circumstantial, and the withholding could equally have been introduced by a toolpack change on the other side.
The fix that must NOT be applied
fleet_prompt_tests.rs:332carries an allowlist:Adding
skill_creatorto it would make the suite pass and silence the one assertion in it that is doing its job. The guard is not wrong; the prompt/belt pairing is. Flagging explicitly because that is the cheapest-looking fix and it is the wrong one.Suggested resolution
Either:
skill_creatorcan actually call (and describe the packed ones as reachable viause_skill, if that is the intent); ornode_exec/npm_execforskill_creatorif they were packed by accident.Which one depends on whether the withholding was deliberate — a question for whoever owns the toolpack split.
Reproduction
Fails deterministically on a clean checkout of
main, including in isolation. Note that no CI lane onmainruns this test — see #6486 and #5021 — which is why it has gone unnoticed. It sits in a sibling module of a scopeci-lite.ymldoes cover (agent::registry::agents::loader::), which makes the area look covered when it is not.