Bỏ qua để đến nội dung

Slash command trong SDK

Bài viết được dịch tự động từ bài viết gốc, chưa được kiểm tra lại bởi con người. Chỉ những bài viết có dấu tick xanh cạnh tiêu đề là đã được kiểm tra.

Slash command là cách điều khiển session Claude Code bằng các lệnh đặc biệt bắt đầu bằng /. Các lệnh này có thể được gửi qua SDK để thực hiện hành động như nén context, liệt kê mức dùng context, hay gọi custom command riêng. Chỉ những lệnh hoạt động được mà không cần terminal tương tác mới có thể gửi qua SDK; message system/init liệt kê những lệnh khả dụng trong session của bạn.

Claude Agent SDK cung cấp thông tin về các slash command khả dụng trong system initialization message. Truy cập thông tin này khi session của bạn bắt đầu:

import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "Hello Claude",
options: { maxTurns: 1 }
})) {
if (message.type === "system" && message.subtype === "init") {
console.log("Available slash commands:", message.slash_commands);
// Gồm built-in command cộng skill được đóng gói sẵn, ví dụ:
// ["clear", "compact", "context", "usage", "code-review", "verify", ...]
}
}
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, SystemMessage
async def main():
async for message in query(prompt="Hello Claude", options=ClaudeAgentOptions(max_turns=1)):
if isinstance(message, SystemMessage) and message.subtype == "init":
print("Available slash commands:", message.data["slash_commands"])
# Gồm built-in command cộng skill được đóng gói sẵn, ví dụ:
# ["clear", "compact", "context", "usage", "code-review", "verify", ...]
asyncio.run(main())

Gửi slash command bằng cách đưa chúng vào chuỗi prompt, giống như text thông thường. Các lệnh tác động lên lịch sử hội thoại, như /compact, cần có message trước đó để làm việc, nên các ví dụ dưới đây hỏi một câu hỏi trước rồi gửi lệnh như một follow-up cho cùng hội thoại đó:

import { query } from "@anthropic-ai/claude-agent-sdk";
// Xây dựng lịch sử hội thoại trước
try {
for await (const message of query({
prompt: "What does the README in this directory cover?",
options: { maxTurns: 2 }
})) {
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}
} catch (error) {
// Một query() single-shot throw lỗi sau khi yield một result lỗi,
// nên query follow-up bên dưới vẫn chạy.
console.error(`Session ended with an error: ${error}`);
}
// Gửi một slash command làm follow-up cho cùng hội thoại
for await (const message of query({
prompt: "/compact",
options: { continue: true, maxTurns: 1 }
})) {
if (message.type === "result") {
console.log("Command executed, result subtype:", message.subtype);
// Ví dụ output: Command executed, result subtype: success
}
}
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
async def main():
# Xây dựng lịch sử hội thoại trước
try:
async for message in query(
prompt="What does the README in this directory cover?",
options=ClaudeAgentOptions(max_turns=2),
):
if isinstance(message, ResultMessage) and message.subtype == "success":
print(message.result)
except Exception as error:
# Một query() single-shot raise lỗi sau khi yield một result lỗi,
# nên query follow-up bên dưới vẫn chạy.
print(f"Session ended with an error: {error}")
# Gửi một slash command làm follow-up cho cùng hội thoại
async for message in query(
prompt="/compact",
options=ClaudeAgentOptions(continue_conversation=True, max_turns=1),
):
if isinstance(message, ResultMessage):
print("Command executed, result subtype:", message.subtype)
# Ví dụ output: Command executed, result subtype: success
asyncio.run(main())

Lệnh /compact giảm kích thước lịch sử hội thoại bằng cách tóm tắt các message cũ hơn trong khi giữ lại ngữ cảnh quan trọng. Việc nén cần một hội thoại hiện có với ít nhất hai lượt trao đổi trước đó để tóm tắt. Ví dụ này có một hội thoại trước, rồi nén nó và đọc system message compact_boundary báo cáo kết quả:

import { query } from "@anthropic-ai/claude-agent-sdk";
// Việc nén cần lịch sử có sẵn, nên hãy hội thoại trước
try {
for await (const message of query({
prompt: "Explain what this project does",
options: { maxTurns: 2 }
})) {
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}
} catch (error) {
// Một query() single-shot throw lỗi sau khi yield một result lỗi,
// nên query follow-up bên dưới vẫn chạy.
console.error(`Session ended with an error: ${error}`);
}
// Nén cùng hội thoại đó
for await (const message of query({
prompt: "/compact",
options: { continue: true, maxTurns: 1 }
})) {
if (message.type === "system" && message.subtype === "compact_boundary") {
console.log("Compaction completed");
console.log("Pre-compaction tokens:", message.compact_metadata.pre_tokens);
console.log("Trigger:", message.compact_metadata.trigger);
// Ví dụ output:
// Compaction completed
// Pre-compaction tokens: 1842
// Trigger: manual
}
}
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage, SystemMessage
async def main():
# Việc nén cần lịch sử có sẵn, nên hãy hội thoại trước
try:
async for message in query(
prompt="Explain what this project does",
options=ClaudeAgentOptions(max_turns=2),
):
if isinstance(message, ResultMessage) and message.subtype == "success":
print(message.result)
except Exception as error:
# Một query() single-shot raise lỗi sau khi yield một result lỗi,
# nên query follow-up bên dưới vẫn chạy.
print(f"Session ended with an error: {error}")
# Nén cùng hội thoại đó
async for message in query(
prompt="/compact",
options=ClaudeAgentOptions(continue_conversation=True, max_turns=1),
):
if isinstance(message, SystemMessage) and message.subtype == "compact_boundary":
print("Compaction completed")
print("Pre-compaction tokens:", message.data["compact_metadata"]["pre_tokens"])
print("Trigger:", message.data["compact_metadata"]["trigger"])
# Ví dụ output:
# Compaction completed
# Pre-compaction tokens: 1842
# Trigger: manual
asyncio.run(main())

