Skip to content

feat(skills)!: promote Agent Skills to core - #210

Open
jeffdupont wants to merge 10 commits into
mainfrom
jdupont/aic-3655-skills-core
Open

jeffdupont wants to merge 10 commits into
mainfrom
jdupont/aic-3655-skills-core

Conversation

@jeffdupont

@jeffdupont jeffdupont commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Promotes Agent Skills from launchdarkly_ai_server.experimental.skills to the package root. Jira: AIC-3655.

Do not merge yet. This PR must not merge until the blockers linked on AIC-3655 are fixed. It releases together with the JS and Go promotion PRs (links to be added).

Migration

Import Agent Skills names from launchdarkly_ai_server instead of launchdarkly_ai_server.experimental.skills. Nothing else changes: the names, signatures and behaviour are the same.

# before
from launchdarkly_ai_server.experimental.skills import get_skill, write_skills
# after
from launchdarkly_ai_server import get_skill, write_skills

This is a breaking change (!), which bumps the minor version while the package is 0.x.

What changed

  • Root exports. All 24 names that experimental/skills.py exported are now in launchdarkly_ai_server.__all__, same spelling. launchdarkly-ai-python re-exports root __all__ with import *, so it gets them with no code change; its existing re-export tests cover it.
  • Experimental module removed. experimental/skills.py is deleted. experimental/__init__.py is only a docstring, so nothing else there referenced it. Evaluations from Code stays in experimental.evaluations, untouched.
  • API reports. Regenerated with make api-report: the skills names appear in launchdarkly_ai_server.txt, and launchdarkly_ai_server.experimental.skills.txt is deleted.
  • Changelog. The three skills → Experimental rows are removed from changelog-sections in release-please-config.json, so feat(skills): now lands under Features.
  • Docs. The client README, the launchdarkly-ai-python README, packages/client/agents.md and AGENTS.md no longer call Agent Skills experimental. Code samples import from the root.
  • Core strings. Docstrings and error messages in skills_core.py, skills_watch.py, types.py, types_validation.py, shutdown_hooks.py and lifecycle.py no longer name the experimental module. For example, the "no skill store" error now says set_skill_store(store) from launchdarkly_ai_server.
  • Usage IDs. None. main reports no skills usage IDs today, so this PR adds none. When skills usage reporting is added, it must use client.* IDs, not experimental.*.
  • Unchanged behaviour. parse_ai_config still passes skills through unvalidated, and skill_refs still validates it. shutdown() still clears the skill store through the internal shutdown hook. The lifecycle module still imports no skills module.

Tests

  • test_skills.py: every skills name is in root __all__ and on the root module. launchdarkly_ai_server.experimental.skills raises ImportError, and launchdarkly_ai_server.experimental has none of the names.
  • test_public_surface.py: the skills names are added to the ROOT_SURFACE snapshot.
  • test_lifecycle.py: the "core loads no experimental module" check now checks evaluations and experimental only, since the root now imports the skills modules.
  • The skills test suites and conftest.py import from the root.

Test plan

Run in the PR worktree after uv sync (exit 0):

  • make lint — exit 0
  • make format-check — exit 0
  • make typecheck — exit 0 (Success: no issues found in 101 source files)
  • make api-report-check — exit 0 (14 API reports are current)
  • uv run pytest -q packages/client packages/ai — 1709 passed, 1 skipped
  • make test — exit 2: 3282 passed, 18 skipped, 3 failed. The same 3 tests fail on unmodified origin/main (e3afb3f) in the same checkout, and CI on main is green. None of them involves skills:
    • test_lifecycle.py::TestInitClientSDKKeyPath::test_uses_options_sdk_key_over_env_var and ::test_retries_after_a_failed_init_instead_of_replaying_it: they get a staging stream_uri. My unverified guess is a local .env above the checkout leaking into the full run. Both pass when run alone.
    • opencode-agents/tests/test_handler.py::TestProcess::test_a_fake_opencode_is_started_spoken_to_and_stopped: on macOS the temp path comes back as /var/... in one place and /private/var/... in another.

