Skip to content

fix(provider): isolate Claude CLI settings hooks with --setting-sources=#298

Merged
keshprad merged 3 commits into
NVIDIA:mainfrom
rodboev:pr/claude-cli-setting-sources
Jul 22, 2026
Merged

fix(provider): isolate Claude CLI settings hooks with --setting-sources=#298
keshprad merged 3 commits into
NVIDIA:mainfrom
rodboev:pr/claude-cli-setting-sources

Conversation

@rodboev

@rodboev rodboev commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Summary

The claude_cli provider builds a capability-stripped claude -p subprocess, but it never constrains settings sources, so the spawned CLI loads the operator's settings.json and runs its hooks. When a hook re-enters Claude Code, each LLM call the scanner makes can turn into a full hook cycle and saturate the machine.

This change adds --setting-sources= beside the existing Claude isolation flags so the spawned CLI loads no user, project, or local settings and therefore runs none of those hooks. With SKILLSPECTOR_MODEL unset, that also means Claude no longer inherits filesystem default-model or thinking settings from those scopes.

Closes #295

Reported by @Mark2Mac in issue #295.

Root cause

_build_claude_argv in src/skillspector/providers/_agent_cli.py already strips tools, MCP servers, and slash commands, but it omits the Claude CLI's settings-source boundary. The returned argv therefore still lets the child CLI load ambient settings before the model call, and settings-derived hooks execute inside what is otherwise intended to be an isolated subprocess.

Before / After

argv tail spawned claude loads settings hooks
Before ... --strict-mcp-config --disable-slash-commands yes
After ... --strict-mcp-config --setting-sources= --disable-slash-commands no

Diff Notes

  • src/skillspector/providers/_agent_cli.py: add the exact --setting-sources= token to _build_claude_argv, directly after --strict-mcp-config
  • src/skillspector/providers/_agent_cli.py: document that the empty settings-source list blocks user, project, and local settings hooks, and that filesystem model settings no longer flow into the spawned Claude CLI unless SkillSpector pins SKILLSPECTOR_MODEL
  • src/skillspector/providers/_agent_cli_base.py and src/skillspector/providers/claude_cli/provider.py: narrow the Claude contract text so model="" means "no explicit override" rather than "inherit filesystem model settings"
  • tests/unit/test_agent_cli.py: add focused argv assertions for the new literal and its required single-token empty-value form
  • tests/unit/test_agent_cli.py: add Codex and Gemini absence checks so the preservation coverage proves --setting-sources= stays Claude-only
  • tests/unit/test_providers.py and tests/integration/test_agent_cli_live.py: align the Claude-facing test language with the new no-filesystem-settings boundary

Scope

This is limited to the Claude CLI subprocess boundary. It does not change Codex or Gemini builders, env scrubbing, auth behavior, graph orchestration, analyzers, report metadata, MCP transport, or dependencies.

The hook-suppression effect is owned by the external Claude CLI flag contract. The committed unit tests prove the argv SkillSpector emits at that boundary, not the external CLI's full runtime behavior. The no-settings boundary also means Claude's filesystem model settings stop applying unless SKILLSPECTOR_MODEL pins a model explicitly.

Verification

  • .\.venv\Scripts\python.exe -m pytest tests\unit\test_agent_cli.py tests\unit\test_providers.py returned 156 passed, 9 skipped in 2.47s.
  • The base argv proxy omitted --setting-sources=; the head argv proxy emitted --strict-mcp-config, --setting-sources=, and --disable-slash-commands in that order.
  • uv run ruff check src/ tests/ returned All checks passed!.
  • uv run ruff format --check src/ tests/ returned 144 files already formatted.
  • claude --help documented --setting-sources <sources> for user, project, local; claude --setting-sources= --version returned 2.1.217 (Claude Code).
  • Issue [BUG] claude_cli provider omits --setting-sources=, so the spawned claude runs the user's hooks (4 LLM calls -> 3h09m CPU, 1225 hook sessions) #295 owner-reaching measurement recorded 33 versus 0 log lines and 1 versus 0 created sessions for current argv versus --setting-sources=.

@keshprad keshprad left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The settings isolation is sound, but the new no-settings fallback changes the documented model-selection contract. Please update the user-facing documentation before merging.

Comment thread src/skillspector/providers/_agent_cli.py
Signed-off-by: Rod Boev <rod.boev@gmail.com>

@keshprad keshprad left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved after re-review: the documentation now accurately describes the CLI runtime fallback and SKILLSPECTOR_MODEL override.

@keshprad
keshprad merged commit 8255b60 into NVIDIA:main Jul 22, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] claude_cli provider omits --setting-sources=, so the spawned claude runs the user's hooks (4 LLM calls -> 3h09m CPU, 1225 hook sessions)

2 participants