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.
| Strategy | Behaviour |
|---|---|
eager | Always injected into every request |
auto | Listed in a catalog — AI calls load_skill to fetch when relevant |
manual | Available 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-inlinedefineSkill
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;
}