🤖 Generated with Claude Code

Related PRs

Releases together with:


Note

Overview
Promotes Agent Skills from experimental to core on launchdarkly-ai-server: all 24 skills APIs now live on launchdarkly_ai_server (and flow through launchdarkly-ai-python via re-export). launchdarkly_ai_server.experimental.skills is removed—callers must switch imports to the package root (feat(skills)!).

The public contract is refreshed: API reports move skills entries into launchdarkly_ai_server.txt, release-please drops the skills Experimental changelog scope, and docs/README samples use root imports. Skills helpers now emit SDK-wide report_usage("client.*") events (once per helper per client); watcher-driven reconciles call internal _write_skills so they do not double-count writeSkills.

Downstream packages (e.g. claude-agents) import store/skill APIs from launchdarkly_ai_server instead of experimental.skills; the Claude skills handler stays under experimental. Tests and lifecycle wording are updated so skills modules are core, while Evaluations remains experimental.

Reviewed by Cursor Bugbot for commit d679fd2. Bugbot is set up for automated code reviews on this repo. Configure here.

jeffdupont and others added 2 commits October 23, 2026 10:25
Every Agent Skills name is now exported from the launchdarkly_ai_server
package root (and so from launchdarkly-ai-python), with the same spelling.
launchdarkly_ai_server.experimental.skills is removed; import from
launchdarkly_ai_server instead. Nothing else changes.

- Root __init__ imports and __all__ gain the 24 skills names.
- API reports regenerated; the experimental.skills report is gone.
- release-please changelog-sections drop the skills Experimental rows.
- READMEs, agents.md, AGENTS.md, core docstrings and error strings no
  longer point at the experimental module.
- Tests import skills names from the root; new tests check the root
  exports them and the experimental module no longer imports.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A put or delete with no usable key stays warned and ignored, and delivery
keeps going. Drop the "experimental stage" and "revisit before 1.0"
wording from agents.md and the pinning test's docstring.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jeffdupont

Copy link
Copy Markdown
Contributor Author

Pushed 4825587, which merges origin/main into this branch with no conflicts. make api-report showed no drift, and make lint-fix and make typecheck are clean. No other changes.

This needs a human reviewer.

@XieX XieX left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I reviewed the promotion, and the code move itself looks clean: no references to experimental.skills remain, and the root __all__ matches the old module's 24 names. My inline comments are mostly about the docs and packaging around it.

One thing outside the diff: the title's scope is AIC-3655. release-please shows the scope in bold in the changelog entry, so the Jira key would appear in the customer-facing changelog. feat(skills)!: promote Agent Skills to core would land under Features in the same way.

Comment thread packages/client/agents.md
Comment thread packages/client/agents.md Outdated
Comment thread packages/ai/README.md
Comment thread packages/client/tests/test_lifecycle.py
Comment thread packages/client/src/launchdarkly_ai_server/experimental/__init__.py
Comment thread packages/client/src/launchdarkly_ai_server/__init__.py
Comment thread packages/client/tests/test_skills.py Outdated
Comment thread packages/client/tests/test_skills_fdv2.py Outdated
jeffdupont and others added 2 commits October 23, 2026 14:11
all_skills, get_skill, get_skill_result, get_skills, skill_refs,
watch_skills and write_skills each report their client.* usage ID as
their first statement (TESTING.md §3.27). The watcher's initial and
follow-up reconciles call the non-reporting _write_skills.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

Comment thread packages/ai/README.md
jeffdupont and others added 2 commits October 23, 2026 14:24
…server 1.0.0

launchdarkly-ai-python doesn't pin launchdarkly-ai-server, so upgrading the barrel alone can leave
an older server installed, and importing a skills name then raises ImportError. The promotion
removed the README warning along with the experimental bullet. This restores it for the root
imports.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- agents.md: a rename of ld.skills.integrity_failure needs a ! commit, which is a minor bump on 0.x
  and a major after 1.0, not always a major.
