- I searched existing issues and this is not a duplicate. #2160 reports the same class for OpenCode; I found no Hermes report (searched "hermes subagent", "subagent bootstrap", "SUBAGENT-STOP"). #2223, the OpenCode fix, was closed unmerged and does not touch
.hermes-plugin/.
Environment (required)
| Field | Value |
|---|---|
| Superpowers version | v7.0.0, bb92a77741419a4ab5f06e711a283343f1ada0c3 (git-clone plugin install, tracking main) |
| Harness | Hermes Agent desktop, native plugin (.hermes-plugin/) |
| Harness version | Hermes Agent v0.22.0 (2026.9.24), e06df9c2 |
| Your model + version | claude-opus-5-5. This report was drafted by the agent from source reading and a zero-token probe; a human reviewed it before posting. |
| All plugins installed | superpowers, honey (plus local plugins that register no pre_llm_call hook) |
| OS + shell | Windows 11, Git Bash (MSYS) |
Is this a Superpowers issue or a platform issue?
- I confirmed this issue does not occur without Superpowers installed. The injected text is the plugin's own bootstrap and is the only
pre_llm_callresult returned.
The injection comes from .hermes-plugin/__init__.py. Hermes runs every pre_llm_call hook for child agents too; the only skip is _persist_disabled (agent/turn_context.py:801), which delegate_task children do not set.
What happened?
pre_llm_call returns the bootstrap whenever is_first_turn is true (.hermes-plugin/__init__.py:121). A delegate_task child starts with no history, so on its first turn it receives the full <EXTREMELY_IMPORTANT> bootstrap, byte-identical to the one the parent gets. The bootstrap then relies on <SUBAGENT-STOP> for the child to ignore it. #2160 shows that is not reliable: an OpenCode worker invoked brainstorming and restarted the design cycle instead of doing its bounded task.
Hermes already tells the hook that the caller is a child: delegate_task builds children with platform="subagent" (tools/delegate_tool.py:277), the agent keeps it (AIAgent(platform="subagent").platform == "subagent"), and _collect_pre_llm_call_context forwards it as platform=.
Steps to reproduce
No model call is needed. From the Hermes source checkout, with its own interpreter:
import types
from agent.turn_context import _collect_pre_llm_call_context
from agent.delegation_context import delegated_child_context
def stub(platform):
return types.SimpleNamespace(session_id="probe", model="m", platform=platform,
_parent_session_id="", _user_id="", _persist_disabled=False)
kw = dict(effective_task_id="t", turn_id="1", original_user_message="hi",
messages=[{"role": "user", "content": "hi"}])
parent = _collect_pre_llm_call_context(stub("desktop"), conversation_history=None, **kw)
with delegated_child_context("probe-child"):
child = _collect_pre_llm_call_context(stub("subagent"), conversation_history=None, **kw)
later = _collect_pre_llm_call_context(stub("subagent"), conversation_history=[{"role": "user", "content": "x"}], **kw)
print(len(parent), len(child), len(later), parent == child)Expected behavior
A delegate_task child gets no bootstrap: the parent has already chosen the process, and the child's brief carries what it needs.
Actual behavior
5729 5729 0 TrueThe parent and the subagent first turn both get 5,729 characters (roughly 1,400 tokens) of identical bootstrap. Later child turns get nothing.
Not verified on Hermes: whether a child actually ignores <SUBAGENT-STOP>. The behavioural failure is the one #2160 reports for OpenCode; I did not run a live delegation for this report.
Suggested fix
if is_first_turn and platform != "subagent":
return {"context": bootstrap}
return NoneChecked on a scratch copy of the adapter with this one-line change: a subagent first turn now gets nothing, while desktop and cron first turns still get the full bootstrap and later turns still get nothing.
platform is the explicit signal. parent_session_id does not mean "subagent" by itself: Hermes also records a parent for the continuation session it creates on context compression (agent/conversation_compression.py, publish_compression_child(parent_session_id=...)).
Debug log or conversation transcript
Injected context is not persisted in Hermes' session records, so a transcript would not show it. The probe above is the reproduction.
Activity
2Hi @thealps01-netizen — I'm Claude, an AI agent (Claude Opus 5.5, running in Claude Code 2.1.305), posting from Drew (@arittr)'s account at their direction. Drew reviewed the finding below and approved this reply.
Confirmed: the Hermes adapter's pre_llm_call hook returns the full using-superpowers bootstrap on every first turn, and a delegate_task child starts with no history, so its first turn gets the same bootstrap as the parent session. Running the hook from the current release with the arguments Hermes passes gives the parent and a subagent first turn identical context. We already stopped injecting the bootstrap into OpenCode task subagents (#2160), and the Hermes side is queued with us. Thanks for the report, and thanks @markalexwatson for the delegation traces.
If any of the evidence above is wrong, reply here — Drew reads these, and decisions can be revisited.
— Claude Opus 5.5, Claude Code 2.1.305, session 5d9d84c2-4219-41be-8d07-d9ba2ad854be
Adding live Hermes delegation observations to this report. The existing reproduction establishes injection without a model call; my runs also show children acting on Superpowers-related instructions before starting their assigned work.
In three instrumented document-review delegations using a local model, the child's first tool action was:
skill_view(superpowers:using-superpowers)skill_view(using-superpowers)→ "not found", followed byskills_listand a qualified loadread_filecall on a Superpowers SKILL.md, despite the skill being excluded from the child's discovery indexA captured outgoing request from a child session identified as
source=subagentcontained the bootstrap appended to its user message (5,707 UTF-8 bytes at the revision below).The bootstrap includes both the subagent exemption (
<SUBAGENT-STOP>) and an instruction not to reloadusing-superpowers. These runs nevertheless began with skill-loading attempts. It also supplies a direct-file fallback (read_fileon the SKILL.md path), providing another route to the skill content when discovery or named loading is restricted.Run 3 was performed while locally testing NousResearch/hermes-agent#140566 (associated with NousResearch/hermes-agent#140537, still an open draft at time of writing). That work addresses platform-specific discovery and skills-tool filtering; bootstrap injection is a separate path.
These observations support the guard already proposed in #2540. The runs incurred substantial elapsed time on local inference, but I have not isolated the bootstrap's contribution with a controlled before/after comparison.
Environment: superpowers
bb92a777(Hermes adapter,.hermes-plugin/__init__.py); hermes-agent 0.22.2 parent (d923a5eb) driving delegate children against a worktree at hermes-agent PR #140566 head (e2303218d1by the final run); child model gpt-oss:20b (MXFP4 as shipped) via Ollama 0.40.5, CPU-only, 32k context.Disclosure per contribution guidelines: prepared with assistance from Claude (Fable 5), DeepSeek-v4.1-flash (as the Hermes orchestrator running the instrumented delegations), and GPT-6 Astra (adversarial review, which found this existing issue and corrected an earlier draft).