@@ -182,15 +182,24 @@ def _build_settings_value(self) -> str | None:
182182
183183 def _apply_skills_defaults (
184184 self ,
185- ) -> tuple [list [str ], list [str ] | None ]:
186- """Compute effective allowed_tools and setting_sources for skills.
185+ ) -> tuple [list [str ], list [str ] | None , list [ str ] | None ]:
186+ """Compute effective allowed_tools, setting_sources, and tools for skills.
187187
188188 When ``options.skills`` is ``"all"``, injects the bare ``Skill`` tool;
189189 when it is a list, injects ``Skill(name)`` for each entry. In either
190190 case ``setting_sources`` defaults to ``["user", "project"]`` when
191191 unset so the CLI discovers installed skills without the caller having
192192 to wire up both options manually. ``None`` is a no-op.
193193
194+ When the caller provides an explicit ``tools`` list (the base set of
195+ tools the CLI is allowed to load), the bare ``Skill`` tool is also
196+ appended to that list when missing. Without this, ``skills="all"``
197+ would add ``Skill`` to ``allowed_tools`` but ``Skill`` would still be
198+ absent from the base tool set, so the model could not invoke it
199+ (issue #977). When ``tools`` is ``None`` or a preset object, no
200+ injection into ``tools`` is needed because the default tool set
201+ already includes ``Skill``.
202+
194203 Does not mutate the original options object.
195204 """
196205 allowed_tools : list [str ] = list (self ._options .allowed_tools )
@@ -199,24 +208,38 @@ def _apply_skills_defaults(
199208 if self ._options .setting_sources is not None
200209 else None
201210 )
211+ # Only mirror an explicit list-form ``tools`` option here. Preset
212+ # objects and ``None`` are returned as ``None`` so ``_build_command``
213+ # uses its existing path for them.
214+ tools : list [str ] | None = (
215+ list (self ._options .tools )
216+ if isinstance (self ._options .tools , list )
217+ else None
218+ )
202219
203220 skills = self ._options .skills
204221 if skills is None :
205- return allowed_tools , setting_sources
222+ return allowed_tools , setting_sources , tools
206223
207224 if skills == "all" :
208225 if "Skill" not in allowed_tools :
209226 allowed_tools .append ("Skill" )
227+ if tools is not None and "Skill" not in tools :
228+ tools .append ("Skill" )
210229 else :
211230 for name in skills :
212231 pattern = f"Skill({ name } )"
213232 if pattern not in allowed_tools :
214233 allowed_tools .append (pattern )
234+ # The CLI's --tools flag matches the bare tool name; allowed_tools
235+ # supplies the per-skill filtering. Ensure Skill is loadable.
236+ if tools is not None and "Skill" not in tools :
237+ tools .append ("Skill" )
215238
216239 if setting_sources is None :
217240 setting_sources = ["user" , "project" ]
218241
219- return allowed_tools , setting_sources
242+ return allowed_tools , setting_sources , tools
220243
221244 def _build_command (self ) -> list [str ]:
222245 """Build CLI command with arguments."""
@@ -237,22 +260,22 @@ def _build_command(self) -> list[str]:
237260 ["--append-system-prompt" , cast (SystemPromptPreset , sp )["append" ]]
238261 )
239262
263+ effective_allowed_tools , effective_setting_sources , effective_tools = (
264+ self ._apply_skills_defaults ()
265+ )
266+
240267 # Handle tools option (base set of tools)
241268 if self ._options .tools is not None :
242- tools = self . _options . tools
243- if isinstance ( tools , list ):
244- if len (tools ) == 0 :
269+ if effective_tools is not None :
270+ # List-form tools, possibly with Skill injected by skills option.
271+ if len (effective_tools ) == 0 :
245272 cmd .extend (["--tools" , "" ])
246273 else :
247- cmd .extend (["--tools" , "," .join (tools )])
274+ cmd .extend (["--tools" , "," .join (effective_tools )])
248275 else :
249276 # Preset object - 'claude_code' preset maps to 'default'
250277 cmd .extend (["--tools" , "default" ])
251278
252- effective_allowed_tools , effective_setting_sources = (
253- self ._apply_skills_defaults ()
254- )
255-
256279 if effective_allowed_tools :
257280 cmd .extend (["--allowedTools" , "," .join (effective_allowed_tools )])
258281
0 commit comments