- Test that lifecycle.py imports no skills module, so the claim in agents.md is checked now that
  test_lifecycle no longer asserts it through launchdarkly_ai_server.skills.
- test_skills' SKILLS_SURFACE docstring points at the root snapshot test that actually catches
  an addition.
- test_skills_fdv2 imports the internal skills_core and skills_fdv2 apart from the public names.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jeffdupont jeffdupont changed the title feat(AIC-3655)!: promote Agent Skills to core feat(skills)!: promote Agent Skills to core Oct 23, 2026

@XieX XieX left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approving. All eight comments from the first round are settled: six are fixed, and the shim and lazy-import decisions are backed by §0.5 and AIC-3674. Thanks for the spec links on the keyless-object rule; ai-sdks-monorepo#86 §3.25 reads the way you described.

Before merging, could you also deal with the follow-ups below?

Docs vs. the new usage reporting (4d6b3cb). The code is right per §3.27, but three places still say skills never calls client.track() or reports telemetry. Details are in the inline comments.

PR description. It still says "Usage IDs. None… this PR adds none." It should now list the seven client.* IDs: skillRefs, getSkill, getSkillResult, getSkills, allSkills, writeSkills and watchSkills.

Changelog. The squash commit only carries the promotion title. Since skills calls now send a usage event, a BEGIN_COMMIT_OVERRIDE with a second line such as feat(skills): report helper usage for the Agent Skills functions would give that its own changelog entry.

Merge timing. This approval doesn't change the "Do not merge yet" note. Please hold until the AIC-3655 blockers are cleared, and make sure this ships as the 1.0 release (AIC-3672). The barrel README now says skills need launchdarkly-ai-server 1.0.0, but the open release PR (#206) would cut 0.5.0. If this lands in a 0.5.0 release, that README note and its pip install "launchdarkly-ai-server>=1.0.0" command would point at a version that doesn't exist.

