Repository navigation
feat(skills): give Claude Agents runs the skills attached to their variation - #208
Merged
Merged
Conversation
…host settings A run with no NativeTool attached now sends tools=[], so the Claude Code built-ins (Read, Bash, Skill and the rest) are off unless a config attaches them. 50e82fd omitted the key instead, which gave every run the full built-in set. TypeScript has sent tools=[] since its first release. TESTING.md §2.x.2. create_claude_agents_handler takes cwd and setting_sources, forwarded to every query() on both paths. setting_sources not given sends [], because the Agent SDK reads None as "load every source": the host's plugins, skills, hooks, permission rules and CLAUDE.md reached every run (AIC-3584). cwd is sent only when given. to_claude_agents also sends setting_sources=[]. §2.x.1. BREAKING CHANGE: runs no longer get Claude Code built-ins unless the config attaches them as NativeTool sentinels, and no longer load host Claude Code settings unless setting_sources names them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…riation
A skill attached to an agent-mode variation never reached a model run
through create_claude_agents_handler: tools=[] removes the Skill tool,
and nothing hands the CLI the skill files.
create_claude_agents_skills_handler(), from the new
launchdarkly_ai_claude_agents.experimental.skills module, does. On every
invoke and stream it:
- writes skill_refs(config) with write_skills, through the store
configured with set_skill_store, into
mkdtemp(<skills_temp_dir>/ld-skills-)/launchdarkly/skills;
- passes plugins=[{"type": "local", "path": <dir>/launchdarkly}] and
skills=["launchdarkly:<key>", ...], and appends Skill to tools (not to
allowed_tools);
- removes the directory when the run ends, however it ends.
It fails closed: a reconcile that is not ok raises before query(),
naming each skill. A variation with no skills runs exactly as with the
core handler and needs no store. setting_sources is always sent, so
claude-agent-sdk never falls back to user,project once skills is set.
Core reaches this only through a private _prepare keyword on the
internal factory. The package root does not import the experimental
module.
Spec: TESTING.md §2.x Claude Agents Skills Integration and A.18
(launchdarkly/ai-sdks-monorepo#59).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
XieX
marked this pull request as ready for review
October 23, 2026 17:36
…t-options # Conflicts: # packages/claude-agents/src/launchdarkly_ai_claude_agents/handler.py
…native adapter Matches launchdarkly/js-ai-sdk#135. claude_agents(), claude_graph() and to_claude_agents() hard-coded setting_sources=[], so a wrapper user could not opt back in to host settings, and these signatures freeze at 1.0. - claude_agents and claude_graph take cwd / setting_sources keyword-only, build the handler with them, and pass neither on to config() / graph(). - to_claude_agents reads both from opts and sends _host_query_options(...) to every node's query(), root and sub-agents, in place of the hard-coded []. - The README gains a migration note: [] also drops the settings-file env (ANTHROPIC_BASE_URL, CLAUDE_CODE_USE_BEDROCK / _VERTEX, proxies), apiKeyHelper and model, so a Bedrock, Vertex or gateway deployment configured through ~/.claude/settings.json stops authenticating. - agents.md §2a describes the model-parameter allowlist from main instead of "forwards none of model.parameters". - API report regenerated for the new signatures. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…kly/python-ai-sdk into xie/claude-agents-skills # Conflicts: # packages/claude-agents/src/launchdarkly_ai_claude_agents/handler.py
…xperimental.skills Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…spans raises The blocking path ran cleanup after finish_root_span and end_unfinished_spans in the same finally, so a raise from either leaked the run's plugin directory. Cleanup now has its own finally. Lists the experimental skills module in FORWARDED_LISTS: it delegates to the core handler, which forwards the parameters. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
This needs a human reviewer. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 85d37ee. Configure here.
…stream spans raises The stream path closed the vendor generator and ran the preparation's cleanup after inference.finish(), abandon_tool_spans and end_span_once in the same finally, so a raise from any of them skipped both and leaked the run's plugin directory. They now run in their own finally, as on the blocking path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jeffdupont
approved these changes
Oct 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Stacked on #201 (host options and built-in tool set). Review that one first. This PR's base is its branch.
A skill attached to an agent-mode variation never reached a model run through
create_claude_agents_handler. #201'stools=[]removes theSkilltool, and nothing hands the CLI the skill files.create_claude_agents_skills_handler(*, capture_content=None, cwd=None, setting_sources=None, skills_temp_dir=None), from the newlaunchdarkly_ai_claude_agents.experimental.skillsmodule, fixes that. On every invoke and stream it:skill_refs(config)withwrite_skills, through the store configured withset_skill_store, intomkdtemp(<skills_temp_dir>/ld-skills-)/launchdarkly/skills. Pinned versions are honored.plugins=[{"type": "local", "path": <dir>/launchdarkly}]andskills=["launchdarkly:<key>", …], and appendsSkilltotools(not toallowed_tools).ok(no store, store not yet initialized, a skill withheld by verification, or an absent pin), the run raises beforequery()and names each skill.setting_sourcesis neverNone. Withskillsset andsetting_sources=None,claude-agent-sdksends--setting-sources=user,project. The core handler already always sends it ([]unless given), and this handler inherits that.Skillis intools, so aSkillcall gets anexecute_tool Skillspan, with no$ld:ai:tool_callevent._preparekeyword argument on_create_claude_agents_handler. It is not an option of the public factory. The package root doesn't import the experimental module, and a test checks that in a fresh interpreter.claude_agents(),claude_graph()andto_claude_agents(). The README says so.Differences from TypeScript
skipMcpDiscovery.claude-agent-sdk'sSdkPluginConfighas no such key, so the plugin entry carries onlytypeandpath. The directory holds no MCP config, so there is nothing to discover.shutil.rmtree, so a cancellation during teardown can't interrupt it. A failed removal is logged and doesn't replace the run's outcome.Tests
test_skills.py(49 tests) uses a mockedquery()with a realInMemorySkillStore, a real filesystem (tmp_pathasskills_temp_dir) and a real OTel provider. Each spec bullet runs on both invoke and stream where it applies.test_sdk_usage.pyadds theexperimental.createClaudeAgentsSkillsHandlerrow.Skillfrom the hook-install condition fails the span tests.Checks:
uv run pytest: everything passes exceptopencode-agentstest_a_fake_opencode_is_started_spoken_to_and_stopped, the macOS/private/vartemp-path failure already onmain.make lint,make format-checkandmake typecheckare clean.Follow-ups in the monorepo
EXPERIMENTAL.mdrow for Python.api-surface/python/launchdarkly_ai_claude_agents.experimental.skills.txt.pythononexperimental.createClaudeAgentsSkillsHandlerinusage-ids.txt.Not verified yet: a live run where a model actually loads the skill.
Spec: TESTING.md §2.x "Claude Agents Skills Integration" and A.18, in launchdarkly/ai-sdks-monorepo#59. The TypeScript side is launchdarkly/js-ai-sdk#136.
🤖 Generated with Claude Code
Note
Overview
Adds experimental
create_claude_agents_skills_handler()underlaunchdarkly_ai_claude_agents.experimental.skillsso Claude Agent runs get the skills attached to their AI Config variation. The corecreate_claude_agents_handler()path is unchanged and still ignores variation skills.On each invoke/stream with skills, the handler writes skill files from
set_skill_storeinto a per-run temp directory, passes it toquery()as a locallaunchdarklyplugin with qualifiedlaunchdarkly:<key>skill names, enables theSkillbuilt-in (via new internal_prepare/QueryPreparationon_create_claude_agents_handler), and removes the directory in a final cleanup on success, failure, cancel, or stream abandonment. Reconcile failures fail closed beforequery(); empty skills behave like the core handler.Docs, API report, usage tracking for
experimental.createClaudeAgentsSkillsHandler, and a largetest_skills.pysuite cover materialization, concurrency, telemetry (execute_tool Skill), and thatclaude_agents/ graph helpers are not wired yet.Reviewed by Cursor Bugbot for commit ac743e0. Bugbot is set up for automated code reviews on this repo. Configure here.