Summary
routing.mjs:840 uses guidanceOnce("bash", …), while routing.mjs:1012 uses guidancePeriodic("external-mcp", …, getExternalMcpNudgeEvery()). The periodic variant already exists, already has an env knob (CONTEXT_MODE_EXTERNAL_MCP_NUDGE_EVERY, default 10, bounds [1,100]), and its docstring gives a rationale that applies just as well to Bash:
A single one-shot nudge gets lost after the model's context compaction kicks in, and subsequent large MCP payloads flood context unchecked.
Asking for the same opt-in knob for the Bash nudge — e.g. CONTEXT_MODE_BASH_NUDGE_EVERY, defaulting to 0/unset = current one-shot behaviour, so nothing changes for anyone who does not set it.
I am aware #113 deliberately introduced the once-per-session throttle to stop advisory spam, and I am not asking to revert it. Default-off knob only.
Why it matters, with numbers
On this machine, across 2,319 session transcripts since 2026-05-15:
| Tool |
Calls |
| Bash |
41,921 |
ctx_execute + ctx_execute_file |
4 |
ctx_batch_execute |
2 |
ctx_search |
1 |
ctx_fetch_and_index |
1 |
The passive capture layer is doing excellent work over the same period — ctx_stats reports 166 MB kept out of context, 37,321 captures. That number is why this is a report rather than a complaint: the plugin's automatic half is clearly earning its place. It is the active half, where the agent is supposed to choose the sandbox over a raw dump, that is not being reached.
The one-shot nudge does fire — I received it this session. It then has to survive every subsequent turn and at least one compaction while competing with everything else in context. Empirically it does not.
Sharper framing, if useful for prioritisation
The habit that defeats it is the multi-line Bash block:
echo "=== A ==="; <cmd A>
echo "=== B ==="; <cmd B>
echo "=== C ==="; <cmd C>
That block exists because the agent wants several outputs in one round trip — which is exactly what ctx_batch_execute provides, with the raw bytes staying in the sandbox. The moment to say so is when that command is submitted, not once at the start of the session. A nudge that re-fires every N unbounded Bash calls would land on that shape repeatedly rather than once.
(Unrelated aside, since it affects anyone measuring the same thing: this shape also defeats rtk's Claude Code hook, which only inspects the first line of a multi-line command — rtk-ai/rtk#3342. Same habit, two tools.)
Verified before filing
ctx_doctor → all [OK] on v1.0.169; FTS5 native module PASS, all six hook scripts PASS.
- WebFetch and curl redirects both fire correctly right now — I checked, because a first pass of my own analysis wrongly suspected they were failing open.
isMCPReady() returns true with live sentinels; the deny path is healthy. Not an issue, recorded here only so the numbers above are not read as "the hooks are broken".
Summary
routing.mjs:840usesguidanceOnce("bash", …), whilerouting.mjs:1012usesguidancePeriodic("external-mcp", …, getExternalMcpNudgeEvery()). The periodic variant already exists, already has an env knob (CONTEXT_MODE_EXTERNAL_MCP_NUDGE_EVERY, default 10, bounds [1,100]), and its docstring gives a rationale that applies just as well to Bash:Asking for the same opt-in knob for the Bash nudge — e.g.
CONTEXT_MODE_BASH_NUDGE_EVERY, defaulting to 0/unset = current one-shot behaviour, so nothing changes for anyone who does not set it.I am aware #113 deliberately introduced the once-per-session throttle to stop advisory spam, and I am not asking to revert it. Default-off knob only.
Why it matters, with numbers
On this machine, across 2,319 session transcripts since 2026-05-15:
ctx_execute+ctx_execute_filectx_batch_executectx_searchctx_fetch_and_indexThe passive capture layer is doing excellent work over the same period —
ctx_statsreports 166 MB kept out of context, 37,321 captures. That number is why this is a report rather than a complaint: the plugin's automatic half is clearly earning its place. It is the active half, where the agent is supposed to choose the sandbox over a raw dump, that is not being reached.The one-shot nudge does fire — I received it this session. It then has to survive every subsequent turn and at least one compaction while competing with everything else in context. Empirically it does not.
Sharper framing, if useful for prioritisation
The habit that defeats it is the multi-line Bash block:
That block exists because the agent wants several outputs in one round trip — which is exactly what
ctx_batch_executeprovides, with the raw bytes staying in the sandbox. The moment to say so is when that command is submitted, not once at the start of the session. A nudge that re-fires every N unbounded Bash calls would land on that shape repeatedly rather than once.(Unrelated aside, since it affects anyone measuring the same thing: this shape also defeats rtk's Claude Code hook, which only inspects the first line of a multi-line command — rtk-ai/rtk#3342. Same habit, two tools.)
Verified before filing
ctx_doctor→ all[OK]on v1.0.169; FTS5 native module PASS, all six hook scripts PASS.isMCPReady()returns true with live sentinels; the deny path is healthy. Not an issue, recorded here only so the numbers above are not read as "the hooks are broken".