Claude API에서 에이전트 스킬 사용하기

Claude API에서 에이전트 스킬 사용하기 (Using Agent Skills with the API)

스킬(Agent Skills)은 정리된 폴더의 지시·스크립트·리소스를 통해 Claude의 능력을 확장해요. 이 문서는 Claude API에서 미리 만들어진 스킬과 커스텀 스킬을 모두 사용하는 방법을 소개해 드릴게요. 스킬은 코드 실행 컨테이너 안에서 동작해 문서(엑셀, 파워포인트, PDF, 워드)를 만들고 데이터를 분석하는 데 유용하답니다.

출처: 문서

본문

에이전트 스킬은 정리된 폴더의 지시·스크립트·리소스를 통해 Claude의 능력을 확장해요. 이 문서는 Claude API에서 미리 만들어진 스킬과 커스텀 스킬을 모두 사용하는 방법을 보여줘요.

요청/응답 스키마와 모든 파라미터를 포함한 완전한 API 레퍼런스는 다음을 참고하세요. 이 기능에 ZDR(zero data retention, 데이터 미보관)가 어떻게 적용되는지 알아보려면 [API와 데이터 보관](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention)을 참고하세요. Claude API로 10분 안에 문서를 만들기 위해 에이전트 스킬을 사용하는 방법 배우기. Claude가 발견하고 성공적으로 사용할 수 있는 효과적인 스킬을 쓰는 방법 배우기.

개요 (Overview)

에이전트 스킬의 아키텍처와 실제 적용에 대한 자세한 내용은 엔지니어링 블로그 글 [에이전트 스킬로 실제 세계를 위한 에이전트 갖추기](https://www.anthropic.com/engineering/equipping-agents-for-the-real-world-with-agent-skills)를 읽어보세요.

스킬은 코드 실행 도구를 통해 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)

스킬을 사용하려면 다음이 필요해요:

  1. Claude 콘솔Claude API 키
  2. 요청에서 활성화된 코드 실행 도구

스킬은 코드 실행 도구가 필요하므로, 그 모델 호환성 목록의 모델을 사용하세요.


Messages에서 스킬 사용하기 (Using Skills in Messages)

Container 파라미터 (Container parameter)

스킬은 Messages API의 container 파라미터로 지정돼요. 요청당 최대 20개의 스킬을 포함할 수 있어요.

구조는 Anthropic과 커스텀 스킬 모두 동일해요. 필수 typeskill_id를 지정하고, 특정 버전에 고정하려면 선택적으로 version을 포함하세요:

```bash cURL 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": "pptx", "version": "latest" } ] }, "messages": [{ "role": "user", "content": "Create a presentation about renewable energy" }], "tools": [{ "type": "code_execution_20250825", "name": "code_execution" }] }' ```
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를 사용해야 해요.

동작 방식:

  1. 스킬이 코드 실행 중에 파일을 만들어요.
  2. 응답이 각 생성된 파일의 file_id를 코드 실행 도구 결과 블록 안에 포함해요(응답 형식 참조).
  3. Files API로 실제 파일 콘텐츠를 다운로드해요.
  4. 로컬에 저장하거나 필요에 따라 처리해요.

스킬이 작업할 입력 파일을 제공하려면 Files API로 업로드하고 컨테이너 업로드 블록으로 요청에서 참조하세요.

예시: Excel 파일 만들고 다운로드하기

```bash cURL # Step 1: Use a Skill to create a file 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": { "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_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 작업:

```bash cURL # Get file metadata curl "https://api.anthropic.com/v1/files/$FILE_ID" \ -H "x-api-key: $ANTHR...KEY" \ -H "anthropic-version: 2023-06-01"

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)
완전한 세부사항은 [Files API](https://platform.claude.com/docs/en/build-with-claude/files)를 참고하세요.

멀티턴 대화 (Multi-turn conversations)

응답의 container 객체가 컨테이너의 idexpires_at 타임스탬프를 지녀요(컨테이너 재사용에서 수명 세부사항 참조). 컨테이너 ID를 지정해 여러 메시지에서 같은 컨테이너를 재사용하세요:

```bash cURL # Multi-turn container reuse doesn't translate well to a one-off shell # command; one of the SDK options would be a better fit. Capture # container.id from the first response, then pass it in the next request as # "container": {"id": "...", "skills": [...]} with the conversation history. ```
# 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 중지 이유를 처리하세요:

```bash cURL # Initial request 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": { "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" }] }')

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
응답에 `pause_turn` 중지 이유가 포함될 수 있는데, 이는 API가 장기 실행 스킬 작업을 일시 중지했음을 나타내요. 후속 요청에서 응답을 그대로 다시 제공해 Claude가 턴을 계속하게 하거나, 대화를 중단하고 추가 안내를 제공하려면 콘텐츠를 수정할 수 있어요.

여러 스킬 사용하기 (Using multiple Skills)

복잡한 워크플로를 처리하기 위해 단일 요청에서 여러 스킬을 결합하세요:

```bash cURL 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" }, { "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" }] }' ```
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)

