Claude API에서 에이전트 스킬 사용하기
Claude API에서 에이전트 스킬 사용하기 (Using Agent Skills with the API)
스킬(Agent Skills)은 정리된 폴더의 지시·스크립트·리소스를 통해 Claude의 능력을 확장해요. 이 문서는 Claude API에서 미리 만들어진 스킬과 커스텀 스킬을 모두 사용하는 방법을 소개해 드릴게요. 스킬은 코드 실행 컨테이너 안에서 동작해 문서(엑셀, 파워포인트, PDF, 워드)를 만들고 데이터를 분석하는 데 유용하답니다.
출처: 문서
본문
에이전트 스킬은 정리된 폴더의 지시·스크립트·리소스를 통해 Claude의 능력을 확장해요. 이 문서는 Claude API에서 미리 만들어진 스킬과 커스텀 스킬을 모두 사용하는 방법을 보여줘요.
- 스킬 관리 API 레퍼런스 - 스킬 CRUD 작업
- 스킬 버전 API 레퍼런스 - 버전 관리
빠른 링크 (Quick links)
개요 (Overview)
스킬은 코드 실행 도구를 통해 Messages API와 통합돼요. Anthropic이 관리하는 미리 만들어진 스킬을 쓰든, 업로드한 커스텀 스킬을 쓰든, 통합 형태는 동일해요. 둘 다 코드 실행이 필요하고 같은 container 구조를 사용하죠.
스킬 사용하기 (Using Skills)
스킬은 소스와 무관하게 Messages API에서 동일하게 통합돼요. container 파라미터에서 skill_id, type, 선택적인 version으로 스킬을 지정하고, 스킬은 코드 실행 환경에서 실행돼요.
두 가지 소스의 스킬을 사용할 수 있어요:
| 측면 | Anthropic 스킬 | 커스텀 스킬 |
|---|---|---|
| Type 값 | anthropic |
custom |
| 스킬 ID | 짧은 이름: pptx, xlsx, docx, pdf |
생성된 값: skill_01AbCdEfGhIjKlMnOpQrStUv |
| 버전 형식 | 날짜 기반: 20251013 또는 latest |
버전 ID: skver_01AbCdEfGhIjKlMnOpQrStUv 또는 latest |
| 관리 | Anthropic이 미리 만들고 유지 | 스킬 API를 통해 업로드·관리 |
| 가용성 | 모든 사용자 사용 가능 | 워크스페이스에 비공개 |
두 스킬 소스 모두 스킬 목록 엔드포인트가 반환해요(source 파라미터로 필터링). 통합 형태와 실행 환경은 동일해요. 유일한 차이는 스킬이 어디서 오는지, 어떻게 관리되는지예요.
사전 요구사항 (Prerequisites)
스킬을 사용하려면 다음이 필요해요:
스킬은 코드 실행 도구가 필요하므로, 그 모델 호환성 목록의 모델을 사용하세요.
Messages에서 스킬 사용하기 (Using Skills in Messages)
Container 파라미터 (Container parameter)
스킬은 Messages API의 container 파라미터로 지정돼요. 요청당 최대 20개의 스킬을 포함할 수 있어요.
구조는 Anthropic과 커스텀 스킬 모두 동일해요. 필수 type과 skill_id를 지정하고, 특정 버전에 고정하려면 선택적으로 version을 포함하세요:
ant messages create <<'YAML'
model: claude-opus-5-5
max_tokens: 4096
container:
skills:
- type: anthropic
skill_id: pptx
version: latest
messages:
- role: user
content: Create a presentation about renewable energy
tools:
- type: code_execution_20250825
name: code_execution
YAML
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-5-5",
max_tokens=4096,
container={
"skills": [{"type": "anthropic", "skill_id": "pptx", "version": "latest"}]
},
messages=[
{"role": "user", "content": "Create a presentation about renewable energy"}
],
tools=[{"type": "code_execution_20250825", "name": "code_execution"}],
)
const client = new Anthropic();
const response = await client.messages.create({
model: "claude-opus-5-5",
max_tokens: 4096,
container: {
skills: [
{
type: "anthropic",
skill_id: "pptx",
version: "latest"
}
]
},
messages: [
{
role: "user",
content: "Create a presentation about renewable energy"
}
],
tools: [
{
type: "code_execution_20250825",
name: "code_execution"
}
]
});
AnthropicClient client = new();
var parameters = new MessageCreateParams
{
Model = "claude-opus-5-5",
MaxTokens = 4096,
Container = new ContainerParams
{
Skills =
[
new SkillParams
{
Type = SkillParamsType.Anthropic,
SkillID = "pptx",
Version = "latest",
},
],
},
Messages = [new() { Role = Role.User, Content = "Create a presentation about renewable energy" }],
Tools = [new CodeExecutionTool20250825()],
};
var message = await client.Messages.Create(parameters);
Console.WriteLine(message);
client := anthropic.NewClient()
response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
Model: "claude-opus-5-5",
MaxTokens: 4096,
Container: anthropic.MessageCreateParamsContainerUnion{
OfContainers: &anthropic.ContainerParams{
Skills: []anthropic.SkillParams{
{
Type: anthropic.SkillParamsTypeAnthropic,
SkillID: "pptx",
Version: anthropic.String("latest"),
},
},
},
},
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("Create a presentation about renewable energy")),
},
Tools: []anthropic.ToolUnionParam{
{OfCodeExecutionTool20250825: &anthropic.CodeExecutionTool20250825Param{}},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(response)
import com.anthropic.models.messages.ContainerParams;
import com.anthropic.models.messages.SkillParams;
import com.anthropic.models.messages.CodeExecutionTool20250825;
// ...
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
MessageCreateParams params = MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_5_5)
.maxTokens(4096L)
.container(ContainerParams.builder()
.addSkill(SkillParams.builder()
.type(SkillParams.Type.ANTHROPIC)
.skillId("pptx")
.version("latest")
.build())
.build())
.addUserMessage("Create a presentation about renewable energy")
.addTool(CodeExecutionTool20250825.builder().build())
.build();
Message response = client.messages().create(params);
System.out.println(response);
}
$client = new Client();
$message = $client->messages->create(
maxTokens: 4096,
messages: [
['role' => 'user', 'content' => 'Create a presentation about renewable energy']
],
model: 'claude-opus-5-5',
container: [
'skills' => [
[
'type' => 'anthropic',
'skillID' => 'pptx',
'version' => 'latest'
]
]
],
tools: [
['type' => 'code_execution_20250825', 'name' => 'code_execution']
]
);
echo $message;
client = Anthropic::Client.new
message = client.messages.create(
model: "claude-opus-5-5",
max_tokens: 4096,
container: {
skills: [
{
type: "anthropic",
skill_id: "pptx",
version: "latest"
}
]
},
messages: [
{ role: "user", content: "Create a presentation about renewable energy" }
],
tools: [
{ type: "code_execution_20250825", name: "code_execution" }
]
)
puts message
생성된 파일 다운로드하기 (Downloading generated files)
스킬이 문서(엑셀, 파워포인트, PDF, 워드)를 만들면 응답에 file_id 속성을 반환해요. 이 파일들을 다운로드하려면 Files API를 사용해야 해요.
동작 방식:
- 스킬이 코드 실행 중에 파일을 만들어요.
- 응답이 각 생성된 파일의
file_id를 코드 실행 도구 결과 블록 안에 포함해요(응답 형식 참조). - Files API로 실제 파일 콘텐츠를 다운로드해요.
- 로컬에 저장하거나 필요에 따라 처리해요.
스킬이 작업할 입력 파일을 제공하려면 Files API로 업로드하고 컨테이너 업로드 블록으로 요청에서 참조하세요.
예시: Excel 파일 만들고 다운로드하기
Step 2: Extract file_id from response (using jq)
FILE_ID=$(echo "$RESPONSE" | jq -r '.content[] | select(.type=="bash_code_execution_tool_result") | .content | select(.type=="bash_code_execution_result") | .content[] | select(.file_id) | .file_id')
Step 3: Get filename from metadata
FILENAME=$(curl "https://api.anthropic.com/v1/files/$FILE_ID"
-H "x-api-key: $ANTHR...KEY"
-H "anthropic-version: 2023-06-01" | jq -r '.filename')
Step 4: Download the file using Files API
curl "https://api.anthropic.com/v1/files/$FILE_ID/content"
-H "x-api-key: $ANTHR...KEY"
-H "anthropic-version: 2023-06-01"
--output "$FILENAME"
echo "Downloaded: $FILENAME"
```bash CLI
# Step 1: Use the xlsx Skill to create a file
# Step 2: Extract file_id from the response with --transform (GJSON path)
FILE_ID=$(ant messages create \
--transform 'content.#.content.content.#.file_id|@flatten|0' \
--raw-output <<'YAML'
model: claude-opus-5-5
max_tokens: 4096
container:
skills:
- type: anthropic
skill_id: xlsx
version: latest
messages:
- role: user
content: Create an Excel file with a simple budget spreadsheet
tools:
- type: code_execution_20250825
name: code_execution
YAML
)
# Step 3: Get the filename from file metadata
FILENAME=$(ant files retrieve-metadata \
--file-id "$FILE_ID" \
--transform filename \
--raw-output)
# Step 4: Download the file using Files API
ant files download --file-id "$FILE_ID" --output "$FILENAME" > /dev/null
printf 'Downloaded: %s\n' "$FILENAME"
client = anthropic.Anthropic()
# Step 1: Use a Skill to create a file
response = client.messages.create(
model="claude-opus-5-5",
max_tokens=4096,
container={
"skills": [{"type": "anthropic", "skill_id": "xlsx", "version": "latest"}]
},
messages=[
{
"role": "user",
"content": "Create an Excel file with a simple budget spreadsheet",
}
],
tools=[{"type": "code_execution_20250825", "name": "code_execution"}],
)
# Step 2: Extract file IDs from the response
def extract_file_ids(response):
file_ids = []
for item in response.content:
if item.type == "bash_code_execution_tool_result":
content_item = item.content
if content_item.type == "bash_code_execution_result":
# each content item is a bash_code_execution_output block carrying a file_id
for file in content_item.content:
file_ids.append(file.file_id)
return file_ids
# Step 3: Download the file using Files API
for file_id in extract_file_ids(response):
file_metadata = client.files.retrieve_metadata(file_id=file_id)
file_content = client.files.download(file_id=file_id)
# Step 4: Save to disk
file_content.write_to_file(file_metadata.filename)
print(f"Downloaded: {file_metadata.filename}")
import { writeFile } from "node:fs/promises";
const client = new Anthropic();
// Step 1: Use a Skill to create a file
const response = await client.messages.create({
model: "claude-opus-5-5",
max_tokens: 4096,
container: {
skills: [{ type: "anthropic", skill_id: "xlsx", version: "latest" }]
},
messages: [
{
role: "user",
content: "Create an Excel file with a simple budget spreadsheet"
}
],
tools: [{ type: "code_execution_20250825", name: "code_execution" }]
});
// Step 2: Extract file IDs from the response
const fileIds: string[] = [];
for (const block of response.content) {
if (
block.type === "bash_code_execution_tool_result" &&
block.content.type === "bash_code_execution_result"
) {
for (const outputBlock of block.content.content) {
fileIds.push(outputBlock.file_id);
}
}
}
// Step 3: Download each file and save to disk
for (const fileId of fileIds) {
const fileMetadata = await client.files.retrieveMetadata(fileId);
const fileResponse = await client.files.download(fileId);
await writeFile(fileMetadata.filename, Buffer.from(await fileResponse.arrayBuffer()));
console.log(`Downloaded: ${fileMetadata.filename}`);
}
AnthropicClient client = new();
// Step 1: Use a Skill to create a file
var parameters = new MessageCreateParams
{
Model = "claude-opus-5-5",
MaxTokens = 4096,
Container = new ContainerParams
{
Skills =
[
new SkillParams
{
Type = SkillParamsType.Anthropic,
SkillID = "xlsx",
Version = "latest",
},
],
},
Messages = [new() { Role = Role.User, Content = "Create an Excel file with a simple budget spreadsheet" }],
Tools = [new CodeExecutionTool20250825()],
};
var response = await client.Messages.Create(parameters);
// Step 2: Extract file IDs from the response
List<string> fileIds = [];
foreach (var block in response.Content)
{
if (block.TryPickBashCodeExecutionToolResult(out var toolResult)
&& toolResult.Content.TryPickBashCodeExecutionResultBlock(out var result))
{
foreach (var output in result.Content)
{
fileIds.Add(output.FileID);
}
}
}
// Step 3: Download each file and save to disk
foreach (var fileId in fileIds)
{
var fileMetadata = await client.Files.RetrieveMetadata(fileId);
using var download = await client.Files.Download(fileId);
using var downloadStream = await download.ReadAsStream();
using var outputFile = File.Create(fileMetadata.Filename);
await downloadStream.CopyToAsync(outputFile);
Console.WriteLine($"Downloaded: {fileMetadata.Filename}");
}
func main() {
client := anthropic.NewClient()
// Step 1: Use a Skill to create a file
response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
Model: "claude-opus-5-5",
MaxTokens: 4096,
Container: anthropic.MessageCreateParamsContainerUnion{
OfContainers: &anthropic.ContainerParams{
Skills: []anthropic.SkillParams{
{
Type: anthropic.SkillParamsTypeAnthropic,
SkillID: "xlsx",
Version: anthropic.String("latest"),
},
},
},
},
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("Create an Excel file with a simple budget spreadsheet")),
},
Tools: []anthropic.ToolUnionParam{
{OfCodeExecutionTool20250825: &anthropic.CodeExecutionTool20250825Param{}},
},
})
if err != nil {
log.Fatal(err)
}
// Step 2: Extract file IDs from the response
fileIDs := extractFileIDs(response)
// Step 3: Download the file using Files API
for _, fileID := range fileIDs {
fileMetadata, err := client.Files.GetMetadata(context.TODO(), fileID, anthropic.FileGetMetadataParams{})
if err != nil {
log.Fatal(err)
}
fileContent, err := client.Files.Download(context.TODO(), fileID, anthropic.FileDownloadParams{})
if err != nil {
log.Fatal(err)
}
// Step 4: Save to disk
out, err := os.Create(fileMetadata.Filename)
if err != nil {
log.Fatal(err)
}
if _, err := io.Copy(out, fileContent.Body); err != nil {
log.Fatal(err)
}
out.Close()
fileContent.Body.Close()
fmt.Printf("Downloaded: %s\n", fileMetadata.Filename)
}
}
func extractFileIDs(response *anthropic.Message) []string {
var fileIDs []string
for _, item := range response.Content {
switch v := item.AsAny().(type) {
case anthropic.BashCodeExecutionToolResultBlock:
if v.Content.Type == "bash_code_execution_result" {
for _, output := range v.Content.Content {
fileIDs = append(fileIDs, output.FileID)
}
}
}
}
return fileIDs
}
import com.anthropic.models.messages.ContainerParams;
import com.anthropic.models.messages.SkillParams;
import com.anthropic.models.messages.CodeExecutionTool20250825;
import com.anthropic.models.messages.ContentBlock;
import com.anthropic.models.files.FileMetadata;
import com.anthropic.core.http.HttpResponse;
// ...
void main() throws Exception {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
// Step 1: Use a Skill to create a file
MessageCreateParams params = MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_5_5)
.maxTokens(4096L)
.container(ContainerParams.builder()
.addSkill(SkillParams.builder()
.type(SkillParams.Type.ANTHROPIC)
.skillId("xlsx")
.version("latest")
.build())
.build())
.addUserMessage("Create an Excel file with a simple budget spreadsheet")
.addTool(CodeExecutionTool20250825.builder().build())
.build();
Message response = client.messages().create(params);
// Step 2: Extract file IDs from the response
List<String> fileIds = new ArrayList<>();
for (ContentBlock block : response.content()) {
if (block.isBashCodeExecutionToolResult()) {
var content = block.asBashCodeExecutionToolResult().content();
if (content.isBashCodeExecutionResultBlock()) {
for (var outputBlock : content.asBashCodeExecutionResultBlock().content()) {
fileIds.add(outputBlock.fileId());
}
}
}
}
// Step 3: Download the file using Files API
for (String fileId : fileIds) {
FileMetadata fileMetadata = client.files().retrieveMetadata(fileId);
HttpResponse fileContent = client.files().download(fileId);
// Step 4: Save to disk
try (InputStream is = fileContent.body();
FileOutputStream fos = new FileOutputStream(fileMetadata.filename())) {
is.transferTo(fos);
}
System.out.println("Downloaded: " + fileMetadata.filename());
}
}
$client = new Client();
// Step 1: Use a Skill to create a file
$response = $client->messages->create(
maxTokens: 4096,
messages: [
['role' => 'user', 'content' => 'Create an Excel file with a simple budget spreadsheet']
],
model: 'claude-opus-5-5',
container: [
'skills' => [
['type' => 'anthropic', 'skillID' => 'xlsx', 'version' => 'latest']
]
],
tools: [
['type' => 'code_execution_20250825', 'name' => 'code_execution']
]
);
// Step 2: Extract file IDs from the response
function extractFileIds($response) {
$fileIds = [];
foreach ($response->content as $item) {
if ($item->type === 'bash_code_execution_tool_result') {
$contentItem = $item->content;
if ($contentItem->type === 'bash_code_execution_result') {
foreach ($contentItem->content as $file) {
$fileIds[] = $file->fileID;
}
}
}
}
return $fileIds;
}
// Step 3: Download the file using Files API
foreach (extractFileIds($response) as $fileId) {
$fileMetadata = $client->files->retrieveMetadata($fileId);
$fileContent = $client->files->download($fileId);
// Step 4: Save to disk
file_put_contents($fileMetadata->filename, $fileContent);
echo "Downloaded: {$fileMetadata->filename}\n";
}
client = Anthropic::Client.new
# Step 1: Use a Skill to create a file
response = client.messages.create(
model: "claude-opus-5-5",
max_tokens: 4096,
container: {
skills: [{ type: "anthropic", skill_id: "xlsx", version: "latest" }]
},
messages: [
{
role: "user",
content: "Create an Excel file with a simple budget spreadsheet"
}
],
tools: [{ type: "code_execution_20250825", name: "code_execution" }]
)
# Step 2: Extract file IDs from the response
def extract_file_ids(response)
file_ids = []
response.content.each do |item|
if item.type == :bash_code_execution_tool_result
content_item = item.content
if content_item.type == :bash_code_execution_result
content_item.content.each do |file|
file_ids << file.file_id
end
end
end
end
file_ids
end
# Step 3: Download the file using Files API
extract_file_ids(response).each do |file_id|
file_metadata = client.files.retrieve_metadata(file_id)
file_content = client.files.download(file_id)
# Step 4: Save to disk
File.binwrite(file_metadata.filename, file_content.read)
puts "Downloaded: #{file_metadata.filename}"
end
추가 Files API 작업:
List all files
curl "https://api.anthropic.com/v1/files"
-H "x-api-key: $ANTHR...KEY"
-H "anthropic-version: 2023-06-01"
Delete a file
curl -X DELETE "https://api.anthropic.com/v1/files/$FILE_ID"
-H "x-api-key: $ANTHR...KEY"
-H "anthropic-version: 2023-06-01"
```bash CLI
# Get file metadata
ant files retrieve-metadata \
--file-id "$FILE_ID" \
--transform '{filename,size_bytes}' \
--format yaml
# List all files
ant files list --transform '{filename,created_at}' --format yaml
# Delete a file
ant files delete --file-id "$FILE_ID" >/dev/null
client = anthropic.Anthropic()
file_id = "file_011CNha8iCJcU1wXNR6q4V8w"
# Get file metadata
file_info = client.files.retrieve_metadata(file_id=file_id)
print(f"Filename: {file_info.filename}, Size: {file_info.size_bytes} bytes")
# List all files
for file in client.files.list():
print(f"{file.filename} - {file.created_at}")
# Delete a file
client.files.delete(file_id=file_id)
const client = new Anthropic();
const fileId = "file_011CNha8iCJcU1wXNR6q4V8w";
// Get file metadata
const fileInfo = await client.files.retrieveMetadata(fileId);
console.log(`Filename: ${fileInfo.filename}, Size: ${fileInfo.size_bytes} bytes`);
// List all files
for await (const file of client.files.list()) {
console.log(`${file.filename} - ${file.created_at}`);
}
// Delete a file
await client.files.delete(fileId);
AnthropicClient client = new();
var fileId = "file_011CNha8iCJcU1wXNR6q4V8w";
// Get file metadata
var fileInfo = await client.Files.RetrieveMetadata(fileId);
Console.WriteLine($"Filename: {fileInfo.Filename}, Size: {fileInfo.SizeBytes} bytes");
// List files
await foreach (var file in (await client.Files.List()).Paginate())
{
Console.WriteLine($"{file.Filename} - {file.CreatedAt}");
}
// Delete the file
await client.Files.Delete(fileId);
client := anthropic.NewClient()
fileID := "file_011CNha8iCJcU1wXNR6q4V8w"
// Get file metadata
fileInfo, err := client.Files.GetMetadata(context.TODO(), fileID, anthropic.FileGetMetadataParams{})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Filename: %s, Size: %d bytes\n", fileInfo.Filename, fileInfo.SizeBytes)
// List all files
files := client.Files.ListAutoPaging(context.TODO(), anthropic.FileListParams{})
for files.Next() {
file := files.Current()
fmt.Printf("%s - %s\n", file.Filename, file.CreatedAt)
}
if files.Err() != nil {
log.Fatal(files.Err())
}
// Delete a file
_, err = client.Files.Delete(context.TODO(), fileID, anthropic.FileDeleteParams{})
if err != nil {
log.Fatal(err)
}
import com.anthropic.models.files.FileMetadata;
import com.anthropic.models.files.FileListPage;
// ...
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
String fileId = "file_011CNha8iCJcU1wXNR6q4V8w";
// Get file metadata
FileMetadata fileInfo = client.files().retrieveMetadata(fileId);
System.out.println("Filename: " + fileInfo.filename() + ", Size: " + fileInfo.sizeBytes() + " bytes");
// List files (first page)
FileListPage files = client.files().list();
for (var file : files.data()) {
System.out.println(file.filename() + " - " + file.createdAt());
}
// Delete a file
client.files().delete(fileId);
}
$client = new Client();
$fileId = 'file_011CNha8iCJcU1wXNR6q4V8w';
// Get file metadata
$fileInfo = $client->files->retrieveMetadata($fileId);
echo "Filename: {$fileInfo->filename}, Size: {$fileInfo->sizeBytes} bytes\n";
// List files (first page)
foreach ($client->files->list()->getItems() as $file) {
echo "{$file->filename} - {$file->createdAt->format(DATE_ATOM)}\n";
}
// Delete a file
$client->files->delete($fileId);
client = Anthropic::Client.new
file_id = "file_011CNha8iCJcU1wXNR6q4V8w"
# Get file metadata
file_info = client.files.retrieve_metadata(file_id)
puts "Filename: #{file_info.filename}, Size: #{file_info.size_bytes} bytes"
# List all files
client.files.list.auto_paging_each do |file|
puts "#{file.filename} - #{file.created_at}"
end
# Delete a file
client.files.delete(file_id)
멀티턴 대화 (Multi-turn conversations)
응답의 container 객체가 컨테이너의 id와 expires_at 타임스탬프를 지녀요(컨테이너 재사용에서 수명 세부사항 참조). 컨테이너 ID를 지정해 여러 메시지에서 같은 컨테이너를 재사용하세요:
# First request creates container
CONTAINER_ID=$(ant messages create \
--transform container.id \
--raw-output <<'YAML'
model: claude-opus-5-5
max_tokens: 4096
container:
skills:
- {type: anthropic, skill_id: xlsx, version: latest}
messages:
- role: user
content: Create a sample sales dataset and analyze it
tools:
- {type: code_execution_20250825, name: code_execution}
YAML
)
# Continue conversation with same container
ant messages create <<YAML
model: claude-opus-5-5
max_tokens: 4096
container:
id: $CONTAINER_ID # Reuse container
skills:
- {type: anthropic, skill_id: xlsx, version: latest}
messages:
- role: user
content: Create a sample sales dataset and analyze it
- role: assistant
content: [] # the assistant's text from the first response
- role: user
content: What was the total revenue?
tools:
- {type: code_execution_20250825, name: code_execution}
YAML
client = anthropic.Anthropic()
# First request creates container
response1 = client.messages.create(
model="claude-opus-5-5",
max_tokens=4096,
container={
"skills": [{"type": "anthropic", "skill_id": "xlsx", "version": "latest"}]
},
messages=[
{"role": "user", "content": "Create a sample sales dataset and analyze it"}
],
tools=[{"type": "code_execution_20250825", "name": "code_execution"}],
)
# Continue conversation with same container
messages = [
{"role": "user", "content": "Create a sample sales dataset and analyze it"},
{
# Carry the assistant's text forward; container.id carries the execution state
"role": "assistant",
"content": "\n".join(
block.text for block in response1.content if block.type == "text"
),
},
{"role": "user", "content": "What was the total revenue?"},
]
response2 = client.messages.create(
model="claude-opus-5-5",
max_tokens=4096,
container={
"id": response1.container.id, # Reuse container
"skills": [{"type": "anthropic", "skill_id": "xlsx", "version": "latest"}],
},
messages=messages,
tools=[{"type": "code_execution_20250825", "name": "code_execution"}],
)
const client = new Anthropic();
// First request creates container
const response1 = await client.messages.create({
model: "claude-opus-5-5",
max_tokens: 4096,
container: {
skills: [{ type: "anthropic", skill_id: "xlsx", version: "latest" }]
},
messages: [{ role: "user", content: "Create a sample sales dataset and analyze it" }],
tools: [{ type: "code_execution_20250825", name: "code_execution" }]
});
// Continue conversation with same container
const messages: Anthropic.MessageParam[] = [
{ role: "user", content: "Create a sample sales dataset and analyze it" },
{
role: "assistant",
// Carry the assistant's text forward; container.id carries the execution state
content: response1.content
.filter((block) => block.type === "text")
.map((block) => block.text)
.join("\n")
},
{ role: "user", content: "What was the total revenue?" }
];
const response2 = await client.messages.create({
model: "claude-opus-5-5",
max_tokens: 4096,
container: {
id: response1.container!.id, // Reuse container
skills: [{ type: "anthropic", skill_id: "xlsx", version: "latest" }]
},
messages,
tools: [{ type: "code_execution_20250825", name: "code_execution" }]
});
AnthropicClient client = new();
// First request with a Skill
var parameters1 = new MessageCreateParams
{
Model = "claude-opus-5-5",
MaxTokens = 4096,
Container = new ContainerParams
{
Skills =
[
new SkillParams
{
Type = SkillParamsType.Anthropic,
SkillID = "xlsx",
Version = "latest",
},
],
},
Messages = [new() { Role = Role.User, Content = "Create a sample sales dataset and analyze it" }],
Tools = [new CodeExecutionTool20250825()],
};
var response1 = await client.Messages.Create(parameters1);
// Continue the conversation in the same container
// Carry the assistant's text forward; container.id carries the execution state
var assistantText = string.Join(
"\n",
response1.Content.Select(block => block.TryPickText(out var text) ? text.Text : null).Where(text => text is not null)
);
var parameters2 = new MessageCreateParams
{
Model = "claude-opus-5-5",
MaxTokens = 4096,
Container = new ContainerParams
{
ID = response1.Container!.ID,
Skills =
[
new SkillParams
{
Type = SkillParamsType.Anthropic,
SkillID = "xlsx",
Version = "latest",
},
],
},
Messages =
[
new() { Role = Role.User, Content = "Create a sample sales dataset and analyze it" },
new() { Role = Role.Assistant, Content = assistantText },
new() { Role = Role.User, Content = "What was the total revenue?" },
],
Tools = [new CodeExecutionTool20250825()],
};
var response2 = await client.Messages.Create(parameters2);
Console.WriteLine(response2);
client := anthropic.NewClient()
response1, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
Model: "claude-opus-5-5",
MaxTokens: 4096,
Container: anthropic.MessageCreateParamsContainerUnion{
OfContainers: &anthropic.ContainerParams{
Skills: []anthropic.SkillParams{
{
Type: anthropic.SkillParamsTypeAnthropic,
SkillID: "xlsx",
Version: anthropic.String("latest"),
},
},
},
},
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("Create a sample sales dataset and analyze it")),
},
Tools: []anthropic.ToolUnionParam{
{OfCodeExecutionTool20250825: &anthropic.CodeExecutionTool20250825Param{}},
},
})
if err != nil {
log.Fatal(err)
}
// Carry the assistant's text forward; container.id carries the execution state
var textParts []string
for _, block := range response1.Content {
if block.Type == "text" {
textParts = append(textParts, block.Text)
}
}
assistantText := strings.Join(textParts, "\n")
response2, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
Model: "claude-opus-5-5",
MaxTokens: 4096,
Container: anthropic.MessageCreateParamsContainerUnion{
OfContainers: &anthropic.ContainerParams{
ID: anthropic.String(response1.Container.ID), // Reuse container
Skills: []anthropic.SkillParams{
{
Type: anthropic.SkillParamsTypeAnthropic,
SkillID: "xlsx",
Version: anthropic.String("latest"),
},
},
},
},
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("Create a sample sales dataset and analyze it")),
{
Role: anthropic.MessageParamRoleAssistant,
Content: []anthropic.ContentBlockParamUnion{anthropic.NewTextBlock(assistantText)},
},
anthropic.NewUserMessage(anthropic.NewTextBlock("What was the total revenue?")),
},
Tools: []anthropic.ToolUnionParam{
{OfCodeExecutionTool20250825: &anthropic.CodeExecutionTool20250825Param{}},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(response2)
import com.anthropic.models.messages.ContainerParams;
import com.anthropic.models.messages.SkillParams;
import com.anthropic.models.messages.CodeExecutionTool20250825;
import com.anthropic.models.messages.ContentBlock;
// ...
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
MessageCreateParams params1 = MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_5_5)
.maxTokens(4096L)
.container(ContainerParams.builder()
.addSkill(SkillParams.builder()
.type(SkillParams.Type.ANTHROPIC)
.skillId("xlsx")
.version("latest")
.build())
.build())
.addUserMessage("Create a sample sales dataset and analyze it")
.addTool(CodeExecutionTool20250825.builder().build())
.build();
Message response1 = client.messages().create(params1);
MessageCreateParams params2 = MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_5_5)
.maxTokens(4096L)
.container(ContainerParams.builder()
.id(response1.container().get().id())
.addSkill(SkillParams.builder()
.type(SkillParams.Type.ANTHROPIC)
.skillId("xlsx")
.version("latest")
.build())
.build())
.addUserMessage("Create a sample sales dataset and analyze it")
// Carry the assistant's text forward; container.id carries the execution state
.addAssistantMessage(response1.content().stream()
.filter(ContentBlock::isText)
.map(block -> block.asText().text())
.collect(Collectors.joining("\n")))
.addUserMessage("What was the total revenue?")
.addTool(CodeExecutionTool20250825.builder().build())
.build();
Message response2 = client.messages().create(params2);
System.out.println(response2);
}
$client = new Client();
$response1 = $client->messages->create(
maxTokens: 4096,
messages: [
['role' => 'user', 'content' => 'Create a sample sales dataset and analyze it']
],
model: 'claude-opus-5-5',
container: [
'skills' => [
['type' => 'anthropic', 'skillID' => 'xlsx', 'version' => 'latest']
]
],
tools: [
['type' => 'code_execution_20250825', 'name' => 'code_execution']
]
);
$messages = [
['role' => 'user', 'content' => 'Create a sample sales dataset and analyze it'],
// Carry the assistant's text forward; container.id carries the execution state
['role' => 'assistant', 'content' => implode("\n", array_map(
fn ($block) => $block->text,
array_filter($response1->content, fn ($block) => $block->type === 'text'),
))],
['role' => 'user', 'content' => 'What was the total revenue?']
];
$response2 = $client->messages->create(
maxTokens: 4096,
messages: $messages,
model: 'claude-opus-5-5',
container: [
'id' => $response1->container->id,
'skills' => [
['type' => 'anthropic', 'skillID' => 'xlsx', 'version' => 'latest']
]
],
tools: [
['type' => 'code_execution_20250825', 'name' => 'code_execution']
]
);
echo $response2;
client = Anthropic::Client.new
response1 = client.messages.create(
model: "claude-opus-5-5",
max_tokens: 4096,
container: {
skills: [{ type: "anthropic", skill_id: "xlsx", version: "latest" }]
},
messages: [
{ role: "user", content: "Create a sample sales dataset and analyze it" }
],
tools: [
{ type: "code_execution_20250825", name: "code_execution" }
]
)
messages = [
{ role: "user", content: "Create a sample sales dataset and analyze it" },
{
# Carry the assistant's text forward; container.id carries the execution state
role: "assistant",
content: response1.content.filter_map { |block| block.text if block.type == :text }.join("\n")
},
{ role: "user", content: "What was the total revenue?" }
]
response2 = client.messages.create(
model: "claude-opus-5-5",
max_tokens: 4096,
container: {
id: response1.container.id,
skills: [
{ type: "anthropic", skill_id: "xlsx", version: "latest" }
]
},
messages: messages,
tools: [
{ type: "code_execution_20250825", name: "code_execution" }
]
)
puts response2
장기 실행 작업 (Long-running operations)
스킬은 여러 턴이 필요한 작업을 수행할 수 있어요. pause_turn 중지 이유를 처리하세요:
If stop_reason is "pause_turn", continue in the same container, appending
the prior response's content array to messages as the assistant turn.
Repeat this continuation request until stop_reason is no longer "pause_turn".
STOP_REASON=$(echo "$RESPONSE" | jq -r '.stop_reason') CONTAINER_ID=$(echo "$RESPONSE" | jq -r '.container.id')
RESPONSE=$(curl https://api.anthropic.com/v1/messages
-H "x-api-key: $ANTHR...KEY"
-H "anthropic-version: 2023-06-01"
-H "content-type: application/json"
-d "{
"model": "claude-opus-5-5",
"max_tokens": 4096,
"container": {
"id": "$CONTAINER_ID",
"skills": [{
"type": "custom",
"skill_id": "skill_01AbCdEfGhIjKlMnOpQrStUv",
"version": "latest"
}]
},
"messages": [],
"tools": [{
"type": "code_execution_20250825",
"name": "code_execution"
}]
}")
```bash CLI
RESP=$(mktemp)
# Initial request: capture the full JSON response to a temp file
ant messages create > "$RESP" <<'YAML'
model: claude-opus-5-5
max_tokens: 4096
container:
skills:
- type: custom
skill_id: skill_01AbCdEfGhIjKlMnOpQrStUv
version: latest
messages:
- role: user
content: Generate and process a large sample dataset
tools:
- type: code_execution_20250825
name: code_execution
YAML
# If stop_reason is "pause_turn", continue in the same container,
# appending the prior response's content array to messages as the
# assistant turn. Repeat until stop_reason is no longer "pause_turn".
CONTAINER_ID=$(jq -r '.container.id' "$RESP")
ant messages create > "$RESP" <<YAML
model: claude-opus-5-5
max_tokens: 4096
container:
id: $CONTAINER_ID
skills:
- type: custom
skill_id: skill_01AbCdEfGhIjKlMnOpQrStUv
version: latest
messages: [] # replace with conversation history + prior assistant content
tools:
- type: code_execution_20250825
name: code_execution
YAML
client = anthropic.Anthropic()
messages = [{"role": "user", "content": "Generate and process a large sample dataset"}]
max_retries = 10
response = client.messages.create(
model="claude-opus-5-5",
max_tokens=4096,
container={
"skills": [
{
"type": "custom",
"skill_id": "skill_01AbCdEfGhIjKlMnOpQrStUv",
"version": "latest",
}
]
},
messages=messages,
tools=[{"type": "code_execution_20250825", "name": "code_execution"}],
)
# Handle pause_turn for long operations
for _ in range(max_retries):
if response.stop_reason != "pause_turn":
break
messages.append({"role": "assistant", "content": response.content})
response = client.messages.create(
model="claude-opus-5-5",
max_tokens=4096,
container={
"id": response.container.id,
"skills": [
{
"type": "custom",
"skill_id": "skill_01AbCdEfGhIjKlMnOpQrStUv",
"version": "latest",
}
],
},
messages=messages,
tools=[{"type": "code_execution_20250825", "name": "code_execution"}],
)
const client = new Anthropic();
const messages: Anthropic.MessageParam[] = [
{ role: "user", content: "Generate and process a large sample dataset" }
];
const maxRetries = 10;
let response = await client.messages.create({
model: "claude-opus-5-5",
max_tokens: 4096,
container: {
skills: [{ type: "custom", skill_id: "skill_01AbCdEfGhIjKlMnOpQrStUv", version: "latest" }]
},
messages,
tools: [{ type: "code_execution_20250825", name: "code_execution" }]
});
// Handle pause_turn for long operations
for (let i = 0; i < maxRetries; i++) {
if (response.stop_reason !== "pause_turn") {
break;
}
messages.push({
role: "assistant",
content: response.content as Anthropic.ContentBlockParam[]
});
response = await client.messages.create({
model: "claude-opus-5-5",
max_tokens: 4096,
container: {
id: response.container!.id,
skills: [
{ type: "custom", skill_id: "skill_01AbCdEfGhIjKlMnOpQrStUv", version: "latest" }
]
},
messages,
tools: [{ type: "code_execution_20250825", name: "code_execution" }]
});
}
using System.Text.Json;
// ...
AnthropicClient client = new();
List<MessageParam> messages =
[
new() { Role = Role.User, Content = "Generate and process a large sample dataset" },
];
var maxRetries = 10;
string? containerId = null;
Message? response = null;
for (var i = 0; i < maxRetries; i++)
{
var parameters = new MessageCreateParams
{
Model = "claude-opus-5-5",
MaxTokens = 4096,
Container = containerId is null
? new ContainerParams
{
Skills =
[
new SkillParams
{
Type = SkillParamsType.Custom,
SkillID = "skill_01AbCdEfGhIjKlMnOpQrStUv",
Version = "latest",
},
],
}
: new ContainerParams
{
ID = containerId,
Skills =
[
new SkillParams
{
Type = SkillParamsType.Custom,
SkillID = "skill_01AbCdEfGhIjKlMnOpQrStUv",
Version = "latest",
},
],
},
Messages = messages,
Tools = [new CodeExecutionTool20250825()],
};
response = await client.Messages.Create(parameters);
containerId = response.Container!.ID;
if (response.StopReason != StopReason.PauseTurn)
{
break;
}
// Append the paused turn's content and continue
var assistantContent = JsonSerializer.SerializeToElement(
response.Content.Select(block => block.Json).ToArray()
);
messages.Add(new() { Role = Role.Assistant, Content = new MessageParamContent(assistantContent) });
}
client := anthropic.NewClient()
messages := []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("Generate and process a large sample dataset")),
}
maxRetries := 10
response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
Model: "claude-opus-5-5",
MaxTokens: 4096,
Container: anthropic.MessageCreateParamsContainerUnion{
OfContainers: &anthropic.ContainerParams{
Skills: []anthropic.SkillParams{
{
Type: anthropic.SkillParamsTypeCustom,
SkillID: "skill_01AbCdEfGhIjKlMnOpQrStUv",
Version: anthropic.String("latest"),
},
},
},
},
Messages: messages,
Tools: []anthropic.ToolUnionParam{
{OfCodeExecutionTool20250825: &anthropic.CodeExecutionTool20250825Param{}},
},
})
if err != nil {
log.Fatal(err)
}
for i := 0; i < maxRetries; i++ {
if response.StopReason != anthropic.StopReasonPauseTurn {
break
}
messages = append(messages, response.ToParam())
response, err = client.Messages.New(context.TODO(), anthropic.MessageNewParams{
Model: "claude-opus-5-5",
MaxTokens: 4096,
Container: anthropic.MessageCreateParamsContainerUnion{
OfContainers: &anthropic.ContainerParams{
ID: anthropic.String(response.Container.ID), // Reuse container
Skills: []anthropic.SkillParams{
{
Type: anthropic.SkillParamsTypeCustom,
SkillID: "skill_01AbCdEfGhIjKlMnOpQrStUv",
Version: anthropic.String("latest"),
},
},
},
},
Messages: messages,
Tools: []anthropic.ToolUnionParam{
{OfCodeExecutionTool20250825: &anthropic.CodeExecutionTool20250825Param{}},
},
})
if err != nil {
log.Fatal(err)
}
}
fmt.Println(response)
import com.anthropic.models.messages.ContainerParams;
import com.anthropic.models.messages.SkillParams;
import com.anthropic.models.messages.CodeExecutionTool20250825;
import com.anthropic.models.messages.StopReason;
// ...
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
List<MessageParam> messages = new ArrayList<>();
messages.add(
MessageParam.builder()
.role(MessageParam.Role.USER)
.content("Generate and process a large sample dataset")
.build()
);
int maxRetries = 10;
Message response = client.messages().create(
MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_5_5)
.maxTokens(4096L)
.container(ContainerParams.builder()
.addSkill(SkillParams.builder()
.type(SkillParams.Type.CUSTOM)
.skillId("skill_01AbCdEfGhIjKlMnOpQrStUv")
.version("latest")
.build())
.build())
.messages(messages)
.addTool(CodeExecutionTool20250825.builder().build())
.build());
for (int i = 0; i < maxRetries; i++) {
if (!response.stopReason().isPresent()
|| !response.stopReason().get().equals(StopReason.PAUSE_TURN)) {
break;
}
messages.add(response.toParam());
response = client.messages().create(
MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_5_5)
.maxTokens(4096L)
.container(ContainerParams.builder()
.id(response.container().get().id())
.addSkill(SkillParams.builder()
.type(SkillParams.Type.CUSTOM)
.skillId("skill_01AbCdEfGhIjKlMnOpQrStUv")
.version("latest")
.build())
.build())
.messages(messages)
.addTool(CodeExecutionTool20250825.builder().build())
.build());
}
}
$client = new Client();
$messages = [
['role' => 'user', 'content' => 'Generate and process a large sample dataset']
];
$maxRetries = 10;
$response = $client->messages->create(
maxTokens: 4096,
messages: $messages,
model: 'claude-opus-5-5',
container: [
'skills' => [
[
'type' => 'custom',
'skillID' => 'skill_01AbCdEfGhIjKlMnOpQrStUv',
'version' => 'latest'
]
]
],
tools: [['type' => 'code_execution_20250825', 'name' => 'code_execution']]
);
for ($i = 0; $i < $maxRetries; $i++) {
if ($response->stopReason !== 'pause_turn') {
break;
}
$messages[] = ['role' => 'assistant', 'content' => $response->content];
$response = $client->messages->create(
maxTokens: 4096,
messages: $messages,
model: 'claude-opus-5-5',
container: [
'id' => $response->container->id,
'skills' => [
[
'type' => 'custom',
'skillID' => 'skill_01AbCdEfGhIjKlMnOpQrStUv',
'version' => 'latest'
]
]
],
tools: [['type' => 'code_execution_20250825', 'name' => 'code_execution']]
);
}
client = Anthropic::Client.new
messages = [
{ role: "user", content: "Generate and process a large sample dataset" }
]
max_retries = 10
response = client.messages.create(
model: "claude-opus-5-5",
max_tokens: 4096,
container: {
skills: [
{
type: "custom",
skill_id: "skill_01AbCdEfGhIjKlMnOpQrStUv",
version: "latest"
}
]
},
messages: messages,
tools: [{ type: "code_execution_20250825", name: "code_execution" }]
)
max_retries.times do
break if response.stop_reason != :pause_turn
messages << { role: "assistant", content: response.content }
response = client.messages.create(
model: "claude-opus-5-5",
max_tokens: 4096,
container: {
id: response.container.id,
skills: [
{
type: "custom",
skill_id: "skill_01AbCdEfGhIjKlMnOpQrStUv",
version: "latest"
}
]
},
messages: messages,
tools: [{ type: "code_execution_20250825", name: "code_execution" }]
)
end
여러 스킬 사용하기 (Using multiple Skills)
복잡한 워크플로를 처리하기 위해 단일 요청에서 여러 스킬을 결합하세요:
ant messages create <<'YAML'
model: claude-opus-5-5
max_tokens: 4096
container:
skills:
- type: anthropic
skill_id: xlsx
version: latest
- type: anthropic
skill_id: pptx
version: latest
- type: custom
skill_id: skill_01AbCdEfGhIjKlMnOpQrStUv
version: latest
messages:
- role: user
content: Analyze sales data and create a presentation
tools:
- type: code_execution_20250825
name: code_execution
YAML
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-5-5",
max_tokens=4096,
container={
"skills": [
{"type": "anthropic", "skill_id": "xlsx", "version": "latest"},
{"type": "anthropic", "skill_id": "pptx", "version": "latest"},
{
"type": "custom",
"skill_id": "skill_01AbCdEfGhIjKlMnOpQrStUv",
"version": "latest",
},
]
},
messages=[
{"role": "user", "content": "Analyze sales data and create a presentation"}
],
tools=[{"type": "code_execution_20250825", "name": "code_execution"}],
)
const client = new Anthropic();
const response = await client.messages.create({
model: "claude-opus-5-5",
max_tokens: 4096,
container: {
skills: [
{
type: "anthropic",
skill_id: "xlsx",
version: "latest"
},
{
type: "anthropic",
skill_id: "pptx",
version: "latest"
},
{
type: "custom",
skill_id: "skill_01AbCdEfGhIjKlMnOpQrStUv",
version: "latest"
}
]
},
messages: [
{
role: "user",
content: "Analyze sales data and create a presentation"
}
],
tools: [
{
type: "code_execution_20250825",
name: "code_execution"
}
]
});
AnthropicClient client = new();
var parameters = new MessageCreateParams
{
Model = "claude-opus-5-5",
MaxTokens = 4096,
Container = new ContainerParams
{
Skills =
[
new SkillParams
{
Type = SkillParamsType.Anthropic,
SkillID = "xlsx",
Version = "latest",
},
new SkillParams
{
Type = SkillParamsType.Anthropic,
SkillID = "pptx",
Version = "latest",
},
new SkillParams
{
Type = SkillParamsType.Custom,
SkillID = "skill_01AbCdEfGhIjKlMnOpQrStUv",
Version = "latest",
},
],
},
Messages = [new() { Role = Role.User, Content = "Analyze sales data and create a presentation" }],
Tools = [new CodeExecutionTool20250825()],
};
var message = await client.Messages.Create(parameters);
Console.WriteLine(message);
client := anthropic.NewClient()
response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
Model: "claude-opus-5-5",
MaxTokens: 4096,
Container: anthropic.MessageCreateParamsContainerUnion{
OfContainers: &anthropic.ContainerParams{
Skills: []anthropic.SkillParams{
{
Type: anthropic.SkillParamsTypeAnthropic,
SkillID: "xlsx",
Version: anthropic.String("latest"),
},
{
Type: anthropic.SkillParamsTypeAnthropic,
SkillID: "pptx",
Version: anthropic.String("latest"),
},
{
Type: anthropic.SkillParamsTypeCustom,
SkillID: "skill_01AbCdEfGhIjKlMnOpQrStUv",
Version: anthropic.String("latest"),
},
},
},
},
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("Analyze sales data and create a presentation")),
},
Tools: []anthropic.ToolUnionParam{
{OfCodeExecutionTool20250825: &anthropic.CodeExecutionTool20250825Param{}},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(response)
import com.anthropic.models.messages.ContainerParams;
import com.anthropic.models.messages.SkillParams;
import com.anthropic.models.messages.CodeExecutionTool20250825;
// ...
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
MessageCreateParams params = MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_5_5)
.maxTokens(4096L)
.container(ContainerParams.builder()
.skills(List.of(
SkillParams.builder()
.type(SkillParams.Type.ANTHROPIC)
.skillId("xlsx")
.version("latest")
.build(),
SkillParams.builder()
.type(SkillParams.Type.ANTHROPIC)
.skillId("pptx")
.version("latest")
.build(),
SkillParams.builder()
.type(SkillParams.Type.CUSTOM)
.skillId("skill_01AbCdEfGhIjKlMnOpQrStUv")
.version("latest")
.build()
))
.build())
.addUserMessage("Analyze sales data and create a presentation")
.addTool(CodeExecutionTool20250825.builder().build())
.build();
Message response = client.messages().create(params);
System.out.println(response);
}
$client = new Client();
$message = $client->messages->create(
maxTokens: 4096,
messages: [
['role' => 'user', 'content' => 'Analyze sales data and create a presentation']
],
model: 'claude-opus-5-5',
container: [
'skills' => [
[
'type' => 'anthropic',
'skillID' => 'xlsx',
'version' => 'latest'
],
[
'type' => 'anthropic',
'skillID' => 'pptx',
'version' => 'latest'
],
[
'type' => 'custom',
'skillID' => 'skill_01AbCdEfGhIjKlMnOpQrStUv',
'version' => 'latest'
]
]
],
tools: [
['type' => 'code_execution_20250825', 'name' => 'code_execution']
]
);
echo $message;
client = Anthropic::Client.new
message = client.messages.create(
model: "claude-opus-5-5",
max_tokens: 4096,
container: {
skills: [
{
type: "anthropic",
skill_id: "xlsx",
version: "latest"
},
{
type: "anthropic",
skill_id: "pptx",
version: "latest"
},
{
type: "custom",
skill_id: "skill_01AbCdEfGhIjKlMnOpQrStUv",
version: "latest"
}
]
},
messages: [
{ role: "user", content: "Analyze sales data and create a presentation" }
],
tools: [
{ type: "code_execution_20250825", name: "code_execution" }
]
)
puts message
커스텀 스킬 관리하기 (Managing custom Skills)
Skills API에 멀티테넌트 플랫폼을 구축한다면 각 테넌트에 별도 워크스페이스를 만드세요. 워크스페이스는 커스텀 스킬의 격리 경계이므로, 테넌트당 워크스페이스 하나가 각 테넌트의 스킬을 다른 모든 테넌트로부터 강하게 격리해요. 각 조직은 기본적으로 최대 100개의 워크스페이스를 가질 수 있어요(워크스페이스 동작 방식 참조). 테넌트 격리를 위해 더 필요하면 계정 팀에 문의하세요.
스킬 만들기 (Creating a Skill)
스킬 번들(Skill bundle)은 최상위에 name과 description YAML frontmatter가 있는 SKILL.md 파일과 지원 스크립트·리소스를 포함하는 디렉터리예요. 작성 방법은 API에서 에이전트 스킬 시작하기를 참고하고, 전체 제약 조건은 예시 다음의 요구사항 목록을 보세요.
커스텀 스킬을 업로드해 워크스페이스에서 사용 가능하게 하세요. zip 아카이브 또는 개별 파일 객체를 업로드할 수 있어요. Python SDK는 디렉터리 경로를 받는 files_from_dir 헬퍼도 제공하고, CLI의 ant apply는 디렉터리 자체를 업로드해요.
파일은 붙이는 파일 이름으로 식별돼요(cURL 예시의 ;filename= 접미사와 SDK 예시의 파일 이름 인자). 워크스루의 스킬에 대해서는 zip -r financial_skill.zip financial_skill/로 zip을 만들고 zip 업로드 옵션의 example_skill.zip 플레이스홀더를 그것으로 대체하세요.
<File filename="financial_skill/SKILL.md">
```markdown
---
name: financial-skill
description: Docs example skill.
---
```
</File>
<File filename="financial_skill/analyze.py">
```python
print("financial analysis helper")
```
</File>
from anthropic.lib import files_from_dir
client = anthropic.Anthropic()
# Option 1: Using a zip file
skill = client.skills.create(
files=[open("example_skill.zip", "rb")],
)
# Option 2: Using file tuples (filename, file_content, mime_type)
skill = client.skills.create(
files=[
(
"financial_skill/SKILL.md",
open("financial_skill/SKILL.md", "rb"),
"text/markdown",
),
(
"financial_skill/analyze.py",
open("financial_skill/analyze.py", "rb"),
"text/x-python",
),
],
)
# Option 3: Using the files_from_dir helper (Python only)
skill = client.skills.create(
files=files_from_dir("financial_skill"),
)
print(f"Created skill: {skill.id}")
print(f"Latest version: {skill.latest_version_id}")
import { toFile } from "@anthropic-ai/sdk";
import fs from "node:fs";
// ...
const client = new Anthropic();
// Option 1: Using a zip file
const skillFromZip = await client.skills.create({
files: [await toFile(fs.createReadStream("example_skill.zip"), "example_skill.zip")]
});
// Option 2: Using individual file objects
const skill = await client.skills.create({
files: [
await toFile(fs.createReadStream("financial_skill/SKILL.md"), "financial_skill/SKILL.md", {
type: "text/markdown"
}),
await toFile(
fs.createReadStream("financial_skill/analyze.py"),
"financial_skill/analyze.py",
{ type: "text/x-python" }
)
]
});
console.log(`Created skill: ${skill.id}`);
console.log(`Latest version: ${skill.latest_version_id}`);
using Anthropic.Core;
// ...
AnthropicClient client = new();
// Option 1: Using a zip file
var parameters = new SkillCreateParams
{
Files = [File.OpenRead("example_skill.zip")],
};
var skill = await client.Skills.Create(parameters);
// Option 2: Using individual files (path-qualified filenames preserve the Skill's directory layout)
var parameters2 = new SkillCreateParams
{
Files =
[
new BinaryContent
{
Stream = File.OpenRead("financial_skill/SKILL.md"),
FileName = "financial_skill/SKILL.md",
},
new BinaryContent
{
Stream = File.OpenRead("financial_skill/analyze.py"),
FileName = "financial_skill/analyze.py",
},
],
};
var skill2 = await client.Skills.Create(parameters2);
Console.WriteLine($"Created skill: {skill.ID}");
Console.WriteLine($"Latest version: {skill.LatestVersionID}");
Console.WriteLine($"Created skill 2: {skill2.ID}");
client := anthropic.NewClient()
// Option 1: Using a zip file
zipFile, err := os.Open("example_skill.zip")
if err != nil {
log.Fatal(err)
}
defer zipFile.Close()
skill, err := client.Skills.New(context.TODO(), anthropic.SkillNewParams{
Files: []io.Reader{zipFile},
})
if err != nil {
log.Fatal(err)
}
// Option 2: Using individual files
skillMd, err := os.Open("financial_skill/SKILL.md")
if err != nil {
log.Fatal(err)
}
defer skillMd.Close()
analyzePy, err := os.Open("financial_skill/analyze.py")
if err != nil {
log.Fatal(err)
}
defer analyzePy.Close()
skill2, err := client.Skills.New(context.TODO(), anthropic.SkillNewParams{
Files: []io.Reader{
anthropic.File(skillMd, "financial_skill/SKILL.md", "text/markdown"),
anthropic.File(analyzePy, "financial_skill/analyze.py", "text/x-python"),
},
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Created skill: %s\n", skill.ID)
fmt.Printf("Latest version: %s\n", skill.LatestVersionID)
fmt.Printf("Created skill 2: %s\n", skill2.ID)
import com.anthropic.core.MultipartField;
import com.anthropic.models.skills.SkillCreateParams;
import com.anthropic.models.skills.Skill;
// ...
void main() throws Exception {
// ...
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
// Option 1: Using a zip file
SkillCreateParams params = SkillCreateParams.builder()
.addFile(MultipartField.<InputStream>builder()
.value(Files.newInputStream(Path.of("example_skill.zip")))
.filename("example_skill.zip")
.contentType("application/zip")
.build())
.build();
Skill skill = client.skills().create(params);
// Option 2: Using individual files (path-qualified filenames preserve the Skill's directory layout)
SkillCreateParams params2 = SkillCreateParams.builder()
.addFile(MultipartField.<InputStream>builder()
.value(Files.newInputStream(Path.of("financial_skill/SKILL.md")))
.filename("financial_skill/SKILL.md")
.contentType("text/markdown")
.build())
.addFile(MultipartField.<InputStream>builder()
.value(Files.newInputStream(Path.of("financial_skill/analyze.py")))
.filename("financial_skill/analyze.py")
.contentType("text/x-python")
.build())
.build();
Skill skill2 = client.skills().create(params2);
System.out.println("Created skill: " + skill.id());
System.out.println("Latest version: " + skill.latestVersionId());
System.out.println("Created skill 2: " + skill2.id());
}
use Anthropic\Core\FileParam;
// ...
$client = new Client();
// Option 1: Using a zip file
$skill = $client->skills->create(
files: [
FileParam::fromResource(fopen('example_skill.zip', 'r')),
],
);
// Option 2: Using individual files
$skill = $client->skills->create(
files: [
FileParam::fromResource(
fopen('financial_skill/SKILL.md', 'r'),
filename: 'financial_skill/SKILL.md',
contentType: 'text/markdown',
),
FileParam::fromResource(
fopen('financial_skill/analyze.py', 'r'),
filename: 'financial_skill/analyze.py',
contentType: 'text/x-python',
),
],
);
echo "Created skill: {$skill->id}\n";
echo "Latest version: {$skill->latestVersionID}\n";
client = Anthropic::Client.new
# Option 1: Using a zip file
skill = client.skills.create(
files: [
File.open("example_skill.zip", "rb")
]
)
# Option 2: Using individual files
skill = client.skills.create(
files: [
Anthropic::FilePart.new(
Pathname("financial_skill/SKILL.md"),
filename: "financial_skill/SKILL.md",
content_type: "text/markdown"
),
Anthropic::FilePart.new(
Pathname("financial_skill/analyze.py"),
filename: "financial_skill/analyze.py",
content_type: "text/x-python"
)
]
)
puts "Created skill: #{skill.id}"
puts "Latest version: #{skill.latest_version_id}"
요구사항 (Requirements):
-
업로드 루트(또는 단일 감싸는 폴더의 최상단)에
SKILL.md파일이 포함되어야 함 -
display_name은 선택 사항: 생략하면SKILL.md의name에서 파생되고, 명시적 값은 최대 255자이며 워크스페이스 내에서 고유할 필요 없음 -
총 업로드 크기는 30 MB(압축 전) 미만이어야 함
-
YAML frontmatter 요구사항:
name: 최대 64자, 소문자/숫자/하이픈만, XML 태그 없음, 예약어 없음("anthropic", "claude")description: 최대 1024자, 비어 있지 않음, XML 태그 없음
완전한 요청/응답 스키마는 스킬 생성 API 레퍼런스를 참고하세요.
스킬 나열하기 (Listing Skills)
Anthropic이 미리 만든 스킬과 커스텀 스킬을 포함해 워크스페이스에서 사용 가능한 모든 스킬을 가져오세요. source 파라미터로 스킬 유형별로 필터링하세요:
List only custom Skills
curl "https://api.anthropic.com/v1/skills?source=custom"
-H "x-api-key: $ANTHR...KEY"
-H "anthropic-version: 2023-06-01"
```bash CLI
# List all Skills
ant skills list
# List only custom Skills
ant skills list --source custom
client = anthropic.Anthropic()
# List all Skills
for skill in client.skills.list():
print(f"{skill.id}: {skill.display_name} (source: {skill.source.type})")
# List only custom Skills
custom_skills = client.skills.list(source="custom")
const client = new Anthropic();
// List all Skills
for await (const skill of client.skills.list()) {
console.log(`${skill.id}: ${skill.display_name} (source: ${skill.source.type})`);
}
// List only custom Skills
const customSkills = await client.skills.list({
source: "custom"
});
AnthropicClient client = new();
// List all Skills
await foreach (var skill in (await client.Skills.List()).Paginate())
{
Console.WriteLine($"{skill.ID}: {skill.DisplayName} (source: {skill.Source.Type})");
}
// List only custom Skills
var customSkills = await client.Skills.List(new SkillListParams { Source = "custom" });
client := anthropic.NewClient()
// List all Skills
skills := client.Skills.ListAutoPaging(context.TODO(), anthropic.SkillListParams{})
for skills.Next() {
skill := skills.Current()
fmt.Printf("%s: %s (source: %s)\n", skill.ID, skill.DisplayName, skill.Source.Type)
}
if skills.Err() != nil {
log.Fatal(skills.Err())
}
// List only custom Skills
customSkills := client.Skills.ListAutoPaging(context.TODO(), anthropic.SkillListParams{
Source: anthropic.String("custom"),
})
for customSkills.Next() {
skill := customSkills.Current()
fmt.Printf("%s: %s (source: %s)\n", skill.ID, skill.DisplayName, skill.Source.Type)
}
if customSkills.Err() != nil {
log.Fatal(customSkills.Err())
}
import com.anthropic.models.skills.SkillListParams;
import com.anthropic.models.skills.SkillListPage;
import com.anthropic.models.skills.Skill;
// ...
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
// List Skills (first page)
SkillListPage skills = client.skills().list();
for (Skill skill : skills.data()) {
System.out.println(skill.id() + ": " + skill.displayName() + " (source: " + skill.source().type() + ")");
}
// List only custom Skills
SkillListParams customParams = SkillListParams.builder()
.source("custom")
.build();
SkillListPage customSkills = client.skills().list(customParams);
}
$client = new Client();
// List Skills (first page)
foreach ($client->skills->list()->getItems() as $skill) {
echo "{$skill->id}: {$skill->displayName} (source: {$skill->source->type})\n";
}
// List only custom Skills
$customSkills = $client->skills->list(
source: 'custom',
);
client = Anthropic::Client.new
# List all Skills
client.skills.list.auto_paging_each do |skill|
puts "#{skill.id}: #{skill.display_name} (source: #{skill.source.type})"
end
# List only custom Skills
custom_skills = client.skills.list(
source: "custom"
)
페이지네이션과 필터링 옵션은 스킬 목록 API 레퍼런스를 참고하세요.
스킬 조회하기 (Retrieving a Skill)
특정 스킬에 대한 세부 사항을 가져오세요:
ant skills retrieve --skill-id skill_01AbCdEfGhIjKlMnOpQrStUv
client = anthropic.Anthropic()
skill = client.skills.retrieve(skill_id="skill_01AbCdEfGhIjKlMnOpQrStUv")
print(f"Skill: {skill.display_name}")
print(f"Latest version: {skill.latest_version_id}")
print(f"Created: {skill.created_at}")
const client = new Anthropic();
const skill = await client.skills.retrieve("skill_01AbCdEfGhIjKlMnOpQrStUv");
console.log(`Skill: ${skill.display_name}`);
console.log(`Latest version: ${skill.latest_version_id}`);
console.log(`Created: ${skill.created_at}`);
AnthropicClient client = new();
var skill = await client.Skills.Retrieve("skill_01AbCdEfGhIjKlMnOpQrStUv");
Console.WriteLine($"Skill: {skill.DisplayName}");
Console.WriteLine($"Latest version: {skill.LatestVersionID}");
Console.WriteLine($"Created: {skill.CreatedAt}");
client := anthropic.NewClient()
skill, err := client.Skills.Get(
context.TODO(),
"skill_01AbCdEfGhIjKlMnOpQrStUv",
anthropic.SkillGetParams{},
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Skill: %s\n", skill.DisplayName)
fmt.Printf("Latest version: %s\n", skill.LatestVersionID)
fmt.Printf("Created: %s\n", skill.CreatedAt)
import com.anthropic.models.skills.Skill;
// ...
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
Skill skill = client.skills().retrieve("skill_01AbCdEfGhIjKlMnOpQrStUv");
System.out.println("Skill: " + skill.displayName());
System.out.println("Latest version: " + skill.latestVersionId());
System.out.println("Created: " + skill.createdAt());
}
$client = new Client();
$skill = $client->skills->retrieve('skill_01AbCdEfGhIjKlMnOpQrStUv');
echo "Skill: {$skill->displayName}\n";
echo "Latest version: {$skill->latestVersionID}\n";
echo "Created: {$skill->createdAt->format(DATE_ATOM)}\n";
client = Anthropic::Client.new
skill = client.skills.retrieve("skill_01AbCdEfGhIjKlMnOpQrStUv")
puts "Skill: #{skill.display_name}"
puts "Latest version: #{skill.latest_version_id}"
puts "Created: #{skill.created_at}"
스킬 삭제하기 (Deleting a Skill)
스킬을 삭제하면 모든 버전도 제거돼요.
ant skills delete --skill-id skill_01AbCdEfGhIjKlMnOpQrStUv >/dev/null
client = anthropic.Anthropic()
client.skills.delete(skill_id="skill_01AbCdEfGhIjKlMnOpQrStUv")
const client = new Anthropic();
await client.skills.delete("skill_01AbCdEfGhIjKlMnOpQrStUv");
AnthropicClient client = new();
await client.Skills.Delete("skill_01AbCdEfGhIjKlMnOpQrStUv");
client := anthropic.NewClient()
_, err := client.Skills.Delete(
context.TODO(),
"skill_01AbCdEfGhIjKlMnOpQrStUv",
anthropic.SkillDeleteParams{},
)
if err != nil {
log.Fatal(err)
}
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
client.skills().delete("skill_01AbCdEfGhIjKlMnOpQrStUv");
}
$client = new Client();
$client->skills->delete('skill_01AbCdEfGhIjKlMnOpQrStUv');
client = Anthropic::Client.new
client.skills.delete("skill_01AbCdEfGhIjKlMnOpQrStUv")
버전 관리 (Versioning)
스킬은 업데이트를 안전하게 관리하기 위한 버전 관리를 지원해요:
Anthropic 스킬:
- 버전은 날짜 형식을 사용해요:
20251013 - 업데이트가 이루어지면 새 버전이 출시돼요
- 안정성을 위해 정확한 버전을 지정하세요
커스텀 스킬:
- 자동 생성된 버전 ID:
skver_01AbCdEfGhIjKlMnOpQrStUv - 항상 가장 최근 버전을 얻으려면
"latest"를 사용 - 스킬 파일을 업데이트할 때 새 버전 만들기
새 버전은 델타가 아니라 완전한 스냅샷이에요. 매번 스킬의 전체 파일 집합을 업로드하세요. 생략한 파일은 이월되지 않고, 새 버전 SKILL.md의 name은 스킬의 기존 이름과 일치해야 해요. 다음 예시는 스킬 만들기의 완전한 financial_skill/ 번들을 다시 업로드해요.
VERSION_ID=$(echo "$NEW_VERSION" | jq -r '.id')
Use specific version
curl https://api.anthropic.com/v1/messages
-H "x-api-key: $ANTHR...KEY"
-H "anthropic-version: 2023-06-01"
-H "content-type: application/json"
-d "{
"model": "claude-opus-5-5",
"max_tokens": 4096,
"container": {
"skills": [{
"type": "custom",
"skill_id": "skill_01AbCdEfGhIjKlMnOpQrStUv",
"version": "$VERSION_ID"
}]
},
"messages": [{"role": "user", "content": "Use updated Skill"}],
"tools": [{"type": "code_execution_20250825", "name": "code_execution"}]
}"
Use latest version
curl https://api.anthropic.com/v1/messages
-H "x-api-key: $ANTHR...KEY"
-H "anthropic-version: 2023-06-01"
-H "content-type: application/json"
-d '{
"model": "claude-opus-5-5",
"max_tokens": 4096,
"container": {
"skills": [{
"type": "custom",
"skill_id": "skill_01AbCdEfGhIjKlMnOpQrStUv",
"version": "latest"
}]
},
"messages": [{"role": "user", "content": "Use latest Skill version"}],
"tools": [{"type": "code_execution_20250825", "name": "code_execution"}]
}'
```bash CLI
# Create a new version
VERSION_ID=$(ant skills:versions create \
--skill-id skill_01AbCdEfGhIjKlMnOpQrStUv \
--file financial_skill.zip \
--transform id \
--raw-output)
# Use specific version
ant messages create <<YAML
model: claude-opus-5-5
max_tokens: 4096
container:
skills:
- type: custom
skill_id: skill_01AbCdEfGhIjKlMnOpQrStUv
version: "$VERSION_ID"
messages:
- role: user
content: Use updated Skill
tools:
- type: code_execution_20250825
name: code_execution
YAML
# Use latest version
ant messages create <<YAML
model: claude-opus-5-5
max_tokens: 4096
container:
skills:
- type: custom
skill_id: skill_01AbCdEfGhIjKlMnOpQrStUv
version: latest
messages:
- role: user
content: Use latest Skill version
tools:
- type: code_execution_20250825
name: code_execution
YAML
from anthropic.lib import files_from_dir
client = anthropic.Anthropic()
# Create a new version
new_version = client.skills.versions.create(
skill_id="skill_01AbCdEfGhIjKlMnOpQrStUv",
files=files_from_dir("financial_skill"),
)
# Use specific version
response = client.messages.create(
model="claude-opus-5-5",
max_tokens=4096,
container={
"skills": [
{
"type": "custom",
"skill_id": "skill_01AbCdEfGhIjKlMnOpQrStUv",
"version": new_version.id,
}
]
},
messages=[{"role": "user", "content": "Use updated Skill"}],
tools=[{"type": "code_execution_20250825", "name": "code_execution"}],
)
# Use latest version
response = client.messages.create(
model="claude-opus-5-5",
max_tokens=4096,
container={
"skills": [
{
"type": "custom",
"skill_id": "skill_01AbCdEfGhIjKlMnOpQrStUv",
"version": "latest",
}
]
},
messages=[{"role": "user", "content": "Use latest Skill version"}],
tools=[{"type": "code_execution_20250825", "name": "code_execution"}],
)
import fs from "node:fs";
const client = new Anthropic();
// Create a new version from a zip of the complete financial_skill/ bundle
const newVersion = await client.skills.versions.create("skill_01AbCdEfGhIjKlMnOpQrStUv", {
files: [fs.createReadStream("financial_skill.zip")]
});
// Use specific version
const specificVersionResponse = await client.messages.create({
model: "claude-opus-5-5",
max_tokens: 4096,
container: {
skills: [
{
type: "custom",
skill_id: "skill_01AbCdEfGhIjKlMnOpQrStUv",
version: newVersion.id
}
]
},
messages: [{ role: "user", content: "Use updated Skill" }],
tools: [{ type: "code_execution_20250825", name: "code_execution" }]
});
// Use latest version
const latestVersionResponse = await client.messages.create({
model: "claude-opus-5-5",
max_tokens: 4096,
container: {
skills: [
{
type: "custom",
skill_id: "skill_01AbCdEfGhIjKlMnOpQrStUv",
version: "latest"
}
]
},
messages: [{ role: "user", content: "Use latest Skill version" }],
tools: [{ type: "code_execution_20250825", name: "code_execution" }]
});
using Anthropic.Core;
using Anthropic.Models.Skills.Versions;
// ...
AnthropicClient client = new();
// Create a new version
var versionParams = new VersionCreateParams
{
Files =
[
new BinaryContent
{
Stream = File.OpenRead("financial_skill/SKILL.md"),
FileName = "financial_skill/SKILL.md",
},
new BinaryContent
{
Stream = File.OpenRead("financial_skill/analyze.py"),
FileName = "financial_skill/analyze.py",
},
],
};
var newVersion = await client.Skills.Versions.Create("skill_01AbCdEfGhIjKlMnOpQrStUv", versionParams);
// Use specific version
var specificVersionParams = new MessageCreateParams
{
Model = "claude-opus-5-5",
MaxTokens = 4096,
Container = new ContainerParams
{
Skills =
[
new SkillParams
{
Type = SkillParamsType.Custom,
SkillID = "skill_01AbCdEfGhIjKlMnOpQrStUv",
Version = newVersion.ID,
},
],
},
Messages = [new() { Role = Role.User, Content = "Use updated Skill" }],
Tools = [new CodeExecutionTool20250825()],
};
var response = await client.Messages.Create(specificVersionParams);
Console.WriteLine(response);
// Use latest version
var latestVersionParams = new MessageCreateParams
{
Model = "claude-opus-5-5",
MaxTokens = 4096,
Container = new ContainerParams
{
Skills =
[
new SkillParams
{
Type = SkillParamsType.Custom,
SkillID = "skill_01AbCdEfGhIjKlMnOpQrStUv",
Version = "latest",
},
],
},
Messages = [new() { Role = Role.User, Content = "Use latest Skill version" }],
Tools = [new CodeExecutionTool20250825()],
};
var latestResponse = await client.Messages.Create(latestVersionParams);
Console.WriteLine(latestResponse);
client := anthropic.NewClient()
// Create a new version
skillMd, err := os.Open("financial_skill/SKILL.md")
if err != nil {
log.Fatal(err)
}
defer skillMd.Close()
analyzePy, err := os.Open("financial_skill/analyze.py")
if err != nil {
log.Fatal(err)
}
defer analyzePy.Close()
newVersion, err := client.Skills.Versions.New(
context.TODO(),
"skill_01AbCdEfGhIjKlMnOpQrStUv",
anthropic.SkillVersionNewParams{
Files: []io.Reader{
anthropic.File(skillMd, "financial_skill/SKILL.md", "text/markdown"),
anthropic.File(analyzePy, "financial_skill/analyze.py", "text/x-python"),
},
},
)
if err != nil {
log.Fatal(err)
}
// Use specific version
response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
Model: "claude-opus-5-5",
MaxTokens: 4096,
Container: anthropic.MessageCreateParamsContainerUnion{
OfContainers: &anthropic.ContainerParams{
Skills: []anthropic.SkillParams{
{
Type: anthropic.SkillParamsTypeCustom,
SkillID: "skill_01AbCdEfGhIjKlMnOpQrStUv",
Version: anthropic.String(newVersion.ID),
},
},
},
},
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("Use updated Skill")),
},
Tools: []anthropic.ToolUnionParam{
{OfCodeExecutionTool20250825: &anthropic.CodeExecutionTool20250825Param{}},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(response)
// Use latest version
latestResponse, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
Model: "claude-opus-5-5",
MaxTokens: 4096,
Container: anthropic.MessageCreateParamsContainerUnion{
OfContainers: &anthropic.ContainerParams{
Skills: []anthropic.SkillParams{
{
Type: anthropic.SkillParamsTypeCustom,
SkillID: "skill_01AbCdEfGhIjKlMnOpQrStUv",
Version: anthropic.String("latest"),
},
},
},
},
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("Use latest Skill version")),
},
Tools: []anthropic.ToolUnionParam{
{OfCodeExecutionTool20250825: &anthropic.CodeExecutionTool20250825Param{}},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(latestResponse)
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.Model;
import com.anthropic.core.MultipartField;
import com.anthropic.models.messages.ContainerParams;
import com.anthropic.models.messages.SkillParams;
import com.anthropic.models.messages.CodeExecutionTool20250825;
import com.anthropic.models.skills.versions.VersionCreateParams;
import com.anthropic.models.skills.versions.SkillVersion;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
// Create a new version from a zip of the complete financial_skill/ bundle
VersionCreateParams versionParams = VersionCreateParams.builder()
.addFile(MultipartField.<InputStream>builder()
.value(Files.newInputStream(Path.of("financial_skill.zip")))
.filename("financial_skill.zip")
.contentType("application/zip")
.build())
.build();
SkillVersion newVersion = client.skills().versions()
.create("skill_01AbCdEfGhIjKlMnOpQrStUv", versionParams);
// Use specific version
MessageCreateParams specificVersionParams = MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_5_5)
.maxTokens(4096L)
.container(ContainerParams.builder()
.addSkill(SkillParams.builder()
.type(SkillParams.Type.CUSTOM)
.skillId("skill_01AbCdEfGhIjKlMnOpQrStUv")
.version(newVersion.id())
.build())
.build())
.addUserMessage("Use updated Skill")
.addTool(CodeExecutionTool20250825.builder().build())
.build();
Message response = client.messages().create(specificVersionParams);
System.out.println(response);
// Use latest version
MessageCreateParams latestVersionParams = MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_5_5)
.maxTokens(4096L)
.container(ContainerParams.builder()
.addSkill(SkillParams.builder()
.type(SkillParams.Type.CUSTOM)
.skillId("skill_01AbCdEfGhIjKlMnOpQrStUv")
.version("latest")
.build())
.build())
.addUserMessage("Use latest Skill version")
.addTool(CodeExecutionTool20250825.builder().build())
.build();
Message latestResponse = client.messages().create(latestVersionParams);
System.out.println(latestResponse);
use Anthropic\Core\FileParam;
// ...
$client = new Client();
// Create a new version
$newVersion = $client->skills->versions->create(
skillID: 'skill_01AbCdEfGhIjKlMnOpQrStUv',
files: [
FileParam::fromResource(
fopen('financial_skill/SKILL.md', 'r'),
filename: 'financial_skill/SKILL.md',
contentType: 'text/markdown',
),
FileParam::fromResource(
fopen('financial_skill/analyze.py', 'r'),
filename: 'financial_skill/analyze.py',
contentType: 'text/x-python',
),
],
);
// Use specific version
$response = $client->messages->create(
maxTokens: 4096,
messages: [['role' => 'user', 'content' => 'Use updated Skill']],
model: 'claude-opus-5-5',
container: [
'skills' => [[
'type' => 'custom',
'skillID' => 'skill_01AbCdEfGhIjKlMnOpQrStUv',
'version' => $newVersion->id
]]
],
tools: [['type' => 'code_execution_20250825', 'name' => 'code_execution']]
);
echo $response;
// Use latest version
$latestResponse = $client->messages->create(
maxTokens: 4096,
messages: [['role' => 'user', 'content' => 'Use latest Skill version']],
model: 'claude-opus-5-5',
container: [
'skills' => [[
'type' => 'custom',
'skillID' => 'skill_01AbCdEfGhIjKlMnOpQrStUv',
'version' => 'latest'
]]
],
tools: [['type' => 'code_execution_20250825', 'name' => 'code_execution']]
);
echo $latestResponse;
client = Anthropic::Client.new
# Create a new version
new_version = client.skills.versions.create(
"skill_01AbCdEfGhIjKlMnOpQrStUv",
files: [
Anthropic::FilePart.new(
Pathname("financial_skill/SKILL.md"),
filename: "financial_skill/SKILL.md",
content_type: "text/markdown"
),
Anthropic::FilePart.new(
Pathname("financial_skill/analyze.py"),
filename: "financial_skill/analyze.py",
content_type: "text/x-python"
)
]
)
# Use specific version
response = client.messages.create(
model: "claude-opus-5-5",
max_tokens: 4096,
container: {
skills: [{
type: "custom",
skill_id: "skill_01AbCdEfGhIjKlMnOpQrStUv",
version: new_version.id
}]
},
messages: [{ role: "user", content: "Use updated Skill" }],
tools: [{ type: "code_execution_20250825", name: "code_execution" }]
)
puts response
# Use latest version
latest_response = client.messages.create(
model: "claude-opus-5-5",
max_tokens: 4096,
container: {
skills: [{
type: "custom",
skill_id: "skill_01AbCdEfGhIjKlMnOpQrStUv",
version: "latest"
}]
},
messages: [{ role: "user", content: "Use latest Skill version" }],
tools: [{ type: "code_execution_20250825", name: "code_execution" }]
)
puts latest_response
완전한 세부 사항은 스킬 버전 생성 API 레퍼런스를 참고하세요.
스킬이 로드되는 방식 (How Skills are loaded)
컨테이너에서 스킬을 지정하면:
- 메타데이터 발견: Claude는 각 스킬의 메타데이터(이름, 설명)를 시스템 프롬프트에서 봐요.
- 파일 로드: 스킬 파일이 컨테이너의
/skills/{skill-name}/로 복사돼요. 디렉터리는 스킬의 이름(Anthropic 스킬은pptx, 커스텀 스킬은SKILL.md의name)이지,skill_01...ID가 아니에요. - 자동 사용: Claude는 요청과 관련 있을 때 스킬을 자동으로 로드하고 사용해요.
- 구성: 여러 스킬이 복잡한 워크플로를 위해 함께 구성돼요.
Claude는 필요할 때만 전체 스킬 지시를 로드해요.
사용 사례 (Use cases)
스킬은 조직 작업과 개인 작업 모두에 맞아요. 조직은 문서에 브랜드 서식을 적용하고, 회사 템플릿에 맞춰 메모와 보고서를 구성하고, 회사별 분석 절차를 실행하는 데 사용해요. 개인은 커스텀 문서 템플릿, 전문화된 데이터 파이프라인, 코드 생성이나 배포 관례에 사용해요.
예시: 금융 모델링 (Example: financial modeling)
Excel 스킬과 커스텀 DCF 분석 스킬을 결합하세요. 먼저 커스텀 DCF 분석 스킬을 만듭니다:
ant apply dcf_skill
from anthropic.lib import files_from_dir
client = anthropic.Anthropic()
dcf_skill = client.skills.create(
files=files_from_dir("/path/to/dcf_skill"),
)
print(dcf_skill.id)
import Anthropic, { toFile } from "@anthropic-ai/sdk";
import fs from "node:fs";
const client = new Anthropic();
const dcfSkill = await client.skills.create({
files: [await toFile(fs.createReadStream("dcf_skill.zip"), "dcf_skill.zip")]
});
console.log(dcfSkill.id);
using Anthropic.Core;
// ...
AnthropicClient client = new();
var dcfSkill = await client.Skills.Create(new SkillCreateParams
{
Files =
[
new BinaryContent
{
Stream = File.OpenRead("dcf_skill/SKILL.md"),
FileName = "dcf_skill/SKILL.md",
},
],
});
Console.WriteLine(dcfSkill.ID);
client := anthropic.NewClient()
skillMd, err := os.Open("dcf_skill/SKILL.md")
if err != nil {
log.Fatal(err)
}
defer skillMd.Close()
dcfSkill, err := client.Skills.New(context.TODO(), anthropic.SkillNewParams{
Files: []io.Reader{
anthropic.File(skillMd, "dcf_skill/SKILL.md", "text/markdown"),
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(dcfSkill.ID)
import com.anthropic.core.MultipartField;
import com.anthropic.models.skills.SkillCreateParams;
import com.anthropic.models.skills.Skill;
// ...
void main() throws Exception {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
SkillCreateParams params = SkillCreateParams.builder()
.addFile(MultipartField.<InputStream>builder()
.value(Files.newInputStream(Path.of("dcf_skill/SKILL.md")))
.filename("dcf_skill/SKILL.md")
.contentType("text/markdown")
.build())
.build();
Skill dcfSkill = client.skills().create(params);
System.out.println(dcfSkill.id());
}
use Anthropic\Core\FileParam;
$client = new Client();
$dcfSkill = $client->skills->create(
files: [
FileParam::fromResource(
fopen('dcf_skill/SKILL.md', 'r'),
filename: 'dcf_skill/SKILL.md',
contentType: 'text/markdown',
),
],
);
echo "{$dcfSkill->id}\n";
client = Anthropic::Client.new
dcf_skill = client.skills.create(
files: [
Anthropic::FilePart.new(
Pathname("dcf_skill/SKILL.md"),
filename: "dcf_skill/SKILL.md",
content_type: "text/markdown"
)
]
)
puts dcf_skill.id
그런 다음 Excel 스킬과 함께 사용해 금융 모델을 만드세요. 만든 스킬의 ID를 커스텀 스킬의 skill_id로 전달하세요:
ant messages create <<'YAML'
model: claude-opus-5-5
max_tokens: 4096
container:
skills:
- type: anthropic
skill_id: xlsx
version: latest
- type: custom
skill_id: skill_01AbCdEfGhIjKlMnOpQrStUv
version: latest
messages:
- role: user
content: Build a DCF valuation model for a SaaS company
tools:
- type: code_execution_20250825
name: code_execution
YAML
client = anthropic.Anthropic()
# Custom DCF analysis Skill (ID obtained from Skills API create response)
dcf_skill_id = "skill_01AbCdEfGhIjKlMnOpQrStUv"
# Use with Excel to create financial model
response = client.messages.create(
model="claude-opus-5-5",
max_tokens=4096,
container={
"skills": [
{"type": "anthropic", "skill_id": "xlsx", "version": "latest"},
{"type": "custom", "skill_id": dcf_skill_id, "version": "latest"},
]
},
messages=[
{
"role": "user",
"content": "Build a DCF valuation model for a SaaS company",
}
],
tools=[{"type": "code_execution_20250825", "name": "code_execution"}],
)
print(response)
const client = new Anthropic();
// Custom DCF analysis Skill (ID obtained from Skills API create response)
const dcfSkillId = "skill_01AbCdEfGhIjKlMnOpQrStUv";
// Use with Excel to create financial model
const response = await client.messages.create({
model: "claude-opus-5-5",
max_tokens: 4096,
container: {
skills: [
{ type: "anthropic", skill_id: "xlsx", version: "latest" },
{ type: "custom", skill_id: dcfSkillId, version: "latest" }
]
},
messages: [
{
role: "user",
content: "Build a DCF valuation model for a SaaS company"
}
],
tools: [{ type: "code_execution_20250825", name: "code_execution" }]
});
console.log(response);
AnthropicClient client = new();
// Custom DCF analysis Skill (ID obtained from Skills API create response)
var dcfSkillId = "skill_01AbCdEfGhIjKlMnOpQrStUv";
// Use with Excel to create financial model
var parameters = new MessageCreateParams
{
Model = "claude-opus-5-5",
MaxTokens = 4096,
Container = new ContainerParams
{
Skills =
[
new SkillParams
{
Type = SkillParamsType.Anthropic,
SkillID = "xlsx",
Version = "latest",
},
new SkillParams
{
Type = SkillParamsType.Custom,
SkillID = dcfSkillId,
Version = "latest",
},
],
},
Messages = [new() { Role = Role.User, Content = "Build a DCF valuation model for a SaaS company" }],
Tools = [new CodeExecutionTool20250825()],
};
var message = await client.Messages.Create(parameters);
Console.WriteLine(message);
client := anthropic.NewClient()
// Custom DCF analysis Skill (ID obtained from Skills API create response)
dcfSkillID := "skill_01AbCdEfGhIjKlMnOpQrStUv"
// Use with Excel to create financial model
response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
Model: "claude-opus-5-5",
MaxTokens: 4096,
Container: anthropic.MessageCreateParamsContainerUnion{
OfContainers: &anthropic.ContainerParams{
Skills: []anthropic.SkillParams{
{
Type: anthropic.SkillParamsTypeAnthropic,
SkillID: "xlsx",
Version: anthropic.String("latest"),
},
{
Type: anthropic.SkillParamsTypeCustom,
SkillID: dcfSkillID,
Version: anthropic.String("latest"),
},
},
},
},
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("Build a DCF valuation model for a SaaS company")),
},
Tools: []anthropic.ToolUnionParam{
{OfCodeExecutionTool20250825: &anthropic.CodeExecutionTool20250825Param{}},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(response)
import com.anthropic.models.messages.ContainerParams;
import com.anthropic.models.messages.SkillParams;
import com.anthropic.models.messages.CodeExecutionTool20250825;
// ...
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
// Custom DCF analysis Skill (ID obtained from Skills API create response)
String dcfSkillId = "skill_01AbCdEfGhIjKlMnOpQrStUv";
// Use with Excel Skill to create financial model
MessageCreateParams params = MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_5_5)
.maxTokens(4096L)
.container(ContainerParams.builder()
.skills(List.of(
SkillParams.builder()
.type(SkillParams.Type.ANTHROPIC)
.skillId("xlsx")
.version("latest")
.build(),
SkillParams.builder()
.type(SkillParams.Type.CUSTOM)
.skillId(dcfSkillId)
.version("latest")
.build()
))
.build())
.addUserMessage("Build a DCF valuation model for a SaaS company")
.addTool(CodeExecutionTool20250825.builder().build())
.build();
Message response = client.messages().create(params);
System.out.println(response);
}
$client = new Client();
// Custom DCF analysis Skill (ID obtained from Skills API create response)
$dcfSkillId = 'skill_01AbCdEfGhIjKlMnOpQrStUv';
// Use with Excel to create financial model
$message = $client->messages->create(
maxTokens: 4096,
messages: [
['role' => 'user', 'content' => 'Build a DCF valuation model for a SaaS company']
],
model: 'claude-opus-5-5',
container: [
'skills' => [
['type' => 'anthropic', 'skillID' => 'xlsx', 'version' => 'latest'],
['type' => 'custom', 'skillID' => $dcfSkillId, 'version' => 'latest']
]
],
tools: [
['type' => 'code_execution_20250825', 'name' => 'code_execution']
]
);
echo $message;
client = Anthropic::Client.new
# Custom DCF analysis Skill (ID obtained from Skills API create response)
dcf_skill_id = "skill_01AbCdEfGhIjKlMnOpQrStUv"
# Use with Excel to create financial model
response = client.messages.create(
model: "claude-opus-5-5",
max_tokens: 4096,
container: {
skills: [
{ type: "anthropic", skill_id: "xlsx", version: "latest" },
{ type: "custom", skill_id: dcf_skill_id, version: "latest" }
]
},
messages: [
{ role: "user", content: "Build a DCF valuation model for a SaaS company" }
],
tools: [{ type: "code_execution_20250825", name: "code_execution" }]
)
puts response
한계와 제약 (Limits and constraints)
요청 한계 (Request limits)
-
요청당 최대 스킬 수: 20
-
최대 스킬 업로드 크기: 30 MB(모든 파일 합산, 압축 전)
-
YAML frontmatter 요구사항:
name: 최대 64자, 소문자/숫자/하이픈만, XML 태그 없음, 예약어 없음("anthropic", "claude")description: 최대 1024자, 비어 있지 않음, XML 태그 없음
환경 제약 (Environment constraints)
스킬은 코드 실행 컨테이너에서 다음 제한과 함께 실행돼요:
- 네트워크 접근 없음: 외부 API 호출 불가
- 런타임 패키지 설치 없음: 미리 설치된 패키지만 사용 가능
- 격리된 환경: 기존 컨테이너 ID를 지정하지 않으면 새 컨테이너가 생성됨
사용 가능한 패키지는 코드 실행 도구를 참고하세요.
모범 사례 (Best practices)
여러 스킬을 사용해야 할 때 (When to use multiple Skills)
과제가 여러 문서 유형이나 도메인을 포함할 때 스킬을 결합하세요:
좋은 사용 사례:
- 데이터 분석(Excel) + 프레젠테이션 생성(PowerPoint)
- 보고서 생성(Word) + PDF로 내보내기
- 커스텀 도메인 로직 + 문서 생성
피하세요:
- 사용하지 않는 스킬 포함(성능에 영향)
버전 관리 전략 (Version management strategy)
이 섹션의 SDK 탭은 Messages 요청에 포함할 container 값을 보여줘요. cURL과 CLI 탭은 전체 요청을 보여줍니다.
프로덕션용: 특정 버전을 고정해서, 스킬 업데이트가 배포된 동작을 절대 바꾸지 않게 하세요. version을 생략하거나 "latest"를 설정하면 요청이 스킬의 최신 버전을 사용하므로, 워크스페이스의 누군가가 업로드한 버전이 즉시 프로덕션 에이전트가 실행하는 것을 바꿔요. 버전 ID는 버전 관리의 버전 생성 응답이나 스킬 버전 목록 API에서 옵니다. ID는 항상 문자열이므로, 숫자처럼 보여도 JSON이나 YAML에서 따옴표로 감싸세요.
# Pin to specific versions for stability
ant messages create <<YAML
model: claude-opus-5-5
max_tokens: 4096
container:
skills:
- type: custom
skill_id: skill_01AbCdEfGhIjKlMnOpQrStUv
version: "skver_01AbCdEfGhIjKlMnOpQrStUv"
messages:
- role: user
content: Analyze the sales data
tools:
- type: code_execution_20250825
name: code_execution
YAML
# Pin to specific versions for stability
container = {
"skills": [
{
"type": "custom",
"skill_id": "skill_01AbCdEfGhIjKlMnOpQrStUv",
"version": "skver_01AbCdEfGhIjKlMnOpQrStUv",
}
]
}
// Pin to specific versions for stability
const container: Anthropic.ContainerParams = {
skills: [
{
type: "custom",
skill_id: "skill_01AbCdEfGhIjKlMnOpQrStUv",
version: "skver_01AbCdEfGhIjKlMnOpQrStUv"
}
]
};
using Anthropic.Models.Messages;
// Pin to specific versions for stability
var container = new ContainerParams
{
Skills =
[
new SkillParams
{
Type = SkillParamsType.Custom,
SkillID = "skill_01AbCdEfGhIjKlMnOpQrStUv",
Version = "skver_01AbCdEfGhIjKlMnOpQrStUv",
},
],
};
// Pin to specific versions for stability
container := anthropic.MessageCreateParamsContainerUnion{
OfContainers: &anthropic.ContainerParams{
Skills: []anthropic.SkillParams{
{
Type: anthropic.SkillParamsTypeCustom,
SkillID: "skill_01AbCdEfGhIjKlMnOpQrStUv",
Version: anthropic.String("skver_01AbCdEfGhIjKlMnOpQrStUv"),
},
},
},
}
import com.anthropic.models.messages.ContainerParams;
import com.anthropic.models.messages.SkillParams;
void main() {
// Pin to specific versions for stability
ContainerParams container = ContainerParams.builder()
.addSkill(SkillParams.builder()
.type(SkillParams.Type.CUSTOM)
.skillId("skill_01AbCdEfGhIjKlMnOpQrStUv")
.version("skver_01AbCdEfGhIjKlMnOpQrStUv")
.build())
.build();
}
// Pin to specific versions for stability
$container = [
'skills' => [[
'type' => 'custom',
'skillID' => 'skill_01AbCdEfGhIjKlMnOpQrStUv',
'version' => 'skver_01AbCdEfGhIjKlMnOpQrStUv'
]]
];
# Pin to specific versions for stability
container = {
skills: [{
type: "custom",
skill_id: "skill_01AbCdEfGhIjKlMnOpQrStUv",
version: "skver_01AbCdEfGhIjKlMnOpQrStUv"
}]
}
개발용: 반복하며 최신 버전을 자동으로 받으려면 latest를 사용하세요.
# Use latest for active development
ant messages create <<YAML
model: claude-opus-5-5
max_tokens: 4096
container:
skills:
- type: custom
skill_id: skill_01AbCdEfGhIjKlMnOpQrStUv
version: latest
messages:
- role: user
content: Analyze the sales data
tools:
- type: code_execution_20250825
name: code_execution
YAML
# Use latest for active development
container = {
"skills": [
{
"type": "custom",
"skill_id": "skill_01AbCdEfGhIjKlMnOpQrStUv",
"version": "latest",
}
]
}
// Use latest for active development
const container: Anthropic.ContainerParams = {
skills: [
{
type: "custom",
skill_id: "skill_01AbCdEfGhIjKlMnOpQrStUv",
version: "latest"
}
]
};
using Anthropic.Models.Messages;
// Use latest for active development
var container = new ContainerParams
{
Skills =
[
new SkillParams
{
Type = SkillParamsType.Custom,
SkillID = "skill_01AbCdEfGhIjKlMnOpQrStUv",
Version = "latest",
},
],
};
// Use latest for active development
container := anthropic.MessageCreateParamsContainerUnion{
OfContainers: &anthropic.ContainerParams{
Skills: []anthropic.SkillParams{
{
Type: anthropic.SkillParamsTypeCustom,
SkillID: "skill_01AbCdEfGhIjKlMnOpQrStUv",
Version: anthropic.String("latest"),
},
},
},
}
import com.anthropic.models.messages.ContainerParams;
import com.anthropic.models.messages.SkillParams;
void main() {
// Use latest for active development
ContainerParams container = ContainerParams.builder()
.addSkill(SkillParams.builder()
.type(SkillParams.Type.CUSTOM)
.skillId("skill_01AbCdEfGhIjKlMnOpQrStUv")
.version("latest")
.build())
.build();
}
// Use latest for active development
$container = [
'skills' => [[
'type' => 'custom',
'skillID' => 'skill_01AbCdEfGhIjKlMnOpQrStUv',
'version' => 'latest'
]]
];
# Use latest for active development
container = {
skills: [{
type: "custom",
skill_id: "skill_01AbCdEfGhIjKlMnOpQrStUv",
version: "latest"
}]
}
프롬프트 캐싱 고려사항 (Prompt caching considerations)
프롬프트 캐싱을 사용한다면 컨테이너의 스킬 목록을 바꾸는 것은 캐시를 깨요. 스킬은 고정된 순서로 시스템 프롬프트에 렌더링되므로, 같은 목록은 같은 캐시 가능 접두사를 만들어요:
Changing the Skills list ([xlsx] vs [xlsx, pptx]) changes the prefix: a cache miss, while an identical list is a cache hit
curl https://api.anthropic.com/v1/messages
-H "x-api-key: $ANTHR...KEY"
-H "anthropic-version: 2023-06-01"
-H "content-type: application/json"
-d '{
"model": "claude-opus-5-5",
"max_tokens": 4096,
"container": {
"skills": [
{"type": "anthropic", "skill_id": "xlsx", "version": "latest"},
{"type": "anthropic", "skill_id": "pptx", "version": "latest"}
]
},
"messages": [{"role": "user", "content": "Create a presentation"}],
"tools": [{"type": "code_execution_20250825", "name": "code_execution"}]
}'
```bash CLI
# Skills render into the system prompt in a fixed, cache-friendly order
ant messages create <<'YAML'
model: claude-opus-5-5
max_tokens: 4096
container:
skills:
- type: anthropic
skill_id: xlsx
version: latest
messages:
- role: user
content: Analyze sales data
tools:
- type: code_execution_20250825
name: code_execution
YAML
# Changing the Skills list ([xlsx] vs [xlsx, pptx]) changes the prefix: a cache miss, while an identical list is a cache hit
ant messages create <<'YAML'
model: claude-opus-5-5
max_tokens: 4096
container:
skills:
- type: anthropic
skill_id: xlsx
version: latest
- type: anthropic
skill_id: pptx
version: latest
messages:
- role: user
content: Create a presentation
tools:
- type: code_execution_20250825
name: code_execution
YAML
client = anthropic.Anthropic()
# Skills render into the system prompt in a fixed, cache-friendly order
response1 = client.messages.create(
model="claude-opus-5-5",
max_tokens=4096,
container={
"skills": [{"type": "anthropic", "skill_id": "xlsx", "version": "latest"}]
},
messages=[{"role": "user", "content": "Analyze sales data"}],
tools=[{"type": "code_execution_20250825", "name": "code_execution"}],
)
# Changing the Skills list ([xlsx] vs [xlsx, pptx]) changes the prefix: a cache miss, while an identical list is a cache hit
response2 = client.messages.create(
model="claude-opus-5-5",
max_tokens=4096,
container={
"skills": [
{"type": "anthropic", "skill_id": "xlsx", "version": "latest"},
{
"type": "anthropic",
"skill_id": "pptx",
"version": "latest",
}, # prefix change: cache miss
]
},
messages=[{"role": "user", "content": "Create a presentation"}],
tools=[{"type": "code_execution_20250825", "name": "code_execution"}],
)
const client = new Anthropic();
// Skills render into the system prompt in a fixed, cache-friendly order
const response1 = await client.messages.create({
model: "claude-opus-5-5",
max_tokens: 4096,
container: {
skills: [{ type: "anthropic", skill_id: "xlsx", version: "latest" }]
},
messages: [{ role: "user", content: "Analyze sales data" }],
tools: [{ type: "code_execution_20250825", name: "code_execution" }]
});
// Changing the Skills list ([xlsx] vs [xlsx, pptx]) changes the prefix: a cache miss, while an identical list is a cache hit
const response2 = await client.messages.create({
model: "claude-opus-5-5",
max_tokens: 4096,
container: {
skills: [
{ type: "anthropic", skill_id: "xlsx", version: "latest" },
{ type: "anthropic", skill_id: "pptx", version: "latest" } // prefix change: cache miss
]
},
messages: [{ role: "user", content: "Create a presentation" }],
tools: [{ type: "code_execution_20250825", name: "code_execution" }]
});
AnthropicClient client = new();
// Skills render into the system prompt in a fixed, cache-friendly order
var parameters1 = new MessageCreateParams
{
Model = "claude-opus-5-5",
MaxTokens = 4096,
Container = new ContainerParams
{
Skills =
[
new SkillParams
{
Type = SkillParamsType.Anthropic,
SkillID = "xlsx",
Version = "latest",
},
],
},
Messages = [new() { Role = Role.User, Content = "Analyze sales data" }],
Tools = [new CodeExecutionTool20250825()],
};
var response1 = await client.Messages.Create(parameters1);
Console.WriteLine(response1);
// Different Skill set ([xlsx] vs [xlsx, pptx]) = a different prefix: a cache miss (an identical set is a cache hit)
var parameters2 = new MessageCreateParams
{
Model = "claude-opus-5-5",
MaxTokens = 4096,
Container = new ContainerParams
{
Skills =
[
new SkillParams
{
Type = SkillParamsType.Anthropic,
SkillID = "xlsx",
Version = "latest",
},
new SkillParams
{
Type = SkillParamsType.Anthropic,
SkillID = "pptx",
Version = "latest",
},
],
},
Messages = [new() { Role = Role.User, Content = "Create a presentation" }],
Tools = [new CodeExecutionTool20250825()],
};
var response2 = await client.Messages.Create(parameters2);
Console.WriteLine(response2);
client := anthropic.NewClient()
// Skills render into the system prompt in a fixed, cache-friendly order
response1, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
Model: "claude-opus-5-5",
MaxTokens: 4096,
Container: anthropic.MessageCreateParamsContainerUnion{
OfContainers: &anthropic.ContainerParams{
Skills: []anthropic.SkillParams{
{
Type: anthropic.SkillParamsTypeAnthropic,
SkillID: "xlsx",
Version: anthropic.String("latest"),
},
},
},
},
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("Analyze sales data")),
},
Tools: []anthropic.ToolUnionParam{
{OfCodeExecutionTool20250825: &anthropic.CodeExecutionTool20250825Param{}},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(response1)
// Changing the Skills list ([xlsx] vs [xlsx, pptx]) changes the prefix: a cache miss, while an identical list is a cache hit
response2, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
Model: "claude-opus-5-5",
MaxTokens: 4096,
Container: anthropic.MessageCreateParamsContainerUnion{
OfContainers: &anthropic.ContainerParams{
Skills: []anthropic.SkillParams{
{
Type: anthropic.SkillParamsTypeAnthropic,
SkillID: "xlsx",
Version: anthropic.String("latest"),
},
{
Type: anthropic.SkillParamsTypeAnthropic,
SkillID: "pptx",
Version: anthropic.String("latest"),
},
},
},
},
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("Create a presentation")),
},
Tools: []anthropic.ToolUnionParam{
{OfCodeExecutionTool20250825: &anthropic.CodeExecutionTool20250825Param{}},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(response2)
import com.anthropic.models.messages.ContainerParams;
import com.anthropic.models.messages.SkillParams;
import com.anthropic.models.messages.CodeExecutionTool20250825;
// ...
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
// Skills render into the system prompt in a fixed, cache-friendly order
MessageCreateParams params1 = MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_5_5)
.maxTokens(4096L)
.container(ContainerParams.builder()
.skills(List.of(
SkillParams.builder()
.type(SkillParams.Type.ANTHROPIC)
.skillId("xlsx")
.version("latest")
.build()
))
.build())
.addUserMessage("Analyze sales data")
.addTool(CodeExecutionTool20250825.builder().build())
.build();
Message response1 = client.messages().create(params1);
System.out.println(response1);
// Changing the Skills list ([xlsx] vs [xlsx, pptx]) changes the prefix: a cache miss, while an identical list is a cache hit
MessageCreateParams params2 = MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_5_5)
.maxTokens(4096L)
.container(ContainerParams.builder()
.skills(List.of(
SkillParams.builder()
.type(SkillParams.Type.ANTHROPIC)
.skillId("xlsx")
.version("latest")
.build(),
SkillParams.builder()
.type(SkillParams.Type.ANTHROPIC)
.skillId("pptx")
.version("latest")
.build()
))
.build())
.addUserMessage("Create a presentation")
.addTool(CodeExecutionTool20250825.builder().build())
.build();
Message response2 = client.messages().create(params2);
System.out.println(response2);
}
$client = new Client();
// Skills render into the system prompt in a fixed, cache-friendly order
$response1 = $client->messages->create(
maxTokens: 4096,
messages: [
['role' => 'user', 'content' => 'Analyze sales data']
],
model: 'claude-opus-5-5',
container: [
'skills' => [
['type' => 'anthropic', 'skillID' => 'xlsx', 'version' => 'latest']
]
],
tools: [
['type' => 'code_execution_20250825', 'name' => 'code_execution']
]
);
echo $response1;
// Changing the Skills list ([xlsx] vs [xlsx, pptx]) changes the prefix: a cache miss, while an identical list is a cache hit
$response2 = $client->messages->create(
maxTokens: 4096,
messages: [
['role' => 'user', 'content' => 'Create a presentation']
],
model: 'claude-opus-5-5',
container: [
'skills' => [
['type' => 'anthropic', 'skillID' => 'xlsx', 'version' => 'latest'],
['type' => 'anthropic', 'skillID' => 'pptx', 'version' => 'latest']
]
],
tools: [
['type' => 'code_execution_20250825', 'name' => 'code_execution']
]
);
echo $response2;
client = Anthropic::Client.new
# Skills render into the system prompt in a fixed, cache-friendly order
response1 = client.messages.create(
model: "claude-opus-5-5",
max_tokens: 4096,
container: {
skills: [{ type: "anthropic", skill_id: "xlsx", version: "latest" }]
},
messages: [{ role: "user", content: "Analyze sales data" }],
tools: [{ type: "code_execution_20250825", name: "code_execution" }]
)
puts response1
# Changing the Skills list ([xlsx] vs [xlsx, pptx]) changes the prefix: a cache miss, while an identical list is a cache hit
response2 = client.messages.create(
model: "claude-opus-5-5",
max_tokens: 4096,
container: {
skills: [
{ type: "anthropic", skill_id: "xlsx", version: "latest" },
{ type: "anthropic", skill_id: "pptx", version: "latest" } # prefix change: cache miss
]
},
messages: [{ role: "user", content: "Create a presentation" }],
tools: [{ type: "code_execution_20250825", name: "code_execution" }]
)
puts response2
최상의 캐싱 성능을 위해, 스킬 목록(순서 포함)을 요청 간 일관되게 유지하세요. 커스텀 스킬 버전을 고정하는 것도 도움이 돼요. "latest"로는 새 버전을 게시하면 스킬 설명이 바뀌어 캐시된 접두사를 무효화할 수 있으니까요.
오류 처리 (Error handling)
스킬 관련 오류를 우아하게 처리하세요:
if ! RESULT=$(ant messages create \
--transform-error error.message \
--format-error yaml 2>&1 <<'YAML'
model: claude-opus-5-5
max_tokens: 4096
container:
skills:
- type: custom
skill_id: skill_01AbCdEfGhIjKlMnOpQrStUv
version: latest
messages:
- role: user
content: Process data
tools:
- type: code_execution_20250825
name: code_execution
YAML
); then
case "$RESULT" in
*skill*)
printf 'Skill error: %s\n' "$RESULT"
# Handle skill-specific errors
;;
*)
printf '%s\n' "$RESULT" >&2
exit 1
;;
esac
fi
client = anthropic.Anthropic()
try:
response = client.messages.create(
model="claude-opus-5-5",
max_tokens=4096,
container={
"skills": [
{
"type": "custom",
"skill_id": "skill_01AbCdEfGhIjKlMnOpQrStUv",
"version": "latest",
}
]
},
messages=[{"role": "user", "content": "Process data"}],
tools=[{"type": "code_execution_20250825", "name": "code_execution"}],
)
except anthropic.BadRequestError as e:
if "skill" in str(e):
print(f"Skill error: {e}")
# Handle skill-specific errors
else:
raise
const client = new Anthropic();
try {
const response = await client.messages.create({
model: "claude-opus-5-5",
max_tokens: 4096,
container: {
skills: [
{ type: "custom", skill_id: "skill_01AbCdEfGhIjKlMnOpQrStUv", version: "latest" }
]
},
messages: [{ role: "user", content: "Process data" }],
tools: [{ type: "code_execution_20250825", name: "code_execution" }]
});
console.log(response);
} catch (error) {
if (error instanceof Anthropic.BadRequestError && error.message.includes("skill")) {
console.error(`Skill error: ${error.message}`);
// Handle skill-specific errors
} else {
throw error;
}
}
using Anthropic.Exceptions;
// ...
AnthropicClient client = new();
try
{
var parameters = new MessageCreateParams
{
Model = "claude-opus-5-5",
MaxTokens = 4096,
Container = new ContainerParams
{
Skills =
[
new SkillParams
{
Type = SkillParamsType.Custom,
SkillID = "skill_01AbCdEfGhIjKlMnOpQrStUv",
Version = "latest",
},
],
},
Messages = [new() { Role = Role.User, Content = "Process data" }],
Tools = [new CodeExecutionTool20250825()],
};
var response = await client.Messages.Create(parameters);
Console.WriteLine(response);
}
catch (AnthropicBadRequestException e) when (e.Message.Contains("skill"))
{
Console.WriteLine($"Skill error: {e.Message}");
}
client := anthropic.NewClient()
response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
Model: "claude-opus-5-5",
MaxTokens: 4096,
Container: anthropic.MessageCreateParamsContainerUnion{
OfContainers: &anthropic.ContainerParams{
Skills: []anthropic.SkillParams{
{
Type: anthropic.SkillParamsTypeCustom,
SkillID: "skill_01AbCdEfGhIjKlMnOpQrStUv",
Version: anthropic.String("latest"),
},
},
},
},
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("Process data")),
},
Tools: []anthropic.ToolUnionParam{
{OfCodeExecutionTool20250825: &anthropic.CodeExecutionTool20250825Param{}},
},
})
if err != nil {
var apierr *anthropic.Error
if errors.As(err, &apierr) && apierr.Type() == anthropic.ErrorTypeInvalidRequestError &&
strings.Contains(apierr.Error(), "skill") {
fmt.Printf("Skill error: %v\n", apierr)
} else {
log.Fatal(err)
}
return
}
fmt.Println(response)
import com.anthropic.errors.BadRequestException;
import com.anthropic.models.messages.ContainerParams;
import com.anthropic.models.messages.SkillParams;
import com.anthropic.models.messages.CodeExecutionTool20250825;
// ...
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
try {
MessageCreateParams params = MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_5_5)
.maxTokens(4096L)
.container(ContainerParams.builder()
.addSkill(SkillParams.builder()
.type(SkillParams.Type.CUSTOM)
.skillId("skill_01AbCdEfGhIjKlMnOpQrStUv")
.version("latest")
.build())
.build())
.addUserMessage("Process data")
.addTool(CodeExecutionTool20250825.builder().build())
.build();
Message response = client.messages().create(params);
System.out.println(response);
} catch (BadRequestException e) {
if (e.getMessage().contains("skill")) {
System.err.println("Skill error: " + e.getMessage());
} else {
throw e;
}
}
}
use Anthropic\Core\Exceptions\BadRequestException;
$client = new Client();
try {
$message = $client->messages->create(
maxTokens: 4096,
messages: [
['role' => 'user', 'content' => 'Process data']
],
model: 'claude-opus-5-5',
container: [
'skills' => [
[
'type' => 'custom',
'skillID' => 'skill_01AbCdEfGhIjKlMnOpQrStUv',
'version' => 'latest'
]
]
],
tools: [
['type' => 'code_execution_20250825', 'name' => 'code_execution']
]
);
echo $message;
} catch (BadRequestException $e) {
if (str_contains($e->getMessage(), 'skill')) {
echo "Skill error: " . $e->getMessage();
} else {
throw $e;
}
}
client = Anthropic::Client.new
begin
response = client.messages.create(
model: "claude-opus-5-5",
max_tokens: 4096,
container: {
skills: [
{
type: "custom",
skill_id: "skill_01AbCdEfGhIjKlMnOpQrStUv",
version: "latest"
}
]
},
messages: [{ role: "user", content: "Process data" }],
tools: [{ type: "code_execution_20250825", name: "code_execution" }]
)
rescue Anthropic::Errors::BadRequestError => e
if e.message.include?("skill")
puts "Skill error: #{e.message}"
else
raise
end
end
skills-2025-10-02에서 마이그레이션하기 (Migrate from skills-2025-10-02)
Skills API는 베타를 벗어났고 베타 헤더가 필요 없어요. skills-2025-10-02에서 벗어나는 것은 선택 사항이에요. 그것을 계속 보내는 요청은 동작을 유지하고 베타 응답 형태를 계속 반환하므로, 기존 통합은 바꿀 때까지 계속 동작해요. 헤더를 제거하면 그 요청들이 이 페이지에 문서화된 형태로 전환돼요:
skills-2025-10-02 사용 시 |
헤더 없음 | |
|---|---|---|
| 스킬 레이블 | display_title(최대 64자, 워크스페이스별 고유) |
display_name(최대 255자, 고유하지 않음); 생략 시 SKILL.md의 name에서 파생 |
| 최신 버전 포인터 | latest_version, epoch-마이크로초 문자열(예: "1759178010641129") |
latest_version_id, 버전 ID(예: "skver_01AbCdEfGhIjKlMnOpQrStUv"); GET /v1/skills/{skill_id}/versions/latest가 한 번에 해결 |
| URL의 버전 식별자 | epoch-마이크로초 문자열 | 버전 ID(skver_...). 베타 아래 skill_version_ 접두사로 포착된 ID는 입력으로 받아들여짐 |
| 버전 객체 | directory 포함(항상 스킬 name과 동일) |
directory 필드 없음 |
source |
문자열, "custom" 또는 "anthropic" |
객체, 예: {"type": "custom"}; 예시 카탈로그 값은 "anthropic_example" |
| 목록 응답 | { data, has_more, next_page } |
{ data, next_page }; limit 1~1,000(기본 20) |
| 버전 목록 순서 | 오래된 것 먼저 | 최신 것 먼저, 기본 limit 20. 한 형태의 페이지 커서는 다른 형태에서 유효하지 않음 |
| 스킬 삭제 | 어떤 버전이 존재하면 400 오류 반환 | 스킬과 모든 버전 삭제 |
| 스킬 유일 버전 삭제 | 허용, 버전 없는 스킬이 남음 | 400 오류 반환; 대체 버전을 먼저 업로드하거나 스킬 삭제 |
| 업로드 레이아웃 | 파일이 스킬 name과 일치하는 최상위 디렉터리 안에 있어야 함 |
SKILL.md가 업로드 루트에 놓일 수 있음; 저장 경로는 어느 쪽이든 동일 |
| 응답 유형 | CreateSkillResponse, GetSkillResponse, 작업별 하나 |
Skill, SkillVersion, DeletedSkill, DeletedSkillVersion |
마이그레이션하려면:
- 베타 헤더를 제거하세요. 요청에서
anthropic-beta: skills-2025-10-02를 빼세요. SDK에서client.beta.skills대신client.skills를 호출하세요.client.beta.skills를 유지하는 것은 더 이상 헤더를 보내지 않는 SDK 릴리스에서만 동작해요. 이전 릴리스는betas인자가 없어도client.beta.skills에서 헤더를 보내요. - 코드의 필드를 이름 바꾸세요:
display_title을display_name으로,latest_version을latest_version_id로, 그리고source를 문자열과 비교하는 대신source.type을 읽으세요. - 버전 ID를 사용하세요. epoch-마이크로초 버전을 저장한 곳마다 버전의
id를 저장하거나latest를 사용하세요. Messages 요청의 스킬 참조는 버전 ID,latest, 또는(Anthropic 스킬의 경우) 카탈로그 버전을 받아들여요. - 삭제 호출을 검토하세요.
DELETE /v1/skills/{skill_id}가 이제 스킬과 함께 모든 버전을 제거해요. 베타의 거부를 안전장치로 의존했다면 자체 확인을 추가하세요.
베타 아래에서 모든 버전이 삭제된 스킬은 반환할 현재 버전이 없어요. GET /v1/skills/{skill_id}가 400 오류를 반환하고 그 스킬은 버전을 업로드할 때까지 목록 응답에서 생략돼요. 그래도 삭제할 수는 있어요.
SDK 베타 네임스페이스 (SDK beta namespace)
Python SDK 1.2.0, TypeScript SDK 0.122.0, Go SDK 1.68.0, Java SDK 2.59.0, Ruby SDK 1.67.0, C# SDK 12.44.0부터 client.beta.skills는 더 이상 skills-2025-10-02를 보내지 않고, Beta 접두사 타입 이름(BetaSkill, BetaSkillVersion, BetaDeletedSkill, BetaDeletedSkillVersion)으로 client.skills와 같은 형태를 반환해요. 여전히 베타인 스킬 기능을 위해 betas 인자를 받아들여요. 베타 Messages 타입에서는 컨테이너 스킬 참조 타입이 BetaSkill에서 BetaContainerSkill로 이름이 바뀌었어요(같은 필드: type, skill_id, version). BetaSkill은 이제 비베타 타입의 Skill과 ContainerSkill에 맞춰 스킬 리소스를 이름 지어요. 이전 SDK 릴리스는 베타 형태로 타이핑돼요. 그 타입에 의존한다면 마이그레이션할 때까지 이전 릴리스에 머무르세요.
데이터 보관 (Data retention)
에이전트 스킬은 ZDR 계약으로 다뤄지지 않아요. 스킬 정의와 실행 데이터는 Anthropic의 표준 데이터 보관 정책에 따라 유지돼요.
모든 기능의 ZDR 자격에 대해서는 API와 데이터 보관을 참고하세요.
감사 로깅 (Audit logging)
조직에 Compliance API가 활성화되어 있으면 그 활동 피드가 Claude API 키나 Claude 콘솔에서 이루어진 스킬과 스킬 버전의 생성·삭제를 기록해요. Compliance API가 꺼져 있는 동안 일어난 작업은 기록되지 않고 나중에 복구할 수 없으므로, 이 감사 추적에 의존하기 전에 Compliance API를 설정하세요.