Lệnh /clear reset hội thoại về context rỗng, nên các prompt sau đó bắt đầu không có lịch sử hội thoại trước. Hội thoại trước vẫn nằm trên đĩa và có thể quay lại bằng cách truyền session ID của nó vào tùy chọn resume.

Điều này hữu ích trong streaming input mode, nơi bạn gửi nhiều prompt qua một kết nối duy nhất. Với lời gọi query() one-shot, mỗi lời gọi đã bắt đầu với context rỗng, nên gửi /clear không có tác dụng thực tế; hãy bắt đầu một query() mới thay vào đó.

Ngoài việc dùng các slash command có sẵn, bạn có thể tạo command riêng khả dụng qua SDK. Bạn định nghĩa custom command dưới dạng file markdown trong các thư mục cụ thể, giống cách bạn cấu hình subagent.

Lưu custom slash command trong một trong các thư mục sau, tùy phạm vi:

  • Command dự án: .claude/commands/ - Chỉ khả dụng trong dự án hiện tại (legacy; ưu tiên .claude/skills/)
  • Command cá nhân: ~/.claude/commands/ - Khả dụng ở mọi dự án của bạn (legacy; ưu tiên ~/.claude/skills/)

Mỗi custom command là một file markdown trong đó:

  • Tên file (không kèm phần mở rộng .md) trở thành tên command
  • Nội dung file định nghĩa command làm gì
  • Frontmatter YAML tùy chọn cung cấp cấu hình

Tạo thư mục .claude/commands trong dự án của bạn nếu chưa có, rồi tạo .claude/commands/refactor.md:

Refactor the selected code to improve readability and maintainability.
Focus on clean code principles and best practices.

Điều này tạo command /refactor mà bạn có thể dùng qua SDK.

Tạo .claude/commands/security-check.md:

---
allowed-tools: Read, Grep, Glob
description: Run security vulnerability scan
model: claude-opus-4-8
---
Analyze the codebase for security vulnerabilities including:
- SQL injection risks
- XSS vulnerabilities
- Exposed credentials
- Insecure configurations

Một khi đã định nghĩa trên filesystem, custom command tự động khả dụng qua SDK:

import { query } from "@anthropic-ai/claude-agent-sdk";
// Dùng một custom command
try {
for await (const message of query({
prompt: "/refactor src/auth/login.ts",
options: { maxTurns: 3 }
})) {
if (message.type === "assistant") {
console.log("Refactoring suggestions:", message.message);
}
}
} catch (error) {
// Một query() single-shot throw lỗi sau khi yield một result lỗi,
// nên query thứ hai bên dưới vẫn chạy.
console.error(`Session ended with an error: ${error}`);
}
// Custom command xuất hiện trong danh sách slash_commands
for await (const message of query({
prompt: "Hello",
options: { maxTurns: 1 }
})) {
if (message.type === "system" && message.subtype === "init") {
console.log("Available commands:", message.slash_commands);
// Gồm built-in command cộng skill đóng gói sẵn và custom command của bạn, ví dụ:
// ["clear", "compact", "context", "usage", "code-review", "verify", "refactor", "security-check", ...]
}
}
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage, SystemMessage
async def main():
# Dùng một custom command
try:
async for message in query(
prompt="/refactor src/auth/login.py", options=ClaudeAgentOptions(max_turns=3)
):
if isinstance(message, AssistantMessage):
for block in message.content:
if hasattr(block, "text"):
print("Refactoring suggestions:", block.text)
except Exception as error:
# Một query() single-shot raise lỗi sau khi yield một result lỗi,
# nên query thứ hai bên dưới vẫn chạy.
print(f"Session ended with an error: {error}")
# Custom command xuất hiện trong danh sách slash_commands
async for message in query(prompt="Hello", options=ClaudeAgentOptions(max_turns=1)):
if isinstance(message, SystemMessage) and message.subtype == "init":
print("Available commands:", message.data["slash_commands"])
# Gồm built-in command cộng skill đóng gói sẵn và custom command của bạn, ví dụ:
# ["clear", "compact", "context", "usage", "code-review", "verify", "refactor", "security-check", ...]
asyncio.run(main())

