Automatic learned skill delivery

Keep published Learning skills available to agents with verified snapshots, automatic refresh, and exact revision pins.

Learned skill delivery makes one Learning container's published skills available to an agent without another CLI download or process restart. A framework adapter adds an alphabetical catalog and two tools. The model decides when to load and follow a skill.

Developer instructions retain precedence. Learned skills cannot override the agent's role, safety rules, tool restrictions, or application policy.

Start with the Learning guide to collect Threads, configure daily runs, and review Skills. Before connecting an adapter, check that Skill delivery is enabled in the container's Skills tab. For guided setup, select Set up skill delivery there and copy the prompt into your coding agent.

Choose an adapter#

FrameworkPackageNative extension
BuiltInAgent@copilotkit/runtime/v2learnedSkills configuration
LangGraph Pythoncopilotkit-intelligence-langgraphcreate_skill_registry_middleware
LangGraph TypeScript@copilotkit/intelligence-langgraphcreateSkillRegistryMiddleware
Mastra@copilotkit/intelligence-mastracreateSkillRegistryProcessor
Google ADKcopilotkit-intelligence-adkSkillRegistry and SkillToolset
Microsoft Agent FrameworkCopilotKit.Intelligence.AgentFrameworkSkillRegistryContextProvider and AddCopilotKitIntelligenceSkills

Attach an adapter to the agents that need skills. Adapters do not inspect or rebuild arbitrary graphs or agent hierarchies. Subagent behavior follows the selected framework.

TypeScript uses the canonical client from @copilotkit/runtime/v2. Python uses copilotkit-intelligence-runtime. These dependencies include Runtime features beyond skill delivery. The .NET adapter targets net9.0 and uses CopilotKit.Intelligence.

Native setup#

These adapters require the server and canonical client releases described below.

BuiltInAgent#

Configure learnedSkills directly on BuiltInAgent. No wrapper or separate adapter package is required.

import { BuiltInAgent } from "@copilotkit/runtime/v2";

const agent = new BuiltInAgent({
  model: "openai/gpt-4o",
  prompt: "Follow the application's support policy.",
  learnedSkills: {
    containerId: "support-learning",
    // revision: "exact-revision-id", // Optional: pin a published revision.
  },
});

Set CPK_INTELLIGENCE_API_KEY for skill delivery and your model provider's key separately. The configuration also accepts an existing CopilotKitIntelligence instance as client, or explicit apiKey and apiUrl. These credentials apply to Intelligence, not the model provider. The environment fallbacks and refresh settings below apply.

Classic mode adds the catalog and both executable skill tools before the model call. When skills are available, the default step limit is 10 so the model can load and use guidance. An explicit maxSteps takes precedence. Without available skills, the existing default step limit remains unchanged.

Factory mode

BuiltInAgent fetches the snapshot before it calls your factory. Connect the catalog and tools to your model call:

import {
  BuiltInAgent,
  convertMessagesToVercelAISDKMessages,
} from "@copilotkit/runtime/v2";
import { openai } from "@ai-sdk/openai";
import { stepCountIs, streamText } from "ai";

const agent = new BuiltInAgent({
  type: "aisdk",
  learnedSkills: { containerId: "support-learning" },
  factory: ({ input, abortSignal, learnedSkills }) =>
    streamText({
      model: openai("gpt-4o"),
      system: [
        "Follow the application's support policy.",
        learnedSkills.catalog,
      ].filter(Boolean).join("\n\n"),
      messages: convertMessagesToVercelAISDKMessages(input.messages),
      tools: { ...learnedSkills.tools },
      stopWhen: stepCountIs(10),
      abortSignal,
    }),
});

Import BuiltInAgentFactoryContext from @copilotkit/runtime/v2 to annotate a factory context. Every factory receives a learnedSkills object. Its catalog is "" and its tools is {} when delivery is unconfigured or the verified snapshot contains no skills. Omitting the configuration disables all skill requests, even when delivery environment variables exist. With configuration, later runs check for newly published skills according to the freshness window.

The tools use AI SDK schemas and executors. TanStack and custom factories receive the same object and must adapt the tools to their model library; they are not TanStack-native tool definitions. Factory code owns the model call and its step limit. Keep the supplied catalog and tools together within that invocation. The tool map is read-only; spread it into a new object to add application tools.

Each run, including a resume, acquires one snapshot before factory or model work. Agent clones share the refresh cache; each invocation retains its own snapshot. Cancellation stops that invocation's delivery wait without cancelling another clone's shared refresh. Snapshots stay out of application state. Existing cached skills can cover transient failures, but a confirmed delivery denial blocks new execution.

Reserve copilotkit_load_skill and copilotkit_read_skill_file for delivery. Classic mode rejects conflicting client, configuration, or MCP tool names. Factory code must avoid overwriting these names when it combines tool maps.

