스킬
스킬 (Skills)
딥 에이전트(deep agent)의 역량을 스킬(skill)로 확장하는 방법을 알아봐요.
스킬은 워크플로, 모범 사례, 스크립트, 참조 문서, 템플릿 같은 도메인 전문 지식을 재사용 가능한 디렉토리에 묶어요. 에이전트는 시작 시 콘텐츠의 요약을 받고, 관련이 있을 때만 포함된 파일을 발견·읽어요.
스킬은 시작 시 요약만 로드하고 작업에 필요할 때 전체 지침을 읽어 컨텍스트 비대화를 피하는 데 도움을 줍니다. 스킬을 에이전트와 프로젝트 간에 공유할 수 있고, 단일 에이전트에 여러 스킬을 구성해 각각이 별개의 역량을 담당하게 할 수 있어요.
참고: 스킬에는
deepagents>=1.7.0이 필요합니다.
팁: LangChain 생태계 작업에서 에이전트 성능을 개선하는 바로 사용 가능한 스킬은 LangChain Skills 저장소를 참고하세요.
출처: 문서
본문
사용법
-
최상위 skills 디렉토리 만들기 — 프로젝트의 모든 스킬을 담을 디렉토리를 만드세요(예: 백엔드 루트 아래의
skills/). -
skills 디렉토리 안에 스킬용 하위 디렉토리 만들기 — 각 스킬은
SKILL.md파일(이름과 설명이 담긴 YAML frontmatter 뒤에 에이전트가 스킬 활성화 시 따르는 지침이 오는 마크다운 파일)을 포함하는 디렉토리입니다. 스킬 디렉토리에는 스크립트, 참조 문서, 템플릿 같은 보조 파일을 선택적으로 포함할 수 있어요. 딥 에이전트 스킬은 Agent Skills 명세를 따릅니다.skills/ └── langgraph-docs/ ├── SKILL.md ├── scripts/fetch_docs.py └── references/ ├── api-patterns.md └── style-guide.md -
YAML frontmatter와 지침이 담긴
SKILL.md추가하기 —SKILL.md는 YAML frontmatter로 시작하고 그 뒤에 마크다운 지침이 옵니다:--- name: langgraph-docs description: Use this skill for requests related to LangGraph in order to fetch relevant documentation to provide accurate, up-to-date guidance. --- # langgraph-docs ## Overview This skill explains how to access LangGraph documentation to help answer questions and guide implementation. ## Instructions ### 1. Fetch the documentation index Use the fetch_url tool to read the following URL: https://docs.langchain.com/llms.txt This provides a structured list of all available documentation with descriptions. ### 2. Select relevant documentation Based on the question, identify 2-4 most relevant documentation URLs from the index. Prioritize: - Specific how-to guides for implementation questions - Core concept pages for understanding questions - Tutorials for end-to-end examples - Reference docs for API details ### 3. Fetch and synthesize Use the fetch_url tool to read the selected documentation URLs, then answer the user's question. Give a direct answer first, include the minimum necessary context, and link to the source pages rather than quoting long passages.참고: 보조 리소스를
SKILL.md에서 해당 파일이 무엇을 담고 언제 사용하는지 설명과 함께 참조하세요. 에이전트는 스킬 지침의 참조를 통해 이 파일들을 발견해요. -
에이전트 생성 시 skills 경로 전달하기 — 에이전트 생성 시
skills인자에 최상위 skills 디렉토리의 경로를 전달하세요:import { createDeepAgent, FilesystemBackend } from "deepagents"; const backend = new FilesystemBackend({ rootDir: process.cwd() }); const agent = await createDeepAgent({ model: "anthropic:claude-sonnet-4-6", backend, skills: ["/skills/"], });이 예시는
FilesystemBackend를 사용해 스킬을 디스크에서 로드합니다. 원격 소스에서 스킬을 로드하는 방법을 포함한 다른 저장 옵션은 백엔드와 원격 스킬 로딩을 참고하세요.각 소스 경로는 스킬 디렉토리를 담은 디렉토리를 가리키거나,
SKILL.md가 있는 스킬 디렉토리 자체를 직접 가리킬 수 있어요.skills(리스트, 선택): 스킬 소스 경로의 목록입니다. 경로는 슬래시를 사용해 백엔드 루트 기준으로 지정해야 해요. 생략하면 스킬이 로드되지 않습니다.StateBackend(기본값)를 사용할 때는invoke(files={...})로 스킬 파일을 제공하세요. 파일 내용은deepagents.backends.utils의create_file_data()로 포맷해야 하며, raw 문자열은 지원되지 않습니다.FilesystemBackend/StoreBackend에서는 백엔드를 만들고backend.uploadFiles()로 스킬 파일을 추가한 뒤createDeepAgent에 백엔드를 전달하세요.FilesystemBackend에서는virtualMode: true를 사용해rootDir아래 경로를 샌드박스 처리할 수 있어요.rootDir아래 디스크에 이미 있는 스킬은 업로드 없이 로드됩니다.- 우선순위: 같은 이름의 스킬에 대해 나중에 나열된 소스가 앞선 소스를 덮어써요(마지막 것이 우선). 스킬을 나중 소스가 우선하게 레이어링할 수 있게 해주며, 예를 들어 프로젝트별 버전이 기본 스킬을 재정의할 수 있어요.
-
에이전트 호출하기 —
invoke()로 에이전트에 작업을 보내세요. 시작 시 에이전트는 frontmatter에서 각 스킬의name과description을 시스템 프롬프트로 로드합니다. 작업이 스킬의 설명과 일치하면 에이전트는 그 스킬의SKILL.md를 읽고 지침을 따릅니다.const result = await agent.invoke( { messages: [{ role: "user", content: "What is LangGraph?" }] }, { configurable: { thread_id: "1" } }, );
스킬의 동작 방식
에이전트가 더 복잡한 작업을 맡을수록 필요한 컨텍스트도 함께 커집니다. 모든 지침을 시스템 프롬프트에 로드하면 현재 작업과 무관한 정보에 토큰을 낭비하고, 세션마다 같은 안내를 수동으로 제공하는 것은 확장되지 않습니다.
정보: 스킬은 점진적 공개(progressive disclosure) 를 사용합니다. 에이전트는 스킬 정보를 한 번에 모두가 아니라 계층적으로 로드합니다. 시작 시에는 각 스킬의 이름과 설명만 보여요. 스킬이 호출되면 전체
SKILL.md지침을 읽습니다. 보조 파일은 지침이 요구할 때에만 나중에 로드됩니다.
스킬은 세 단계로 로드됩니다. 각 단계는 작업이 필요할 때만 세부 정보를 추가해요:
| 단계 | 로드되는 것 | 시점 |
|---|---|---|
| 1. 메타데이터 | SKILL.md frontmatter의 name과 description |
에이전트 시작 시, 구성된 모든 스킬에 대해 |
| 2. 지침 | 전체 SKILL.md 본문 |
스킬이 호출되었을 때 |
| 3. 리소스 | scripts/, references/, assets/ 아래의 보조 파일 |
호출 후 지침이 참조할 때 필요에 따라 |
특정 시점에 에이전트 컨텍스트에 나타나는 내용은 위 다이어그램과 같습니다. 시작 시 모든 스킬의 1단계 메타데이터가 시스템 프롬프트에 있습니다. 스킬이 호출되면 2단계 지침이 컨텍스트에 추가되고, 3단계 파일은 에이전트가 호출 후 읽을 때까지 백엔드에 남아 있게 됩니다.
Deep Agents에서 SkillsMiddleware(skills를 전달할 때 Deep Agents 스택의 일부)는 처음 두 단계를 처리하고, 세 번째 단계는 LLM이 처리합니다:
- 발견(1단계): 에이전트 시작 시 미들웨어가 구성된 스킬 경로를 스캔하고 각
SKILL.mdfrontmatter를 파싱해name과description필드를 시스템 프롬프트에 주입합니다. - 읽기(2단계): 에이전트가 스킬을 호출하면
read_file을 통해 전체SKILL.md콘텐츠를 읽습니다. - 실행(3단계): 호출 후 에이전트는 스킬의 지침을 따르고 지침이 요구하는 만큼만 보조 파일(스크립트, 참조, 자산)을 읽습니다.
스킬 사용 시기
에이전트에게 비슷한 지침을 반복해서 주고 있다면, 특히 상세하고 여러 단계가 포함된 지침이라면 이를 에이전트용 코드로 정리하는 것을 고려하세요. 그러면 앞으로 비슷한 작업을 수행하려 할 때 에이전트가 이미 무엇을 해야 하는지 알게 됩니다.
팁: 에이전트와 함께 작업한 작업에 대해 에이전트에게 스킬 작성을 요청할 수도 있어요.
스킬은 특히 다음을 코드화할 때 유용합니다:
- 단계별 워크플로: 레시피처럼 여러 단계에 걸치는 워크플로.
- 도메인별 지식: 에이전트가 워크플로를 위해 도구를 사용하는 방법을 지시. 예를 들어 스킬이 접근할 수 있는 참조 정보나 스크립트를 포함해 정보를 어디서 가져올지 알려주는 정보를 포함하세요.
- 실행 가능한 코드가 있는 지침: 에이전트가 실행할 수 있는 스크립트나 모듈과 절차를 묶어, 매번 지침에서 재생성하는 대신 검증된 로직을 따르게 하세요. 스킬로 코드 실행 참고.
- 지침: 가드레일에 관한 보조 지침을 에이전트에 제공. 예를 들어 특정 형식이나 스타일 가이드를 따르거나 워크플로의 일부로 항상 테스트를 실행하도록 지정.
효과적인 스킬 작성
Agent Skills 명세에는 신뢰할 수 있는 발견·활성화를 위한 스킬 구성 지침이 포함되어 있어요. 다음 권장사항은 그 기반 위에 Deep Agents를 위한 실용적 패턴을 더합니다.
frontmatter는 간결하게 유지하고 SKILL.md 본문은 5,000 토큰 미만으로 하세요. 모든 스킬의 frontmatter는 발견 시 시스템 프롬프트에 추가되는 반면, 전체 본문은 활성화될 때만 읽힙니다. 두 계층을 작게 유지하면 컨텍스트 창을 채우지 않고도 많은 스킬을 로드할 수 있어요.
구체적인 설명을 작성하세요. 발견 중 description 필드는 에이전트가 각 스킬에 대해 보는 유일한 정보입니다. 좋은 설명은 스킬이 무엇을 하는지와 언제 활성화해야 하는지를 모두 말해주며, 에이전트가 매칭할 수 있는 구체적인 키워드를 담습니다:
# Good: specific about what and when
description: >-
Extract text and tables from PDF files, fill PDF forms, and merge
multiple PDFs. Use when working with PDF documents or when the user
mentions PDFs, forms, or document extraction.
# Poor: too vague for reliable matching
description: Helps with PDFs.
관련 도메인의 스킬이 여러 개 있을 때는 설명을 명확히 구분하세요. 겹치는 설명은 에이전트가 잘못된 스킬을 활성화하거나 옵션 사이에서 망설이게 만듭니다. 두 스킬이 비슷한 목적을 제공한다면 하나로 통합하세요.
지침을 집중적으로 유지하세요. Agent Skills 명세는 SKILL.md를 500줄 미만으로 유지할 것을 권장합니다. 지침이 길어지면 상세 참조 자료를 보조 리소스 파일로 옮기고 메인 SKILL.md에서 참조하세요:
skills/
└── data-pipeline/
├── SKILL.md
└── references/
├── schema-reference.md
└── error-codes.md
에이전트는 지침이 요구할 때만 참조 파일을 로드해, 점진적 공개 각 계층의 크기를 적절히 유지합니다. 파일 참조는 SKILL.md에서 한 단계 깊이로 유지하고, 에이전트가 필요한 정보에 도달하려 여러 번 읽게 만드는 깊게 중첩된 참조 체인은 피하세요.
에이전트용으로 지침을 구조화하세요. SKILL.md 본문을 에이전트가 따를 수 있는 명확한 지침으로 작성하세요:
- 단계별 절차: 여러 단계 워크플로용
- 의사 결정 기준: 접근 방식 선택용
- 예상 입력·출력 예시: 성공이 어떤 모습인지 에이전트가 알도록
- 엣지 케이스: 에이전트가 처리하거나 사용자에게 알려야 할 경우
스킬 수를 관리하세요. 범위가 명확한 스킬이 적은 수가 겹치는 스킬이 많은 것보다 낫습니다. 비슷한 설명의 스킬 수가 늘면 적절한 스킬을 선택하는 에이전트의 능력이 떨어집니다. 관련 스킬이 많다면 다음을 고려하세요:
- 관련 역량을 각 하위 작업 섹션이 있는 단일 스킬로 통합
- 여러 하위 작업을 다루면서 메인
SKILL.md를 간결하게 유지하도록 참조 파일 사용
팁:
skills-ref검증 도구를 사용해SKILL.mdfrontmatter가 Agent Skills 명세의 명명·형식 규칙을 따르는지 확인하세요.
보조 리소스 추가하기
SKILL.md 외에도 스킬 디렉토리는 추가 파일이나 디렉토리를 포함할 수 있어요. Agent Skills 명세는 일반적인 리소스 유형을 위한 세 개의 선택적 디렉토리를 정의합니다. Deep Agents는 발견·활성화 시 이 파일들을 로드하지 않으며, 에이전트는 SKILL.md 지침이 말할 때만 이를 읽거나 실행합니다.
scripts/
scripts/ 디렉토리는 에이전트가 실행할 수 있는 실행 코드(예: API 클라이언트, 데이터 변환, 검증 검사)를 담습니다. 스크립트는:
- 자체 포함되거나 의존성을 명확히 문서화해야 하고
- 도움이 되는 오류 메시지를 포함해야 하며
- 엣지 케이스를 우아하게 처리해야 합니다.
지원되는 언어는 에이전트 설정에 따라 달라집니다. 일반적인 옵션으로 Python, Bash, JavaScript/TypeScript가 있어요. 읽기만 하지 않고 실행하려면 스킬로 코드 실행을, 셸이 필요하면 샌드박스 스크립트를 참고하세요.
references/
references/ 디렉토리는 에이전트가 필요 시 읽는 보조 문서를 담습니다. SKILL.md에는 너무 상세하지만 여전히 작업별로 중요한 자료(예: REFERENCE.md 상세 기술 참조, FORMS.md 템플릿·구조화 데이터 형식, finance.md/legal.md 같은 도메인별 가이드)에 사용하세요. 개별 참조 파일은 집중적으로 유지하세요. 에이전트는 필요할 때만 로드하므로 파일이 작을수록 컨텍스트를 덜 사용합니다.
assets/
assets/ 디렉토리는 에이전트가 사용하되 지침으로 읽을 필요는 없는 정적 리소스(문서·구성 템플릿, 이미지(다이어그램·예시), 데이터 파일(조회표·스키마))를 담습니다. SKILL.md에서 에이전트가 각 자산을 언제 열거나 복사해야 하는지 설명하세요.
SKILL.md에서 파일 참조하기
보조 파일을 참조할 때는 스킬 루트 기준 상대 경로를 사용하세요:
For API details, see the [reference guide](references/api-patterns.md).
To extract tables from a PDF, run:
scripts/extract.py
참조하는 각 파일에 대해 그 내용과 에이전트가 언제 사용해야 하는지를 명시하세요. 참조는 SKILL.md에서 한 단계 깊이로 유지하고, 에이전트가 여러 번 읽게 만드는 깊게 중첩된 참조 체인은 피하세요.
백엔드와 원격 스킬 로딩
Deep Agents는 스킬 파일을 저장·관리하는 방법에 따라 여러 백엔드를 지원합니다:
StateBackend: 현재 스레드에 대한 LangGraph 에이전트 상태에 파일을 저장.StoreBackend: 지속적·교차 스레드 저장을 위해 LangGraph 스토어에 파일을 저장.FilesystemBackend: 구성 가능한root_dir아래 디스크에서 스킬 파일을 읽고 씀.
다음은 각 백엔드에서 스킬을 로드하는 예시입니다(StateBackend/StoreBackend/FilesystemBackend). 세 백엔드 모두 SKILL.md를 https://raw.githubusercontent.com/langchain-ai/deepagentsjs/refs/heads/main/examples/skills/langgraph-docs/SKILL.md에서 가져와 /skills/ 루트 아래에 배치합니다:
// StateBackend: invoke(files={...})로 스킬 파일을 전달합니다.
import { createDeepAgent, StateBackend, type FileData } from "deepagents";
import { MemorySaver } from "@langchain/langgraph";
const checkpointer = new MemorySaver();
const backend = new StateBackend();
function createFileData(content: string): FileData {
const now = new Date().toISOString();
return {
content: content.split("\n"),
created_at: now,
modified_at: now,
};
}
const skillsFiles: Record<string, FileData> = {};
const skillUrl =
"https://raw.githubusercontent.com/langchain-ai/deepagentsjs/refs/heads/main/examples/skills/langgraph-docs/SKILL.md";
const response = await fetch(skillUrl);
const skillContent = await response.text();
skillsFiles["/skills/langgraph-docs/SKILL.md"] = createFileData(skillContent);
const agent = await createDeepAgent({
model: "anthropic:claude-sonnet-4-6",
backend,
checkpointer, // Required !
// IMPORTANT: deepagents skill source paths are virtual (POSIX) paths relative to the backend root.
skills: ["/skills/"],
});
const config = { configurable: { thread_id: `thread-${Date.now()}` } };
const result = await agent.invoke(
{
messages: [{ role: "user", content: "what is langraph?" }],
files: skillsFiles,
},
config,
);
// StoreBackend: store에 스킬 파일을 업로드합니다 (InMemoryStore 예시).
import { createDeepAgent, StoreBackend } from "deepagents";
import { InMemoryStore, MemorySaver } from "@langchain/langgraph";
const checkpointer = new MemorySaver();
const store = new InMemoryStore();
const backend = new StoreBackend({
namespace: () => ["filesystem"],
store,
});
const skillUrl =
"https://raw.githubusercontent.com/langchain-ai/deepagentsjs/refs/heads/main/examples/skills/langgraph-docs/SKILL.md";
const response = await fetch(skillUrl);
const skillContent = await response.text();
await backend.uploadFiles([
["/skills/langgraph-docs/SKILL.md", new TextEncoder().encode(skillContent)],
]);
const agent = await createDeepAgent({
model: "anthropic:claude-sonnet-4-6",
backend,
store,
checkpointer,
// IMPORTANT: deepagents skill source paths are virtual (POSIX) paths relative to the backend root.
skills: ["/skills/"],
});
const config = {
recursionLimit: 50,
configurable: { thread_id: `thread-${Date.now()}` },
};
const result = await agent.invoke(
{ messages: [{ role: "user", content: "what is langraph?" }] },
config,
);
// FilesystemBackend: 디스크에서 스킬 파일을 읽고 씁니다.
import { createDeepAgent, FilesystemBackend } from "deepagents";
import { MemorySaver } from "@langchain/langgraph";
const checkpointer = new MemorySaver();
const skillUrl =
"https://raw.githubusercontent.com/langchain-ai/deepagentsjs/refs/heads/main/examples/skills/langgraph-docs/SKILL.md";
const response = await fetch(skillUrl);
const skillContent = await response.text();
let backend = new FilesystemBackend({
rootDir: process.cwd(),
virtualMode: true,
});
await backend.uploadFiles([
["/skills/langgraph-docs/SKILL.md", new TextEncoder().encode(skillContent)],
]);
const agent = await createDeepAgent({
model: "anthropic:claude-sonnet-4-6",
backend,
// IMPORTANT: deepagents skill source paths are virtual (POSIX) paths relative to the backend root.
skills: ["/skills/"],
interruptOn: {
read_file: true,
write_file: true,
delete_file: true,
},
checkpointer, // Required for filesystem operations!
});
const config = { configurable: { thread_id: `thread-${Date.now()}` } };
const result = await agent.invoke(
{ messages: [{ role: "user", content: "what is langraph?" }] },
config,
);
스킬 가용성
모든 실행이 모든 스킬을 필요로 하지는 않습니다. skills에 전달하는 경로를 선택하고, 그 경로를 컨텍스트별 저장소에 대해 해석하거나, 여러 스킬 소스를 결합해 에이전트가 볼 수 있는 스킬을 제어할 수 있어요. 컨텍스트는 요청 핸들러, 인증 클레임, 그래프 팩토리, 배포 구성 또는 다른 애플리케이션 로직에서 올 수 있습니다.
컨텍스트로 스킬 선택
에이전트를 만들기 전에 skills 배열을 선택하세요. 스킬이 공통 위치에 있고 애플리케이션이 현재 역할·테넌트·사용자·요청 유형에 어떤 경로가 적용되는지 결정할 때 사용합니다:
import { createDeepAgent } from "deepagents";
const SKILLS_BY_ROLE: Record<string, string[]> = {
engineering: [
"/skills/code-review/",
"/skills/testing/",
"/skills/deployment/",
],
data: [
"/skills/sql-analysis/",
"/skills/visualization/",
"/skills/data-pipeline/",
],
support: ["/skills/ticket-triage/", "/skills/runbook/"],
};
function createAgentForUser(userRole: string) {
return createDeepAgent({
model: "anthropic:claude-sonnet-4-6",
skills: SKILLS_BY_ROLE[userRole] ?? [],
});
}
이 패턴은 각 스킬의 유지 관리되는 사본 하나를 유지하면서 각 에이전트에 전달되는 경로만 달리합니다. 배포에서 그래프 팩토리는 사용자 정보를 파싱하고 올바른 스킬 경로로 에이전트를 구성하기 자연스러운 위치입니다.
참고: SDK는
skills에 전달한 소스만 로드합니다. CLI 디렉토리(예:~/.deepagents/...또는~/.agents/...)를 자동으로 스캔하지 않아요. SDK 코드에서 CLI 스타일 계층을 원한다면 모든 원하는 소스를 낮은 우선순위에서 높은 우선순위 순서로 명시적으로 전달하세요:[ "<user-home>/.deepagents/{agent}/skills/", "<user-home>/.agents/skills/", "<project-root>/.deepagents/skills/", "<project-root>/.agents/skills/", ]그런 다음 에이전트 생성 시 그 정렬된 목록을
skills로 전달하세요.
스킬 라이브러리 격리
같은 스킬 경로가 사용자·역할·테넌트·워크스페이스·환경에 따라 다른 파일로 해석되어야 할 때 격리된 라이브러리를 사용하세요. 예를 들어 모든 에이전트가 skills=["/skills/"]를 받게 하고, 백엔드가 현재 신원 또는 배포 컨텍스트로 범위가 지정된 저장소에 대해 /skills/를 해석할 수 있습니다.
다음 예시는 StoreBackend를 사용하지만, 동일 패턴은 런타임 컨텍스트를 기준으로 파일을 해석할 수 있는 어떤 백엔드에도 적용됩니다:
import {
createDeepAgent,
CompositeBackend,
StateBackend,
StoreBackend,
} from "deepagents";
const agent = await createDeepAgent({
model: "anthropic:claude-sonnet-4-6",
skills: ["/skills/"],
backend: new CompositeBackend(new StateBackend(), {
"/skills/": new StoreBackend({
namespace: (ctx) => [
ctx.assistantId ?? "default",
ctx.config?.configurable?.user_id ?? "anonymous",
],
}),
}),
});
이렇게 하면 백엔드가 에이전트가 접근할 수 있는 라이브러리를 강제하는 동안 에이전트 구성은 안정적으로 유지됩니다. 범위는 사용자별일 필요 없습니다. 역할, 테넌트, 워크스페이스, 조직, 환경, 요청 유형 등 애플리케이션이 사용하는 어떤 경계가 되어도 됩니다.
공유 라이브러리를 채우려면 애플리케이션 코드나 관리 워크플로에서 스토어를 시드하세요:
- 워크스페이스 전역 스킬은 조직 ID별로 네임스페이스를 지정하세요. 에이전트가 라이브러리를 사용하되 수정하지 않아야 할 땐 읽기 전용 스킬과 함께 사용하세요.
- 각 사용자가 독립 라이브러리가 필요하면 위 예시처럼 사용자 ID별로 네임스페이스를 지정하세요.
스토어를 /company-policies/SKILL.md 같은 키와 content·encoding 필드를 포함하는 값으로 시드하세요. 스토어에서 레코드를 읽기 전에 /skills/ 라우트 접두사가 제거됩니다.
공유 라이브러리와 개인 라이브러리를 결합할 수도 있어요: /skills/approved/는 조직 범위 StoreBackend로, /skills/editable/는 사용자 범위 백엔드로 라우팅하고 두 경로를 skills에 전달하세요. 쓰기 가능한 스킬 참고.
여러 소스 구성
에이전트가 둘 이상의 라이브러리를 봐야 할 때 여러 스킬 경로를 전달하세요. 예를 들어 승인된 조직 스킬, 팀별 워크플로, 요청별 지침을 결합할 수 있어요:
import { createDeepAgent } from "deepagents";
const agent = await createDeepAgent({
model: "anthropic:claude-sonnet-4-6",
skills: ["/skills/org/", "/skills/team/", "/skills/request/"],
});
각 경로는 같은 백엔드, 다른 백엔드 라우트, 또는 런타임 컨텍스트로 범위가 지정된 백엔드를 가리킬 수 있어요. 스킬 접근·공유·워크스페이스 수준 가시성을 처리하는 관리형 솔루션은 Fleet skills를 참고하세요.
스킬 다시 로드
스킬은 스레드당 한 번 로드되어 에이전트 상태에 유지되므로, 그 스레드의 이후 모든 모델 호출은 같은 목록을 재사용합니다. 그 이후에 스킬을 추가·편집·삭제해도 모델에는 도달하지 않습니다. 이는 체크포인터가 구성된 경우에 적용됩니다. 체크포인터가 없으면 상태가 실행 간에 유지되지 않으므로 매 실행마다 스킬을 다시 로드합니다.
저장된 메타데이터를 재설정하면 다음 모델 호출에서 모든 소스를 다시 로드합니다.
참고: 로컬 실행에는 체크포인터가 없는 경우가 많아 스킬 편집이 즉시 적용되고 스킬이 자체적으로 다시 로드되는 것처럼 보입니다. LangSmith Deployments는 영구 체크포인터를 자동 구성하므로, 배포 후에는 같은 에이전트가 스레드 수명 동안 스킬을 유지합니다. 프로덕션으로 이동 참고.
참고: 스킬 다시 로드에는
deepagents>=1.14.0이 필요합니다.
단일 호출에서 재설정 시점에 다시 로드하고 실행하려면 재설정을 실행 입력으로 전달하세요:
const result = await agent.invoke(
{
messages: [{ role: "user", content: "What is LangGraph?" }],
skillsMetadata: null,
},
config,
);
실행 사이에 스레드를 재설정하려면 상태를 업데이트하세요:
await agent.updateState(config, { skillsMetadata: null });
빈 목록이 아니라 null을 사용하세요. 빈 목록은 소스가 로드되어 스킬이 없음을 의미하므로 에이전트는 스레드의 나머지 동안 스킬을 보지 못합니다.
참고: 다른 스킬 집합을 찾은 재로드는 시스템 프롬프트를 변경하고 해당 스레드의 프롬프트 캐시를 무효화합니다. 같은 스킬을 찾은 재로드는 같은 프롬프트를 생성하므로 비용이 들지 않습니다.
미들웨어도 값을 재설정할 수 있어 애플리케이션이 스레드가 언제 오래 되었는지 결정하게 합니다. 로드는 각 모델 호출 전에 일어나므로 훅에서의 재설정은 실행 도중을 포함해 다음 모델 호출에 적용됩니다.
import { createMiddleware } from "langchain";
import { StateSchema } from "@langchain/langgraph";
import { skillsMetadataValue } from "deepagents";
const reloadEditedSkills = createMiddleware({
name: "ReloadEditedSkills",
stateSchema: new StateSchema({ skillsMetadata: skillsMetadataValue }),
afterModel: (state) =>
agentEditedSkills(state) ? { skillsMetadata: null } : undefined,
});
서브에이전트용 스킬
서브에이전트를 사용할 때 각 유형이 접근할 수 있는 스킬을 구성할 수 있어요:
- 범용 서브에이전트:
create_deep_agent에skills를 전달하면 메인 에이전트의 스킬을 자동으로 상속합니다. 추가 구성이 필요 없습니다. - 커스텀 서브에이전트: 메인 에이전트의 스킬을 상속하지 않습니다. 각 서브에이전트 정의에 그 서브에이전트의 스킬 소스 경로로
skills매개변수를 추가하세요.
스킬 상태는 완전히 격리됩니다. 메인 에이전트의 스킬은 서브에이전트에 보이지 않고, 서브에이전트의 스킬도 메인 에이전트에 보이지 않습니다.
import { createDeepAgent } from "deepagents";
const researchSubagent = {
name: "researcher",
description: "Research assistant with specialized skills",
systemPrompt: "You are a researcher.",
tools: [webSearch],
skills: ["/skills/research/", "/skills/web-search/"], // Subagent-specific skills
};
const agent = await createDeepAgent({
model: "google_genai:gemini-3.6-flash",
skills: ["/skills/main/"], // Main agent and GP subagent get these
subagents: [researchSubagent], // Researcher gets only its own skills
});
서브에이전트 구성과 스킬 상속에 대한 자세한 내용은 서브에이전트를 참고하세요.
스킬 권한
스킬 가용성은 에이전트가 볼 수 있는 스킬 파일을 제어합니다. 스킬 권한은 에이전트가 해당 파일을 읽을 수 있는지, 쓸 수 있는지, 또는 쓰기 전에 인간 승인을 위해 일시 중지할지 제어합니다. 경로 기반 읽기·쓰기 규칙에는 파일시스템 권한을, 쓰기에 승인이 필요할 때는 interrupt_on 또는 mode="interrupt" 권한 규칙을 사용하세요.
읽기 전용 스킬
에이전트가 선별된 스킬 라이브러리를 수정하지 않고 사용하게 하려면 스킬 경로를 승인된 라이브러리를 담은 백엔드로 라우팅하고 해당 경로 아래의 쓰기 작업을 거부하세요. 에이전트는 스킬을 발견·읽을 수 있고, 백엔드를 업데이트하는 것은 애플리케이션 코드나 관리 워크플로뿐입니다.
다음 예시는 Google / OpenAI / Anthropic / OpenRouter / Fireworks / Baseten / Ollama 등 여러 모델 제공자 탭에 대해 같은 패턴을 보여줍니다 — CompositeBackend로 /skills/를 조직 범위 StoreBackend에 라우팅하고, /skills/** 아래 쓰기를 deny하며, 각 제공자별 model 문자열만 다릅니다:
// 예: Anthropic (다른 제공자 탭은 model 문자열만 다름)
import { InMemoryStore } from "@langchain/langgraph";
import {
createDeepAgent,
CompositeBackend,
StateBackend,
StoreBackend,
} from "deepagents";
const store = new InMemoryStore(); // Good for local dev; omit for LangSmith Deployment
const agent = createDeepAgent({
model: "anthropic:claude-sonnet-5",
backend: new CompositeBackend(new StateBackend(), {
"/skills/": new StoreBackend({
namespace: (rt) => ["curated-skills", rt.context.orgId],
}),
}),
skills: ["/skills/"],
permissions: [
{
operations: ["write"],
paths: ["/skills/**"],
mode: "deny",
},
],
store,
});
다른 제공자 탭의 model 값: Google google-genai:gemini-3.6-flash, OpenAI openai:gpt-5.5, OpenRouter openrouter:z-ai/glm-5.2, Fireworks fireworks:accounts/fireworks/models/glm-5p2, Baseten baseten:zai-org/GLM-5.2, Ollama ollama:north-mini-code-1.0.
이를 엔터프라이즈 지식 베이스, 승인된 도구 지침, 에이전트가 콘텐츠를 사용하되 진실 원천을 다시 쓰지 말아야 하는 중앙 관리 스킬 팩에 사용하세요.
쓰기 가능한 스킬
기본적으로 에이전트는 백엔드가 허용하고 어떤 권한 규칙도 경로를 차단하지 않으면 스킬 파일에 쓸 수 있어요. 에이전트가 일부 스킬을 만들거나 개선하도록 하면서 다른 스킬은 보호하려면:
- 쓰기 가능한 경로를 에이전트 편집을 유지할 수 있는 백엔드로 라우팅.
- 그 경로를
skills에 전달. - 읽기 전용으로 유지할 경로에
deny규칙 추가. 경로가 겹치면 더 구체적인 규칙을 더 넓은 deny 규칙보다 먼저 배치하세요(규칙 순서).
import { InMemoryStore } from "@langchain/langgraph";
import {
createDeepAgent,
CompositeBackend,
StateBackend,
StoreBackend,
} from "deepagents";
const store = new InMemoryStore(); // Good for local dev; omit for LangSmith Deployment
const agent = await createDeepAgent({
model: "anthropic:claude-sonnet-4-6",
backend: new CompositeBackend(new StateBackend(), {
"/skills/approved/": new StoreBackend({
namespace: (rt) => ["approved-skills", rt.context.orgId],
}),
"/skills/editable/": new StoreBackend({
namespace: (ctx) => [
"editable-skills",
ctx.config?.configurable?.user_id ?? "anonymous",
],
}),
}),
skills: ["/skills/approved/", "/skills/editable/"],
permissions: [
{
operations: ["write"],
paths: ["/skills/approved/**"],
mode: "deny",
},
],
store,
});
에이전트는 write_file과 edit_file을 사용해 쓰기 가능한 경로 아래에서 SKILL.md 및 보조 파일을 만들거나 업데이트합니다. 스킬 형식 밖의 일반적인 학습을 포착하려면 /memories/ 같은 별도 경로를 다른 쓰기 가능한 백엔드로 라우팅하세요. 라우팅과 스토어 설정은 백엔드를 참고하세요.
쓰기 승인
에이전트가 스킬 파일에 쓸 수는 있지만 먼저 인간을 루프에 넣으려면 interrupt_on 또는 mode="interrupt" 권한 규칙 중 하나를 사용하세요. 둘 다 write_file 또는 edit_file 실행 전에 일시 중지하고 같은 재개 흐름을 사용합니다.
import { MemorySaver } from "@langchain/langgraph";
import { createDeepAgent } from "deepagents";
const agent = await createDeepAgent({
model: "anthropic:claude-sonnet-4-6",
skills: ["/skills/editable/"],
permissions: [
{
operations: ["write"],
paths: ["/skills/**"],
mode: "interrupt",
},
],
checkpointer: new MemorySaver(), // Required to pause and resume
});
또는 스킬 경로뿐만 아니라 모든 파일시스템 쓰기에 승인을 요구하려면 interrupt_on={"write_file": True, "edit_file": True}를 구성하세요. 인터럽트 처리·재개는 Human-in-the-loop을 참고하세요.
스킬로 코드 실행하기
코드 실행이 없으면 스킬은 수동적입니다. 에이전트가 지침을 읽고 가용한 도구를 사용해 따릅니다. 코드 실행은 스킬을 능동적 역량으로 바꿉니다. 스킬은 API를 호출하거나, 데이터를 변환하거나, 출력을 검증하거나, 파이프라인을 실행하는 테스트된 스크립트를 실을 수 있고, 에이전트는 매번 지침에서 로직을 재생성하는 대신 결정적으로 실행합니다. 이는 정확한 동작이 필요한 워크플로(데이터 변환, API 통합, 규정 준수 검사)나 에이전트가 도구 호출만으로는 사용할 수 없는 라이브러리에 의존하는 워크플로에서 특히 가치가 있습니다.
스킬은 샌드박스 스크립트를 통해 코드를 실행합니다. 에이전트는 의존성을 설치하거나, 테스트를 실행하거나, CLI를 호출하거나, 운영체제 파일시스템으로 작업할 필요가 있을 때 번들된 스크립트를 실행합니다.
샌드박스 스크립트
스킬은 SKILL.md 파일과 함께 스크립트를 포함할 수 있어요. 스크립트의 존재와 실행 시기를 에이전트가 알도록 SKILL.md에서 스크립트를 참조하세요:
skills/
└── arxiv-search/
├── SKILL.md
└── scripts/search.ts
---
name: arxiv-search
description: Search the arXiv preprint repository for research papers. Use when the user asks about academic papers, recent research, or scientific literature.
---
# arxiv-search
Search arXiv for papers matching the user's query.
## Instructions
1. Run `scripts/search.ts` with the user's query as an argument.
2. Parse the results and present them with title, authors, abstract summary, and link.
3. If the user asks for more detail on a specific paper, fetch the full abstract.
에이전트는 어떤 백엔드에서든 스크립트를 읽을 수 있지만, 실행하려면 셸에 접근해야 하며, 이는 샌드박스 백엔드만 제공합니다.
샌드박스 백엔드는 격리된 컨테이너에서 실행됩니다. 샌드박스 밖에 저장된 스킬 파일은 그 안에서 사용할 수 없으므로, 에이전트는 먼저 전송되지 않으면 스킬 스크립트를 실행하거나 스킬 리소스에 접근할 수 없습니다. 이 전송을 처리하려면 커스텀 미들웨어를 사용하세요:
before_agent: 백엔드에서 스킬 파일을 읽어 샌드박스에 업로드해 에이전트가 처음부터 스크립트를 실행할 수 있게 합니다.after_agent: 업데이트되거나 새로 만들어진 스킬 파일을 샌드박스에서 다운로드해 백엔드에 다시 써서 변경이 실행 간 유지되게 합니다.
다음은 여러 제공자 탭(Google / OpenAI / Anthropic / OpenRouter / Fireworks / Baseten / Ollama)에 대해 같은 패턴을 보여줍니다. 공유 스토어 네임스페이스에서 디스크의 스킬 파일을 시드한 뒤, SkillSandboxSyncMiddleware가 각 에이전트 실행 전에 그 파일을 샌드박스로 복사합니다. 제공자별 model 문자열만 다릅니다:
// 예: Google 제공자 (다른 탭은 model 문자열만 다름)
import { readFile, readdir } from "node:fs/promises";
import { join, posix, relative, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { createMiddleware } from "langchain";
import {
CompositeBackend,
createDeepAgent,
type FileData,
LangSmithSandbox,
StoreBackend,
} from "deepagents";
import { InMemoryStore } from "@langchain/langgraph";
import { SandboxClient } from "langsmith/sandbox";
/** Identical skill bundles for every user: one shared store namespace. */
const SKILLS_SHARED_NAMESPACE = ["skills", "builtin"] as const;
function createFileData(content: string): FileData {
const now = new Date().toISOString();
return {
content: content.split("\n"),
created_at: now,
modified_at: now,
};
}
function normalizeSkillsStoreKey(key: string): string {
const k = String(key);
if (k.includes("..") || /[*?]/.test(k)) {
throw new Error(`Invalid key: ${key}`);
}
return k.startsWith("/") ? k : `/${k}`;
}
async function walkFiles(dir: string): Promise<string[]> {
const entries = await readdir(dir, { withFileTypes: true });
const files: string[] = [];
for (const entry of entries) {
const fullPath = join(dir, entry.name);
if (entry.isDirectory()) {
files.push(...(await walkFiles(fullPath)));
} else if (entry.isFile()) {
files.push(fullPath);
}
}
return files.sort((a, b) => a.localeCompare(b));
}
/** Load canonical skill files from disk into the shared store namespace (run once at deploy). */
async function seedSkillStore(store: InMemoryStore) {
const moduleDir = resolve(fileURLToPath(new URL(".", import.meta.url)));
const skillsDir = resolve(moduleDir, "skills");
const filePaths = await walkFiles(skillsDir);
for (const filePath of filePaths) {
const rel = relative(skillsDir, filePath);
const key = `/${posix.normalize(rel.split("\\").join("/"))}`;
const content = await readFile(filePath, "utf8");
await store.put([...SKILLS_SHARED_NAMESPACE], key, createFileData(content));
}
}
/** Copy shared skill files from the store into the sandbox before each agent run. */
function createSkillSandboxSyncMiddleware(backend: CompositeBackend) {
return createMiddleware({
name: "SkillSandboxSyncMiddleware",
beforeAgent: async (state, runtime) => {
const store = (runtime as any).store;
if (!store) {
throw new Error(
"Store is required for syncing skills into the sandbox. " +
"Pass `store` to createDeepAgent and ensure your runtime provides it.",
);
}
const encoder = new TextEncoder();
const files: Array<[string, Uint8Array]> = [];
for (const item of await store.search([...SKILLS_SHARED_NAMESPACE])) {
const normalized = normalizeSkillsStoreKey(String(item.key));
const data = item.value as FileData;
files.push([
`/skills${normalized}`,
encoder.encode(data.content.join("\n")),
]);
}
if (files.length > 0) await backend.uploadFiles(files);
return state;
},
});
}
async function main() {
const store = new InMemoryStore();
await seedSkillStore(store);
const client = new SandboxClient();
const lsSandbox = await client.createSandbox();
const backend = new CompositeBackend(
new LangSmithSandbox({ sandbox: lsSandbox }),
{
"/skills/": new StoreBackend({
store,
namespace: () => [...SKILLS_SHARED_NAMESPACE],
} as any),
},
);
try {
const agent = await createDeepAgent({
model: "google-genai:gemini-3.6-flash",
backend,
skills: ["/skills/"],
store,
middleware: [createSkillSandboxSyncMiddleware(backend)],
});
} finally {
await client.deleteSandbox(lsSandbox.name);
}
}
main().catch((err) => {
console.error(err);
process.exitCode = 1;
});
다른 제공자 탭의 model 값: OpenAI openai:gpt-5.5, Anthropic anthropic:claude-sonnet-5, OpenRouter openrouter:z-ai/glm-5.2, Fireworks fireworks:accounts/fireworks/models/glm-5p2, Baseten baseten:zai-org/GLM-5.2, Ollama ollama:north-mini-code-1.0.
실행 전에 스킬과 메모리를 모두 시드하고 실행 후 다시 동기화하는 완전한 예시는 캐스텀 미들웨어로 스킬·메모리 동기화를 참고하세요.
문제 해결
LangSmith 트레이스를 사용해 스킬 발견, SKILL.md에 대한 read_file 호출, 보조 리소스 접근을 디버그하세요. 트레이싱 퀵스타트를 따라 설정하세요. 트레이스를 모니터링하고 문제를 감지·수정을 제안하는 LangSmith Engine도 설정하는 것을 권장합니다.
스킬이 활성화되지 않음
문제: 에이전트가 스킬의 SKILL.md를 읽지 않고 작업을 처리합니다.
해결책:
-
설명을 더 구체적으로. 에이전트는 발견 시
description필드만으로 스킬을 선택합니다. 스킬이 무엇을 하는지, 언제 사용하는지, 에이전트가 매칭할 키워드를 포함하세요:# Good description: >- Search the arXiv preprint repository for research papers. Use when the user asks about academic papers, recent research, or scientific literature. # Poor description: Helps with research. -
스킬 간 겹침 줄이기. 여러 스킬의 설명이 비슷하면 에이전트가 올바른 것을 건너뛰거나 잘못된 것을 고를 수 있어요. 설명을 구분하거나 관련 스킬을 통합하세요.
-
스킬이
skills배열에 있는지 확인. 스킬은 에이전트 생성 시 전달한 경로나 서브에이전트별skills매개변수에서만 로드됩니다.
시작 시 스킬 누락
문제: 에이전트가 시스템 프롬프트에 스킬을 나열하지 않거나, SKILL.md에 대한 read_file이 실패합니다.
해결책:
- 스킬 경로 확인. 경로는 슬래시를 사용해야 하고 백엔드 루트 기준이어야 합니다.
FilesystemBackend에서는root_dir기준입니다.StateBackend에서는create_file_data()를 사용해invoke(files={...})로 스킬 파일을 전달하세요. SKILL.mdfrontmatter 검증.name은 부모 디렉토리 이름과 일치하고 Agent Skills 명세를 따라야 합니다.skills-ref검증 도구로 형식을 확인하세요.- 파일 크기 확인. Deep Agents는 발견 시 10MB를 초과하는
SKILL.md파일을 건너뜁니다. - 레이어된 소스 확인. 같은 스킬 이름이 여러 소스에 있으면 마지막 소스가 우선합니다. 나중 경로의 오래되거나 빈 스킬이 기대한 것을 덮어쓸 수 있어요.
스킬 변경이 반영되지 않음
문제: 스킬을 추가·편집·삭제한 후에도 에이전트가 계속 이전 버전을 사용합니다.
해결책: 스킬은 스레드당 한 번 로드되므로 이미 실행된 스레드는 변경을 보지 못합니다. 저장된 메타데이터를 재설정하세요. 스킬 다시 로드 참고.
보조 파일을 찾지 못함
문제: 에이전트가 SKILL.md는 읽지만 스크립트, 참조, 자산에 접근할 수 없습니다.
해결책:
SKILL.md에서 파일 참조. 에이전트는 보조 파일을 자동 발견하지 않습니다. 각 파일의 내용과 사용 시기를 명시하세요. 스킬 루트 기준 상대 경로를 사용하세요.- 경로를 스킬 디렉토리 안에 유지. 파일 경로는 백엔드 기준으로 해석됩니다. 지침이 참조하는 경로에 보조 파일이 존재하는지 확인하세요.
- 스킬을 샌드박스로 동기화. 샌드박스 백엔드를 사용하면 컨테이너 밖의 스킬 파일은 복사하기 전까지 사용할 수 없습니다. 샌드박스 스크립트와 캐스텀 미들웨어로 스킬·메모리 동기화 참고.
스크립트 실행 실패
문제: 에이전트가 스크립트를 읽지만 실행할 수 없습니다.
해결책: 에이전트는 어떤 백엔드에서든 스크립트를 읽을 수 있지만, 실행하려면 샌드박스 백엔드가 필요합니다. 스킬로 코드 실행 참고.
서브에이전트가 스킬에 접근하지 못함
문제: 커스텀 서브에이전트가 메인 에이전트가 사용하는 스킬을 보지 못합니다.
해결책: 커스텀 서브에이전트는 메인 에이전트의 스킬을 상속하지 않습니다. 각 서브에이전트 정의에 그 서브에이전트의 스킬 소스 경로로 skills 매개변수를 추가하세요. 범용 서브에이전트는 create_deep_agent에서 스킬을 자동 상속합니다.
참조
스킬, 메모리, 도구
스킬, 메모리(AGENTS.md 파일), 도구는 모두 에이전트에 컨텍스트나 역량을 제공합니다. 다음 표는 각각을 언제 사용할지 요약합니다:
| 스킬 | 메모리 | 도구 | |
|---|---|---|---|
| 목적 | 점진적 공개로 발견되는 온디맨드 역량 | 시작 시 로드되는 지속 컨텍스트 | 에이전트가 호출할 수 있는 프로그래매틱 작업 |
| 로딩 | 에이전트가 관련성을 판단할 때만 읽음 | 에이전트 시작 시 로드 | 매 턴 사용 가능 |
| 형식 | 명명된 디렉토리의 SKILL.md |
AGENTS.md 파일 |
에이전트에 바인딩된 함수 |
| 계층 | 사용자, 그다음 프로젝트(마지막이 우선) | 사용자, 그다음 프로젝트(결합) | 에이전트 생성 시 정의 |
| 사용 시기 | 지침이 작업별이고 잠재적으로 클 때 | 컨텍스트가 항상 관련 있을 때(프로젝트 규칙·선호) | 에이전트가 프로그래매틱 작업이 필요하거나 파일시스템 접근이 없을 때 |
이는 경직된 경계가 아니라 지침입니다. 실제로 스킬과 메모리는 스펙트럼 위에 있습니다. 에이전트는 작업하면서 자신의 스킬을 업데이트해 새 절차를 포착하고 시간에 따라 지침을 다듬을 수 있어요. 이런 식으로 스킬은 점진적 공개 메모리의 한 형태로 기능할 수 있습니다. 매 프롬프트에서 로드하는 대신 온디맨드로 검색하는 에이전트가 쌓아 올린 컨텍스트입니다.
Frontmatter 필드
Agent Skills 명세는 다음 frontmatter 필드를 정의합니다:
| 필드 | 필수 | 설명 |
|---|---|---|
name |
예 | 하이픈이 있는 소문자 영숫자, 1-64자. 부모 디렉토리 이름과 일치해야 함. |
description |
예 | 스킬이 무엇을 하고 언제 사용하는지. 최대 1,024자. |
license |
아니오 | 라이선스 이름 또는 번들된 라이선스 파일 참조. |
compatibility |
아니오 | 환경 요구사항(시스템 패키지, 네트워크 접근). 최대 500자. |
metadata |
아니오 | 추가 속성용 임의 키-값 쌍. |
allowed-tools |
아니오 | 스킬이 사용할 수 있는 사전 승인된 도구의 공백 구분 목록. 실험적. |
---
name: langgraph-docs
description: Use this skill for requests related to LangGraph in order to fetch relevant documentation to provide accurate, up-to-date guidance.
license: MIT
compatibility: Requires internet access for fetching documentation URLs
metadata:
author: langchain
version: "1.0"
allowed-tools: fetch_url
---
# langgraph-docs
Instructions for the agent go here. See [Usage](#usage) for a complete example of skill instructions.
경고: 자세한 제약과 검증 규칙은 전체 Agent Skills 명세를 참조하세요. Deep Agents에서
SKILL.md파일은 10MB 미만이어야 합니다. 이 한도를 초과하는 파일은 스킬 로딩 중 건너뜁니다.
더 많은 예시 스킬은 Deep Agents 예시 스킬을 참고하세요.
더 알아보기 (Learn more)
- 서브에이전트 — 서브에이전트 구성과 스킬 상속
- 백엔드 — 백엔드 라우팅과 스토어 설정
- 샌드박스 — 샌드박스 백엔드와 스크립트 실행
- 권한 — 경로 기반 읽기·쓰기 규칙
- Human-in-the-loop — 쓰기 승인용 인터럽트
- 프로덕션으로 이동 — 캐스텀 미들웨어로 스킬·메모리 동기화
- Agent Skills 명세 — 스킬 구조 및 검증 규칙