Custom command hỗ trợ argument động bằng placeholder:

Tạo .claude/commands/fix-issue.md:

---
argument-hint: [issue-number] [priority]
description: Fix a GitHub issue
---
Fix issue #$0 with priority $1.
Check the issue description and implement the necessary changes.

Dùng trong SDK:

import { query } from "@anthropic-ai/claude-agent-sdk";
// Truyền argument cho custom command
try {
for await (const message of query({
prompt: "/fix-issue 123 high",
options: { maxTurns: 5 }
})) {
// Command sẽ xử lý với $0="123" và $1="high"
if (message.type === "result" && message.subtype === "success") {
console.log("Issue fixed:", message.result);
}
}
} catch (err) {
// Run kết thúc với lỗi khi chạm giới hạn maxTurns
console.error("Session ended with an error:", err);
}
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
async def main():
# Truyền argument cho custom command
try:
async for message in query(prompt="/fix-issue 123 high", options=ClaudeAgentOptions(max_turns=5)):
# Command sẽ xử lý với $0="123" và $1="high"
if isinstance(message, ResultMessage):
print("Issue fixed:", message.result)
except Exception as error:
# Run kết thúc với lỗi khi chạm giới hạn max_turns
print(f"Session ended with an error: {error}")
asyncio.run(main())

Nếu prompt truyền ít argument hơn số placeholder được tham chiếu, các placeholder đánh số chưa khớp như $1 giữ nguyên trong text command. Để biết hành vi substitution đầy đủ, gồm named argument, xem available string substitutions.

Custom command có thể thực thi bash command và đưa output vào:

Tạo .claude/commands/git-commit.md:

---
allowed-tools: Bash(git add *), Bash(git status *), Bash(git commit *)
description: Create a git commit
---
## Context
- Current status: !`git status`
- Current diff: !`git diff HEAD`
## Task
Create a git commit with appropriate message based on the changes.

Đưa nội dung file vào bằng tiền tố @:

Tạo .claude/commands/review-config.md:

---
description: Review configuration files
---
Review the following configuration files for issues:
- Package config: @package.json
- TypeScript config: @tsconfig.json
- Environment config: @.env
Check for security issues, outdated dependencies, and misconfigurations.

Tổ chức command trong các thư mục con để có cấu trúc tốt hơn:

Terminal window
.claude/commands/
├── frontend/
├── component.md # Tạo /component (project:frontend)
└── style-check.md # Tạo /style-check (project:frontend)
├── backend/
├── api-test.md # Tạo /api-test (project:backend)
└── db-migrate.md # Tạo /db-migrate (project:backend)
└── review.md # Tạo /review (project)

Thư mục con xuất hiện trong mô tả command nhưng không ảnh hưởng tới bản thân tên command.

Tạo .claude/commands/review-pr.md:

---
allowed-tools: Read, Grep, Glob, Bash(git diff *)
description: Comprehensive code review
---
## Changed Files
!`git diff --name-only HEAD~1`
## Detailed Changes
!`git diff HEAD~1`
## Review Checklist
Review the above changes for:
1. Code quality and readability
2. Security vulnerabilities
3. Performance implications
4. Test coverage
5. Documentation completeness
Provide specific, actionable feedback organized by priority.

Tạo .claude/commands/test.md:

---
allowed-tools: Bash, Read, Edit
argument-hint: [test-pattern]
description: Run tests with optional pattern
---
Run tests matching pattern: $ARGUMENTS
1. Detect the test framework (Jest, pytest, etc.)
2. Run tests with the provided pattern
3. If tests fail, analyze and fix them
4. Re-run to verify fixes

Dùng các command này qua SDK:

import { query } from "@anthropic-ai/claude-agent-sdk";
// Chạy code review
try {
for await (const message of query({
prompt: "/review-pr",
options: { maxTurns: 3 }
})) {
// Xử lý phản hồi review
}
} catch (error) {
// Một query() single-shot throw lỗi sau khi yield một result lỗi,
// nên query thứ hai bên dưới vẫn chạy.
console.error(`Session ended with an error: ${error}`);
}
// Chạy test cụ thể
for await (const message of query({
prompt: "/test auth",
options: { maxTurns: 5 }
})) {
// Xử lý kết quả test
}
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions
async def main():
# Chạy code review
try:
async for message in query(prompt="/review-pr", options=ClaudeAgentOptions(max_turns=3)):
# Xử lý phản hồi review
pass
except Exception as error:
# Một query() single-shot raise lỗi sau khi yield một result lỗi,
# nên query thứ hai bên dưới vẫn chạy.
print(f"Session ended with an error: {error}")
# Chạy test cụ thể
async for message in query(prompt="/test auth", options=ClaudeAgentOptions(max_turns=5)):
# Xử lý kết quả test
pass
asyncio.run(main())