LangGraph Python#

Use the middleware with native asynchronous agents from langchain.agents.create_agent:

from copilotkit_intelligence_langgraph import create_skill_registry_middleware
from langchain.agents import create_agent

skills = create_skill_registry_middleware()  # Uses the environment below.
try:
    await skills.initialize()
    agent = create_agent(
        "your-provider:your-model",
        system_prompt="Follow the application's support policy.",
        middleware=[skills],
    )
    result = await agent.ainvoke(
        {"messages": [{"role": "user", "content": "Help with a refund"}]}
    )
finally:
    await skills.aclose()

Use ainvoke or astream; synchronous execution is unsupported. The adapter supports LangChain >=1.2.16,<2 and LangGraph >=1.1.10,<2. Attach middleware explicitly to each agent that needs skills. Arbitrary compiled graphs are outside this integration.

LangGraph TypeScript#

Use Node.js 20.19 or later with native LangChain agents:

import { createAgent } from "langchain";
import {
  SkillRegistry,
  createSkillRegistryMiddleware,
} from "@copilotkit/intelligence-langgraph";

const registry = new SkillRegistry(); // Uses the environment below.
await registry.initialize(); // Catch this error in your application's startup code.
const skills = createSkillRegistryMiddleware({ registry });
const agent = skills.wrapAgent(
  createAgent({
    model: "your-provider:your-model",
    systemPrompt: "Follow the application's support policy.",
    middleware: [skills],
  }),
);
const result = await agent.invoke({
  messages: [{ role: "user", content: "Help with a refund" }],
});

The wrapper is currently required because affected LangChain/LangGraph versions cannot keep private transient middleware state correctly. Use the wrapped agent for invoke, stream, and streamEvents, including native Command resumes. withConfig retains the wrapper. Apply default cancellation signals with agent.withConfig after wrapping, or pass the signal to each invocation. Stream objects, readers, and native cancellation remain available. Calling the middleware without its wrapper returns INVALID_CONFIG.

After the native framework fix passes the same lifecycle tests, middleware-only setup will become the default. The wrapper will be optional, and existing wrapped agents will continue to work.

Attach this middleware and its wrapper to each selected agent. Several agents can share one registry, but each wrapped invocation captures its own snapshot. Skills do not propagate automatically to arbitrary subagents. The wrapper supports the native agent's graph execution entry points for integrations that access .graph; graph batching and arbitrary compiled graph adaptation are outside this integration.

The supported dependency ranges are LangChain >=1.5.11,<2, LangGraph >=1.4.14,<2, and LangChain core >=1.2.10,<2. The registry owns in-memory snapshots and performs no filesystem writes. Your application retains ownership of an injected canonical client.

Mastra#

Use Node.js 22.13 or later with @mastra/core>=1.0.0,<2. Install @copilotkit/intelligence-mastra alongside Mastra, then register the processor and its tools on a native Agent:

import { Agent } from "@mastra/core/agent";
import {
  SkillRegistry,
  createSkillRegistryProcessor,
} from "@copilotkit/intelligence-mastra";

const registry = new SkillRegistry(); // Uses the environment below.
await registry.initialize(); // Catch this error in your application's startup code.
const skills = createSkillRegistryProcessor({ registry });
const agent = skills.wrapAgent(
  new Agent({
    id: "support",
    name: "Support",
    model: "openai/gpt-4.1",
    instructions: "Follow the application's support policy.",
    inputProcessors: [skills],
    tools: { ...skills.tools },
  }),
);
const result = await agent.generate("Help with a refund.");

Keep other processors and tools in the same arrays and maps. Reserve the names copilotkit_load_skill and copilotkit_read_skill_file for this adapter.

Call the wrapped agent for generate, stream, resumeGenerate, and resumeStream. The wrapper checks delivery before native execution and preserves Mastra's stream result. It also covers native tool approval and decline methods when your installed Mastra version provides them: approveToolCall, declineToolCall, approveToolCallGenerate, and declineToolCallGenerate. A resume starts a new invocation and captures the current verified snapshot, including when a tool runs before the next model call.

Register the processor and tools, and wrap each selected agent. Several agents can share a registry; each invocation keeps its own snapshot. Subagents follow Mastra's native propagation rules. Networks, legacy methods, background workers, and separate durable-worker dispatch are outside this integration.

Pass abortSignal in the invocation options to cancel both the delivery wait and native execution. A signal set only in the agent's defaultOptions applies to native execution, but cannot cancel the delivery wait that runs before it. Cancelling one invocation does not cancel a registry refresh shared with other callers.

Google ADK#

Add SkillToolset to a standard ADK LlmAgent:

from copilotkit_intelligence_adk import SkillRegistry, SkillToolset
from google.adk.agents import LlmAgent