**커스텀 스킬은 엔드 사용자, 대화, 세션으로 한정되지 않고 워크스페이스 전체에 접근 가능해요.** 워크스페이스에 접근할 수 있는 모든 API 키가 그 워크스페이스에 업로드된 모든 커스텀 스킬을 읽고, 호출하고, 삭제할 수 있어요. 모든 서비스 계정과 조직 역할이 API 접근을 허용하는 모든 사용자는 사용자가 추가한 어떤 워크스페이스와 더불어 기본 워크스페이스도 사용할 수 있으므로, 반드시 분리되어야 하는 스킬은 자기 [워크스페이스](https://platform.claude.com/docs/en/manage-claude/workspaces#api-keys-and-resource-scoping)에 두고 그 워크스페이스로 한정된 키로만 접근하세요.

Skills API에 멀티테넌트 플랫폼을 구축한다면 각 테넌트에 별도 워크스페이스를 만드세요. 워크스페이스는 커스텀 스킬의 격리 경계이므로, 테넌트당 워크스페이스 하나가 각 테넌트의 스킬을 다른 모든 테넌트로부터 강하게 격리해요. 각 조직은 기본적으로 최대 100개의 워크스페이스를 가질 수 있어요(워크스페이스 동작 방식 참조). 테넌트 격리를 위해 더 필요하면 계정 팀에 문의하세요.

스킬 만들기 (Creating a Skill)

스킬 번들(Skill bundle)은 최상위에 namedescription 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 플레이스홀더를 그것으로 대체하세요.

```bash cURL curl -X POST "https://api.anthropic.com/v1/skills" \ -H "x-api-key: $ANTHR...KEY" \ -H "anthropic-version: 2023-06-01" \ -F "files[]=@financial_skill/SKILL.md;filename=financial_skill/SKILL.md" \ -F "files[]=@financial_skill/analyze.py;filename=financial_skill/analyze.py" ``` ```bash CLI ant apply financial_skill ```
<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.mdname에서 파생되고, 명시적 값은 최대 255자이며 워크스페이스 내에서 고유할 필요 없음

  • 총 업로드 크기는 30 MB(압축 전) 미만이어야 함

  • YAML frontmatter 요구사항:

    • name: 최대 64자, 소문자/숫자/하이픈만, XML 태그 없음, 예약어 없음("anthropic", "claude")
    • description: 최대 1024자, 비어 있지 않음, XML 태그 없음

완전한 요청/응답 스키마는 스킬 생성 API 레퍼런스를 참고하세요.

스킬 나열하기 (Listing Skills)

Anthropic이 미리 만든 스킬과 커스텀 스킬을 포함해 워크스페이스에서 사용 가능한 모든 스킬을 가져오세요. source 파라미터로 스킬 유형별로 필터링하세요:

```bash cURL # List all Skills curl "https://api.anthropic.com/v1/skills" \ -H "x-api-key: $ANTHR...KEY" \ -H "anthropic-version: 2023-06-01"

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)

특정 스킬에 대한 세부 사항을 가져오세요:

```bash cURL curl "https://api.anthropic.com/v1/skills/skill_01AbCdEfGhIjKlMnOpQrStUv" \ -H "x-api-key: $ANTHR...KEY" \ -H "anthropic-version: 2023-06-01" ```
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)

스킬을 삭제하면 모든 버전도 제거돼요.

```bash cURL curl -X DELETE "https://api.anthropic.com/v1/skills/skill_01AbCdEfGhIjKlMnOpQrStUv" \ -H "x-api-key: $ANTHR...KEY" \ -H "anthropic-version: 2023-06-01" ```
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.mdname은 스킬의 기존 이름과 일치해야 해요. 다음 예시는 스킬 만들기의 완전한 financial_skill/ 번들을 다시 업로드해요.

```bash cURL # Create a new version NEW_VERSION=$(curl -X POST "https://api.anthropic.com/v1/skills/skill_01AbCdEfGhIjKlMnOpQrStUv/versions" \ -H "x-api-key: $ANTHR...KEY" \ -H "anthropic-version: 2023-06-01" \ -F "files[]=@financial_skill/SKILL.md;filename=financial_skill/SKILL.md" \ -F "files[]=@financial_skill/analyze.py;filename=financial_skill/analyze.py")

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)

컨테이너에서 스킬을 지정하면:

  1. 메타데이터 발견: Claude는 각 스킬의 메타데이터(이름, 설명)를 시스템 프롬프트에서 봐요.
  2. 파일 로드: 스킬 파일이 컨테이너의 /skills/{skill-name}/로 복사돼요. 디렉터리는 스킬의 이름(Anthropic 스킬은 pptx, 커스텀 스킬은 SKILL.mdname)이지, skill_01... ID가 아니에요.
  3. 자동 사용: Claude는 요청과 관련 있을 때 스킬을 자동으로 로드하고 사용해요.
  4. 구성: 여러 스킬이 복잡한 워크플로를 위해 함께 구성돼요.

Claude는 필요할 때만 전체 스킬 지시를 로드해요.