Comment thread packages/client/src/launchdarkly_ai_server/skills.py
Comment thread packages/client/agents.md Outdated
Comment thread packages/client/tests/test_skills.py Outdated
jeffdupont added a commit to launchdarkly/js-ai-sdk that referenced this pull request Oct 26, 2026
Jira: [AIC-3655](https://launchdarkly.atlassian.net/browse/AIC-3655)

> **Do not merge** until the blockers linked on AIC-3655 are fixed. This
PR releases together with the Python and Go promotion PRs (links added
later).

## What changed

- **Agent Skills is core.** All 35 Agent Skills names (functions,
stores, watcher, constants, factories and types) are exported from the
`@launchdarkly/ai-server` root with the same spelling, and are
**removed** from `@launchdarkly/ai-server/experimental`. This is
breaking under the 0.x rule, so it bumps the minor version.
- `@launchdarkly/ai-node` gets the names from its root through its
existing `export *`. Its `/experimental` entry keeps working and still
re-exports Evaluations from Code.
- Evaluations from Code stays experimental. The `/experimental` entry
point stays.
- The API reports (`etc/ai-server.api.md`,
`etc/ai-server-experimental.api.md`) are regenerated. The skills names
are added to `api-surface/ai-server.txt` as `+` (joining) and marked `-`
(leaving) in `api-surface/ai-server.experimental.txt`.
- The `skills` rows are removed from `changelog-sections` in
`release-please-config.json`. AGENTS.md now says `skills` is a core
scope.
- The shutdown hook is renamed from `experimental Agent Skills` to
`Agent Skills`. The no-store error message now points to
`@launchdarkly/ai-server`. Core doc comments no longer call Agent Skills
experimental.
- Tests: the root export snapshot now includes the skills values, the
experimental entry exports only the Evaluations values, a new test
checks that the API reports list every skills name at the root and none
in the experimental report, and the lifecycle test now expects the
`Agent Skills` hook after loading the root and no experimental hook.
- The integration fixtures import skills from the root and check that
`getSkill` is on the root and not on either `/experimental` subpath.
- The READMEs and both agents.md files are updated, including the
promotion note.
- **Usage IDs:** `main` reports no `experimental.*` skills usage IDs, so
this PR adds none. When the skills usage-reporting work (AIC-3555) lands
in this SDK, it must use `client.*` IDs.

## Migration

Change the import path from `'@launchdarkly/ai-server/experimental'` to
`'@launchdarkly/ai-server'` (or from
`'@launchdarkly/ai-node/experimental'` to `'@launchdarkly/ai-node'`).
Nothing else changes: names, signatures and behavior are the same.

## Test plan

Run in the worktree after `yarn install`:

- [x] `yarn code:check`: exit 0
- [x] `yarn build`: exit 0
- [x] `yarn typecheck`: exit 0
- [x] `yarn test`: exit 0 (client: 1826 passed, 11 skipped)
- [x] `yarn test:integration`: exit 0 (36 passed)
- [x] `yarn api:surface`: exit 0
- [x] `yarn test:api-surface`, `yarn test:api-breaking`, `yarn
lint:pkg`: exit 0
- [x] `yarn workspace @launchdarkly/ai-server api:check`: exit 0
- [ ] `yarn api:check`: exit 1, only because
`packages/claude-agents/etc/ai-claude-agents.api.md` is already out of
date on `main` (`ClaudeAgentsHostOptions` came in after the report was
last generated). This PR doesn't touch that package.

🤖 Generated with [Claude Code](https://claude.com/claude-code)


[AIC-3655]:
https://launchdarkly.atlassian.net/browse/AIC-3655?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

## Related PRs

Releases together with:
- launchdarkly/python-ai-sdk#210
- launchdarkly/go-ai-sdk#14

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Overview**
> **Agent Skills moves from `@launchdarkly/ai-server/experimental` to
the package root** (and the same via `@launchdarkly/ai-node`). All
skills APIs—stores, accessors, `writeSkills`/`watchSkills`, types—are
removed from the experimental entry point; **Evaluations from Code**
remains on `/experimental` only. This is a **breaking** 0.x change:
imports must switch from `.../experimental` to the root; names and
behavior are unchanged.
> 
> API Extractor reports and `api-surface/*.txt` are updated accordingly;
`skills` is dropped from release-please **Experimental** changelog
sections and AGENTS.md now treats `skills` as a core scope. Docs call
out that loading the **root** now pulls in Node built-ins (`node:fs`,
`node:path`, etc.) for skills, which can break non-Node edge runtimes
(tracked as AIC-3674).
> 
> Implementation follow-ups: shutdown hook renamed to `Agent Skills`;
skills helpers emit **`client.*` `$ld:ai:sdk:usage` IDs**; `watchSkills`
uses `writeSkillsInternal` so only the watcher reports usage. Tests,
webpack integration fixtures, and re-export assertions are aligned with
the new surface.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
ecef311. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
jeffdupont and others added 3 commits October 26, 2026 07:19
skill_refs now reports client.skillRefs through report_usage, so its
docstring and agents.md no longer call it free of telemetry. agents.md
names the helper usage event as the one client.track() path, so the
skills no-track rule does not read as forbidding it.

test_requires_no_client_or_store asserted track() was never called on a
client that was never installed. It now checks there is no client or
store and that the usage event is held for the next init.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#208 added the Claude Agents skills handler while Agent Skills was still
experimental, so it imported launchdarkly_ai_server.experimental.skills.
This PR removes that module, which broke the handler, its tests and
mypy once main was merged in. The handler itself stays in
launchdarkly_ai_claude_agents.experimental.skills.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ 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 d679fd2. Configure here.

ProviderHandler,
ReconcileReport,
SkillReference,
report_usage,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Skills imports need a newer server

Medium Severity

create_claude_agents_skills_handler now imports ReconcileReport, SkillReference, skill_refs, and write_skills from the launchdarkly_ai_server root, but launchdarkly-ai-claude-agents still depends on launchdarkly-ai-server>=0.4.1, which only exported those names from experimental.skills. Upgrading the handler alone raises ImportError.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit d679fd2. Configure here.

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.

2 participants