registry = SkillRegistry()
await registry.initialize()
agent = LlmAgent(
    name="support",
    model="your-model",
    instruction="Follow the application's support policy.",
    tools=[SkillToolset(registry)],
)
# Run this agent with your application's normal async ADK Runner.
# Call await registry.aclose() after all runners finish.

The adapter supports google-adk>=1.17,<2. Several selected agents can share one registry. Closing a toolset does not close that shared registry. Native resumed runs receive a fresh invocation pin; session state contains no snapshot or lock.

Microsoft Agent Framework#

Use the provider's native agent factory with your application's IChatClient:

using CopilotKit.Intelligence.AgentFramework;
using Microsoft.Agents.AI;

using var skills = new SkillRegistryContextProvider(new SkillRegistryOptions());
await skills.InitializeAsync();
var agent = skills.CreateAgent(chatClient, new ChatClientAgentOptions
{
    Name = "support",
    ChatOptions = new() { Instructions = "Follow the application's support policy." }
});
var response = await agent.RunAsync("Help with a refund.");

The adapter targets .NET 9 and Agent Framework >=1.0.0,<2.0.0. AddCopilotKitIntelligenceSkills also registers a keyed provider and native agent through dependency injection. Use this extension or CreateAgent for complete invocation checks. Background responses and continuation tokens are unsupported because the framework bypasses context providers for those calls.

Configure one container#

An injected canonical Intelligence client supplies its existing project key, endpoint, and HTTP lifecycle. Your application retains ownership of that client. The adapter does not construct a second authenticated transport.

Environment-based setup uses these variables:

CPK_INTELLIGENCE_API_KEY=your-project-key
CPK_INTELLIGENCE_LEARNING_CONTAINER_ID=expense-review
# Self-hosted deployments only:
INTELLIGENCE_API_URL=https://intelligence.example.com
# Optional exact revision; omit to follow latest:
CPK_INTELLIGENCE_SKILLS_REVISION=42

Explicit configuration overrides environment values. An injected client overrides connection environment values. Freshness and request timeout each default to five seconds; debug logging defaults to false. Configure these behavior options in code.

Initialization can run during application startup. A valid empty container initializes successfully. Initialization failures are catchable and retryable; the adapter never terminates the process. Model work cannot start until a verified snapshot exists.

Refresh and invocation behavior#

Before an invocation, the registry checks whether its last successful check falls within the freshness window. When a check is due, that invocation waits for it. Concurrent invocations share one request, with no internal retry. An unchanged response resets the freshness window without transferring the ZIP again.

Each invocation keeps one complete snapshot for its model and tool calls. A later refresh affects later invocations. Revision identifiers are opaque: pass the exact string without parsing, incrementing, or comparing it numerically.

ModeBehavior
latestAdopt the complete newest published snapshot after a successful check.
Exact revisionKeep the selected complete skill set while continuing authorization and revocation checks.

Published revisions have no automatic expiry. A revoked revision cannot be used by new invocations once the adapter receives that denial. An invocation already in progress finishes with its captured snapshot.

Read tools#

The framework adapters keep both tools registered even when the snapshot is empty. BuiltInAgent omits both tools for an empty snapshot; its factory receives tools: {}. With available skills, the tools are:

  • copilotkit_load_skill(skill_name) returns SKILL.md and the supporting file list.
  • copilotkit_read_skill_file(skill_name, path) returns one supporting UTF-8 text file.

Lookups match the invocation's manifest. Unknown names, unknown paths, and unsupported content use the framework's tool-error behavior. The adapter never executes scripts or writes skill files to disk.

Failures and status#

A cold registry returns a typed error when it cannot load a valid snapshot. After a successful load, a network failure, timeout, unavailable server, or unreadable replacement keeps the previous snapshot and marks it stale.

There is no maximum stale age. A network-isolated process can retain its last verified snapshot until connectivity returns. Restarting clears that in-memory snapshot. Confirmed authentication, authorization, entitlement, delivery disablement, or revocation blocks new invocations instead of falling back to stale content.

The read-only status contains initialized, revision, mode, lastCheckedAt, stale, and lastError. Errors expose a stable code, safe message, retryable, and cause. Debug mode uses the normal language logger and excludes credentials, prompts, skill bodies, and file contents.

Migrate from downloaded skills#

Remove the old manual Learning-directory wiring when you enable an adapter for the same container. Keep unrelated static or hand-authored skills as needed. The adapter does not scan, change, or delete downloaded files.

copilotkit skills download remains supported for inspection, offline use, and unsupported frameworks. See the Learning guide for the manual workflow.

Deployment requirements#

Managed and self-hosted Intelligence use the same delivery contract. The server migration and v1 delivery endpoint must deploy before adapters rely on them. Each adapter also requires a published canonical client version with the learned-snapshot operation.

Pausing new Learning runs does not stop delivery. Entitlement, explicit delivery disablement, and revision revocation control access to published snapshots separately.