사용 사례 (Use cases)

스킬은 조직 작업과 개인 작업 모두에 맞아요. 조직은 문서에 브랜드 서식을 적용하고, 회사 템플릿에 맞춰 메모와 보고서를 구성하고, 회사별 분석 절차를 실행하는 데 사용해요. 개인은 커스텀 문서 템플릿, 전문화된 데이터 파이프라인, 코드 생성이나 배포 관례에 사용해요.

예시: 금융 모델링 (Example: financial modeling)

Excel 스킬과 커스텀 DCF 분석 스킬을 결합하세요. 먼저 커스텀 DCF 분석 스킬을 만듭니다:

```bash cURL curl -X POST "https://api.anthropic.com/v1/skills" \ -H "x-api-key: $ANTHR...KEY" \ -H "anthropic-version: 2023-06-01" \ -F "files[]=@dcf_skill/SKILL.md;filename=dcf_skill/SKILL.md" ```
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로 전달하세요:

```bash cURL 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": "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" }] }' ```
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에서 따옴표로 감싸세요.

```bash cURL # Pin to specific versions for stability 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": "skver_01AbCdEfGhIjKlMnOpQrStUv" }] }, "messages": [{"role": "user", "content": "Analyze the sales data"}], "tools": [{"type": "code_execution_20250825", "name": "code_execution"}] }' ```
# 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를 사용하세요.

```bash cURL # Use latest for active development 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": "Analyze the sales data"}], "tools": [{"type": "code_execution_20250825", "name": "code_execution"}] }' ```
# 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)

프롬프트 캐싱을 사용한다면 컨테이너의 스킬 목록을 바꾸는 것은 캐시를 깨요. 스킬은 고정된 순서로 시스템 프롬프트에 렌더링되므로, 같은 목록은 같은 캐시 가능 접두사를 만들어요:

```bash cURL # Skills render into the system prompt in a fixed, cache-friendly order 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"} ] }, "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

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)

스킬 관련 오류를 우아하게 처리하세요:

```bash cURL # This error-handling flow doesn't translate well to a one-off shell # command; one of the SDK options would be a better fit. A failing request # returns HTTP 400 with an error JSON whose .error.message names the # Skill problem. ```
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.mdname에서 파생
최신 버전 포인터 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

마이그레이션하려면:

  1. 베타 헤더를 제거하세요. 요청에서 anthropic-beta: skills-2025-10-02를 빼세요. SDK에서 client.beta.skills 대신 client.skills를 호출하세요. client.beta.skills를 유지하는 것은 더 이상 헤더를 보내지 않는 SDK 릴리스에서만 동작해요. 이전 릴리스는 betas 인자가 없어도 client.beta.skills에서 헤더를 보내요.
  2. 코드의 필드를 이름 바꾸세요: display_titledisplay_name으로, latest_versionlatest_version_id로, 그리고 source를 문자열과 비교하는 대신 source.type을 읽으세요.
  3. 버전 ID를 사용하세요. epoch-마이크로초 버전을 저장한 곳마다 버전의 id를 저장하거나 latest를 사용하세요. Messages 요청의 스킬 참조는 버전 ID, latest, 또는(Anthropic 스킬의 경우) 카탈로그 버전을 받아들여요.
  4. 삭제 호출을 검토하세요. DELETE /v1/skills/{skill_id}가 이제 스킬과 함께 모든 버전을 제거해요. 베타의 거부를 안전장치로 의존했다면 자체 확인을 추가하세요.
마이그레이션 후 `client.skills.delete(skill_id)`와 `client.beta.skills.delete(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은 이제 비베타 타입의 SkillContainerSkill에 맞춰 스킬 리소스를 이름 지어요. 이전 SDK 릴리스는 베타 형태로 타이핑돼요. 그 타입에 의존한다면 마이그레이션할 때까지 이전 릴리스에 머무르세요.

데이터 보관 (Data retention)

에이전트 스킬은 ZDR 계약으로 다뤄지지 않아요. 스킬 정의와 실행 데이터는 Anthropic의 표준 데이터 보관 정책에 따라 유지돼요.

모든 기능의 ZDR 자격에 대해서는 API와 데이터 보관을 참고하세요.

감사 로깅 (Audit logging)

조직에 Compliance API가 활성화되어 있으면 그 활동 피드가 Claude API 키나 Claude 콘솔에서 이루어진 스킬과 스킬 버전의 생성·삭제를 기록해요. Compliance API가 꺼져 있는 동안 일어난 작업은 기록되지 않고 나중에 복구할 수 없으므로, 이 감사 추적에 의존하기 전에 Compliance API를 설정하세요.

다음 단계 (Next steps)

모든 엔드포인트가 있는 완전한 API 레퍼런스 Claude가 발견하고 성공적으로 사용할 수 있는 효과적인 스킬 쓰는 방법 배우기. 샌드박스 컨테이너에서 Python과 bash 코드를 실행해 데이터를 분석하고 파일을 만들며 솔루션을 반복하기.

더 알아보기 (Learn more)