You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
debugging: probe disallowed-tools MCP pattern and large-heap converter #7593
Refs #7580 (Tool per job). Source: PLAN Phase 1, topic poteto-review.
Depends on
none: on the frontier now
Outcome
Two recorded observations that gate the tool-per-job setting slice: whether a skill's disallowed-tools entry naming an MCP server-wide pattern denies that server's tools, and how long
analyze-profile's SQLite converter takes, and how much memory it peaks at, on a heap near its 512 MiB
cap.
Decisions
Q561 (owner: follow Lauren or better): one named tool per job; the skill names the command, checks
it resolves and stops if missing. Origin: Lauren's (Playwright plus CDP; SQLite dump and diff).
The converter must handle a large heap before CI use is promised (Q561 research tag).
No product code; probe artifacts stay out of tracked plugin files.
Key interfaces
Variation verdicts: "Browser driver and profiling tools: abstract now; tool-per-job setting read
through the adapter; one named tool, no MCP handoff (Q561, Q569)."
Done when
A Probe result: comment records the throwaway skill's disallowed-tools pattern, whether the
server's tools were denied, and a control (a tool outside the pattern stays allowed), with the
Claude Code version and date.
A Probe result: comment records the converter's run on a heap near 512 MiB: input size, wall
time, peak memory, command, date.
git status --porcelain plugins/ is empty after the probe.
Out of scope
Changing the converter or any skill; the setting slice acts on the result.
Probe result: a skill's disallowed-tools entry naming an MCP server-wide pattern removes that server's tools. A tool from another server stays allowed.
Claude Code 2.1.301, 2026-10-16, headless claude -p --plugin-dir <throwaway plugin> --output-format stream-json --verbose --model sonnet.
Docs read: Skills: frontmatter reference says disallowed-tools removes the listed tools from Claude's pool while the skill is active, and the restriction clears on the next message. Permissions: MCP says mcp__<server> and mcp__<server>__* both match every tool from that server. The skills page does not say that disallowed-tools accepts this rule syntax. This probe checks that.
Server under test: context7, which is user-scoped and showed connected in every run. Control tool: mcp__ref__ref_search_documentation.
All three runs passed the same --allowedTools covering both tools and ToolSearch. Each prompt asked for one mcp__context7__resolve-library-id call and one ref call.
Run
Skill disallowed-tools
context7 tools in init tool list
context7 call
ref call (control)
Baseline (no skill)
none
both present
ran, returned results
ran
block-star
mcp__context7__*
none
not attempted: ToolSearch select: returned only the ref tool
ran
block-bare
mcp__context7
none
denied: <tool_use_error>Error: No such tool available: mcp__context7__resolve-library-id</tool_use_error>
ran
permission_denials was empty in every run. The tools were removed from the pool, so no permission rule was involved. The model was told the context7 server had "disconnected", but the init event still showed the server connected.
Caveat: stream-json does not echo the slash-command expansion. The evidence that the skill took effect is the difference between runs: the only change from the baseline is the /probe7593:block-* prefix, and only those runs lose the context7 tools.
Probe artifacts stay untracked under .work/poteto-review/probes/7593/: the plugin, the three run-*.jsonl streams and summarize.jq. git status --porcelain plugins/ is empty.
Input: a V8 .heapsnapshot written by v8.writeHeapSnapshot() after allocating 2,000,000 linked objects. Size: 535,749,748 bytes (510.9 MiB). The converter's MAX_INPUT_BYTES is 536,870,912.
Result: exit 0, {"format": "heapsnapshot", "tables": {"nodes": 8057330, "edges": 22246947, ...}}. The SQLite output was 1,292,222,464 bytes (1.2 GiB).
/usr/bin/time -v: elapsed 0:59.10, user 54.10 s, system 4.69 s, maximum resident set size 3,911,012 kB (3.73 GiB, about 7.3x the input size).
The peak memory comes from read_json, which reads the whole file into memory and then calls json.loads, so the full Python object graph is in memory at once. A CI runner needs about 4 GiB free for a heap at the cap.
The heap and SQLite files were deleted after the run. git status --porcelain plugins/ is empty.
Activity
github-actions commentedon Oct 16, 2026
Thanks for the report. Automated triage handed this issue to a maintainer.
Proposed work class: work-class: read-only
Basis: automated intake triage; a maintainer confirms or changes it.
Automated triage. A maintainer reviews it.
kyle-sexton commentedon Oct 16, 2026
Probe result: a skill's
disallowed-toolsentry naming an MCP server-wide pattern removes that server's tools. A tool from another server stays allowed.claude -p --plugin-dir <throwaway plugin> --output-format stream-json --verbose --model sonnet.disallowed-toolsremoves the listed tools from Claude's pool while the skill is active, and the restriction clears on the next message. Permissions: MCP saysmcp__<server>andmcp__<server>__*both match every tool from that server. The skills page does not say thatdisallowed-toolsaccepts this rule syntax. This probe checks that.context7, which is user-scoped and showedconnectedin every run. Control tool:mcp__ref__ref_search_documentation.--allowedToolscovering both tools andToolSearch. Each prompt asked for onemcp__context7__resolve-library-idcall and one ref call.disallowed-toolsblock-starmcp__context7__*ToolSearch select:returned only the ref toolblock-baremcp__context7<tool_use_error>Error: No such tool available: mcp__context7__resolve-library-id</tool_use_error>permission_denialswas empty in every run. The tools were removed from the pool, so no permission rule was involved. The model was told the context7 server had "disconnected", but the init event still showed the serverconnected.Caveat: stream-json does not echo the slash-command expansion. The evidence that the skill took effect is the difference between runs: the only change from the baseline is the
/probe7593:block-*prefix, and only those runs lose the context7 tools.Probe artifacts stay untracked under
.work/poteto-review/probes/7593/: the plugin, the threerun-*.jsonlstreams andsummarize.jq.git status --porcelain plugins/is empty.kyle-sexton commentedon Oct 16, 2026
Probe result: analyze-profile's
trace_to_sqlite.pyconverted a 510.9 MiB heap snapshot (cap: 512 MiB) in 59 s wall time with a peak RSS of 3.73 GiB.Date: 2026-10-16. Host: WSL2 Linux, 24 CPUs, 39 GiB RAM, Python 3.14.8, Node v24.21.0.
Input: a V8
.heapsnapshotwritten byv8.writeHeapSnapshot()after allocating 2,000,000 linked objects. Size: 535,749,748 bytes (510.9 MiB). The converter'sMAX_INPUT_BYTESis 536,870,912.Command, with paths relative to the repo root:
Result: exit 0,
{"format": "heapsnapshot", "tables": {"nodes": 8057330, "edges": 22246947, ...}}. The SQLite output was 1,292,222,464 bytes (1.2 GiB)./usr/bin/time -v: elapsed 0:59.10, user 54.10 s, system 4.69 s, maximum resident set size 3,911,012 kB (3.73 GiB, about 7.3x the input size).The peak memory comes from
read_json, which reads the whole file into memory and then callsjson.loads, so the full Python object graph is in memory at once. A CI runner needs about 4 GiB free for a heap at the cap.The heap and SQLite files were deleted after the run.
git status --porcelain plugins/is empty.