Skip to content

fix(skills): inject Skill into --tools when explicit tools= is set (#977)#985

Open
Zeffut wants to merge 1 commit into
anthropics:mainfrom
Zeffut:fix/977-skills-injects-tool
Open

fix(skills): inject Skill into --tools when explicit tools= is set (#977)#985
Zeffut wants to merge 1 commit into
anthropics:mainfrom
Zeffut:fix/977-skills-injects-tool

Conversation

@Zeffut
Copy link
Copy Markdown

@Zeffut Zeffut commented May 23, 2026

Summary

Closes #977.

When users pass an explicit tools=[...] list alongside skills="all" (or skills=["pdf", ...]), the CLI receives --tools <user_list> and --allowedTools Skill. The CLI loads only the tools listed in --tools, so Skill is authorized but never loaded — the model cannot invoke any skill. This contradicts the documented behavior of allowed_tools as the single configuration knob for skills.

Root cause

SubprocessCLITransport._apply_skills_defaults in src/claude_agent_sdk/_internal/transport/subprocess_cli.py injects Skill into allowed_tools but never touches the base tools list. _build_command emits --tools from self._options.tools directly. The two paths never meet.

Fix

_apply_skills_defaults now returns a third value, effective_tools, which mirrors the caller's tools list with Skill appended when skills is set. Idempotent; only when tools is an explicit list — preset objects and None are left untouched. The original options object is not mutated. _build_command emits --tools from this effective list.

Behavior matrix

tools skills --tools emitted
None any (not set; CLI default includes Skill)
preset object any default (unchanged)
[] any "" (unchanged)
["Read"] None Read (unchanged)
["Read"] "all" Read,Skill (FIXED)
["Read"] ["pdf"] Read,Skill (FIXED; allowed_tools is Skill(pdf))
["Read","Skill"] "all" Read,Skill (idempotent)

Files modified

  • src/claude_agent_sdk/_internal/transport/subprocess_cli.py_apply_skills_defaults now also returns effective tools; _build_command uses it.
  • tests/test_transport.py — 5 new regression tests covering injection, idempotency, no-skills passthrough, and non-mutation.

Verification

Python 3.12 venv, pip install -e ".[dev]":

  • python -m pytest tests/ --ignore=tests/test_build_wheel.py -> 744 passed, 5 skipped (5 new tests; baseline 739 passed).
  • python -m mypy src/ -> Success: no issues found in 24 source files.
  • python -m ruff check src/ tests/ -> All checks passed!

Relation to #979

This is an alternative approach to #979, which is also open and targets the same bug. #979 injects in _build_command itself; this PR centralizes all skills-related logic in _apply_skills_defaults (the same helper that already handles allowed_tools and setting_sources), which is easier to reason about and test in isolation. Happy to defer to whichever approach maintainers prefer.

Test plan

  • pytest tests/ --ignore=tests/test_build_wheel.py green (744 passed)
  • mypy src/ clean
  • ruff check src/ tests/ clean
  • 5 new regression tests in tests/test_transport.py

…nthropics#977)

When users pass an explicit tools=[...] list alongside skills="all",
the CLI's --tools argument did not include Skill, so the Skill tool
was authorized but never loaded. Centralizes the injection inside
_apply_skills_defaults via an effective_tools return value used by
_build_command. Idempotent, no-op when skills is unset.

Adds 5 regression tests. mypy + ruff clean. 744 passed.

Alternative approach to anthropics#979.

Closes anthropics#977.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 23, 2026 00:01
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds a regression fix for skills + explicit tools handling in SubprocessCLITransport so that selecting skills ensures the base --tools includes Skill, and extends the test suite to prevent regressions.

Changes:

  • Update skills defaulting logic to optionally inject Skill into an explicit list-form tools option.
  • Adjust _build_command() to use the skills-adjusted tools list when building the --tools flag.
  • Add regression tests covering injection behavior, idempotency, and immutability.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
tests/test_transport.py Adds regression tests ensuring Skill is added to --tools when skills are enabled with explicit tools, without mutating options.
src/claude_agent_sdk/_internal/transport/subprocess_cli.py Extends _apply_skills_defaults() to also compute effective tools, and wires it into _build_command().

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +227 to 238
if tools is not None and "Skill" not in tools:
tools.append("Skill")
else:
for name in skills:
pattern = f"Skill({name})"
if pattern not in allowed_tools:
allowed_tools.append(pattern)
# The CLI's --tools flag matches the bare tool name; allowed_tools
# supplies the per-skill filtering. Ensure Skill is loadable.
if tools is not None and "Skill" not in tools:
tools.append("Skill")

Comment thread tests/test_transport.py
Comment on lines +641 to +642
assert "--tools" in cmd
assert cmd[cmd.index("--tools") + 1] == "WebSearch,WebFetch,Read,Skill"
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.

skills="all" does not add "Skill" to tools

2 participants