Skills

Instruction playbooks the AI loads on demand — keeps the system prompt lean

Skills are Markdown instruction sets the AI loads at runtime. Instead of putting everything in the system prompt, skills are injected only when relevant.

StrategyBehaviour
eagerAlways injected into every request
autoListed in a catalog — AI calls load_skill to fetch when relevant
manualAvailable via load_skill but not advertised

Adding Skills

Use <SkillProvider> and useSkill inside your React app. Supports inline content only.

import { SkillProvider, defineSkill, useSkill } from "@yourgpt/copilot-sdk/react";

const brandVoice = defineSkill({
  name: "brand-voice",
  description: "Ensures responses match our brand tone",
  strategy: "eager",
  source: { type: "inline", content: "Always respond in a friendly, concise tone." },
});

// App-level — always active
export default function App() {
  return (
    <CopilotProvider widgetToken="...">
      <SkillProvider skills={[brandVoice]}>
        <YourApp />
      </SkillProvider>
    </CopilotProvider>
  );
}

// Page-level — active only while this component is mounted
function CheckoutPage() {
  useSkill({
    name: "checkout-flow",
    description: "Guides the user through checkout",
    strategy: "auto",
    source: { type: "inline", content: "1. Confirm cart  2. Check promo codes  3. Shipping..." },
  });

  return <CheckoutUI />;
}

useSkill auto-unregisters when the component unmounts — great for route-scoped skills.

Use loadSkills() in your API route. Supports inline, file (local .md files), and url (remote .md) sources.

skills/
├── brand-voice.md     # eager — always active
└── sql-expert.md      # auto — loaded on demand
// app/api/chat/route.ts
import path from "path";
import { loadSkills } from "@yourgpt/copilot-sdk/server";

export async function POST(req: Request) {
  const { messages } = await req.json();

  const { buildSystemPrompt, tools } = await loadSkills({
    dir: path.join(process.cwd(), "skills"),                // local .md files
    remoteUrls: ["https://cdn.myapp.com/skills/policy.md"], // remote URLs
  });

  return runtime.stream({
    system: buildSystemPrompt("You are a helpful assistant."),
    messages,
    tools,
  });
}

<SkillProvider> automatically forwards client skills to the server via __skills. Pass them to loadSkills to merge with server-side skills.

export async function POST(req: Request) {
  const { messages, __skills } = await req.json();

  const { buildSystemPrompt, tools } = await loadSkills({
    dir: path.join(process.cwd(), "skills"),  // server files take precedence
    clientSkills: __skills ?? [],             // client inline skills merged in
  });

  return runtime.stream({ system: buildSystemPrompt("..."), messages, tools });
}

Source precedence (highest → lowest):

server-dir  >  remote-url  >  client-inline

defineSkill

Type-safe helper for creating reusable skill definitions:

const mySkill = defineSkill({
  name: "api-docs-helper",
  description: "Helps users understand the Acme API",
  strategy: "auto",
  source: { type: "inline", content: "When explaining endpoints, include example requests..." },
});

// Reuse anywhere
<SkillProvider skills={[mySkill]} />

useSkillStatus

Observe the live skill registry from any component:

const { skills, count, has } = useSkillStatus();

// count            — number of active skills
// has("name")      — check if a skill is active
// skills           — full list of ResolvedSkill[]

Type Reference

type SkillStrategy = "eager" | "auto" | "manual";

type SkillSource =
  | { type: "inline"; content: string }
  | { type: "file"; path: string }       // server only
  | { type: "url"; url: string };        // server only

interface SkillDefinition {
  name: string;
  description: string;
  source: SkillSource;
  strategy?: SkillStrategy;  // default: "auto"
  version?: string;
}

On this page