Lộ trình học›Claude Code›Claude Code in Action Mở bản đồ

4.18 · Claude Code SDK — Claude Code programmatic

Bài viếtNâng cao28 phút đọc

Bạn đã dùng Claude Code qua CLI:

Sau bài này, bạn sẽ
  1. Giải thích SDK là gì, khác gì với CLI, và khi nào dùng mỗi cái
  2. Viết code TypeScript/Python gọi Claude Code programmatic
  3. Cấu hình allowedTools và permission cho SDK
  4. Embed SDK vào script, CI/CD pipeline, hook (đã dùng ở Bài 4.16)
  5. Thiết kế 5 automation scenario dùng SDK hiệu quả

Mở đầu: Khi CLI không đủ

claude
> Fix bug trong userService.ts

Interactive, thuận tiện — cho dev cá nhân.

Nhưng khi muốn:

  • Chạy Claude Code trong GitHub Action để auto-review PR (Bài 4.11 đã giới thiệu)
  • Cron job mỗi đêm scan codebase, generate report
  • Script tùy chỉnh analyze codebase khi merge
  • Hook gọi Claude trong Claude (Bài 4.16)
  • Chatbot internal với power của Claude Code

CLI interactive không fit. Bạn cần programmatic access.

Đó là Claude Code SDK.

SDK là gì?

Claude Code SDK = library cho phép bạn chạy Claude Code từ code.

Available cho:

  • TypeScript/JavaScript: npm install @anthropic-ai/claude-code
  • Python: pip install anthropic-claude-code
  • CLI headless mode: claude --print "task" --output-format json

Key insight

SDK chạy cùng Claude Code bạn dùng CLI. Same tools, same capability. Chỉ khác: output là structured data bạn code xử lý thay vì in ra terminal.

Ví dụ đơn giản: TypeScript

Setup

npm install @anthropic-ai/claude-code

Code

analyze.ts:

import { query } from "@anthropic-ai/claude-code";

const prompt = "Look for duplicate queries in the ./src/queries dir";

for await (const message of query({ prompt })) {
  console.log(JSON.stringify(message, null, 2));
}

Run

npx tsx analyze.ts

Output

Script print từng message raw — bạn thấy conversation giữa local Claude Code và LM remote:

{
  "type": "text",
  "text": "I'll analyze the queries directory..."
}

{
  "type": "tool_use",
  "name": "Glob",
  "input": { "pattern": "src/queries/**/*.ts" }
}

{
  "type": "tool_result",
  "content": "src/queries/orders.ts\nsrc/queries/users.ts\n..."
}

...

{
  "type": "text",
  "text": "Found 2 duplicates: getPendingOrders and getPendingOrdersByStatus overlap in functionality."
}

Message cuối chứa conclusion. Bạn extract, dùng trong logic tiếp theo.

Permissions — SDK default là read-only

Khi bạn gọi SDK, Claude chạy với permission mặc định chỉ read:

  • Read
  • Grep
  • Glob
  • Edit
  • Write
  • Bash

Lý do: Safety. Script chạy headless, không ai đứng approve tool call. Default lớp bảo vệ.

Grant permission qua allowedTools

for await (const message of query({
  prompt: "Update all TypeScript files...",
  options: {
    allowedTools: ["Edit", "Write", "Bash"],
  }
})) {
  // ...
}

Grant qua settings

Trong .claude/settings.json của project:

{
  "permissions": {
    "allow": ["Edit", "Write"]
  }
}

SDK run trong thư mục project inherit settings đó.

MCP tools

options: {
  allowedTools: [
    "mcp__playwright__browser_snapshot",
    "mcp__playwright__browser_click"
  ]
}

Mỗi MCP tool liệt kê tên riêng.

Python SDK

Tương tự:

from claude_code import query

async def main():
    async for message in query(
        prompt="Analyze security of auth module",
        options={
            "allowed_tools": ["Read", "Grep"],
        }
    ):
        print(message.to_dict())

Giống shape, khác syntax.

CLI headless mode

Nếu không muốn viết code, dùng flag --print:

claude --print "Count TS files in src/" --output-format json

Output: JSON một message — final response. Dùng trong shell script dễ.

Shell script ví dụ

#!/bin/bash
result=$(claude --print "List files changed in last commit" --output-format json)
echo "$result" | jq -r '.messages[-1].text'

Ví dụ thực chiến 1: Git hook review

Setup

.git/hooks/pre-commit:

#!/bin/bash

diff=$(git diff --cached)
[ -z "$diff" ] && exit 0

result=$(claude --print "Review this diff. Flag any issues. If clean, reply 'CLEAN'. Diff:
$diff
" --allowed-tools Read)

if echo "$result" | grep -q "CLEAN"; then
  exit 0
else
  echo "$result"
  echo
  read -p "Proceed with commit? (y/N) " answer
  [ "$answer" = "y" ] && exit 0 || exit 1
fi

Flow:

  1. Dev git commit
  2. Hook kick Claude review diff
  3. Nếu clean → auto pass
  4. Nếu có issue → print + ask confirm

Kết quả: Catch lỗi trước commit thay vì trong review. Developer feedback-loop nhanh hơn.

Ví dụ thực chiến 2: Cron job audit dependency

Setup

scripts/weekly-audit.ts:

import { query } from "@anthropic-ai/claude-code";
import fs from "fs";

async function audit() {
  const report: string[] = [];
  
  for await (const message of query({
    prompt: `
      Audit npm dependencies. Do the following:
      1. Run 'npm outdated --json' and parse
      2. For each outdated package, check changelog for breaking changes
      3. Check CVE database for known vulnerabilities
      4. Prioritize updates: security critical > major breaking > minor
      5. Output markdown report with sections
    `,
    options: {
      allowedTools: ["Bash", "WebFetch", "Read"],
      maxTurns: 20,
    }
  })) {
    if (message.type === 'text') report.push(message.text);
  }
  
  // Save report
  const filename = `reports/audit-${new Date().toISOString().split('T')[0]}.md`;
  fs.writeFileSync(filename, report.join("\n"));
  console.log(`Report saved: ${filename}`);
}

audit().catch(console.error);

Cron

0 8 * * 1   cd /path/to/repo && npx tsx scripts/weekly-audit.ts

Mỗi sáng thứ Hai 8h, có file report trong reports/.

Team workflow: Eng lead review report Monday standup, assign updates.

Ví dụ thực chiến 3: Slack bot với SDK

Setup

Server Node.js với Slack Bolt:

import { App } from "@slack/bolt";
import { query } from "@anthropic-ai/claude-code";

const app = new App({ token: process.env.SLACK_BOT_TOKEN, ... });

app.message(/@claude-bot (.*)/, async ({ message, say }) => {
  const userPrompt = message.text.replace("@claude-bot", "").trim();
  
  await say(":thinking_face: Working on it...");
  
  let response = "";
  for await (const msg of query({
    prompt: userPrompt,
    options: {
      cwd: "/path/to/codebase",
      allowedTools: ["Read", "Grep", "Glob", "WebFetch"],
      maxTurns: 10,
    }
  })) {
    if (msg.type === 'text') response += msg.text;
  }
  
  await say(response);
});

app.start(3000);

Use case: Team Slack, mention @claude-bot, hỏi câu hỏi về codebase, bot answer.

User: @claude-bot why do we have 2 implementations of formatPrice?

Bot: I found 2 implementations:
  1. src/utils/price.ts (older, used in API layer)
  2. src/components/Price.tsx (newer, used in UI)
  
  The newer one handles i18n, the older doesn't. Recommend 
  deprecating the older, migrating API layer.

Ví dụ thực chiến 4: Documentation generator

Setup

scripts/gen-docs.ts:

import { query } from "@anthropic-ai/claude-code";
import fs from "fs";

const FEATURES = ["auth", "billing", "reports", "admin"];

for (const feature of FEATURES) {
  console.log(`Documenting ${feature}...`);
  
  let doc = "";
  for await (const msg of query({
    prompt: `
      Document the ${feature} feature:
      1. Read @src/features/${feature}/
      2. Generate markdown with:
         - Overview (2 paragraphs)
         - Key files & responsibilities
         - API surface (exported functions, types)
         - Integration points (external services, DB tables)
         - Common gotchas from code comments
    `,
    options: { allowedTools: ["Read", "Grep", "Glob"] }
  })) {
    if (msg.type === 'text') doc += msg.text;
  }
  
  fs.writeFileSync(`docs/features/${feature}.md`, doc);
}

console.log("Docs generated!");

Run:

npx tsx scripts/gen-docs.ts

4 doc files sinh ra, consistent format, auto-update khi codebase đổi.

Ví dụ thực chiến 5: CI/CD gate

Setup

.github/workflows/ci.yml:

- name: Claude quality gate
  run: |
    result=$(claude --print "Scan @src/ for TODO comments older than 30 days. List them with file:line." --output-format json)
    
    count=$(echo "$result" | jq -r '.messages[-1].text' | grep -c TODO || true)
    
    if [ "$count" -gt 50 ]; then
      echo "::warning::TODO count exceeds 50: $count"
    fi
    
    echo "$result" > quality-report.json
  env:
    ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

Use case

CI sinh báo cáo tech debt định kỳ. Team review, priority.

Case studies theo ngành

Fintech — Compliance scanner SDK

Setup: Nightly SDK job scan codebase for compliance pattern (PII leak, unauthorized API call, etc.)

  • Kết quả: Compliance reports automated, save 20 hours/week.

Healthcare — Data flow mapper

Setup: SDK script map PHI data flow across microservices weekly.

  • Kết quả: Data flow diagram auto-updated, SOC2 audit evidence.

Platform engineering — API breaking change detector

Setup: SDK on PR → scan changes to public API interface, flag breaking.

  • Kết quả: Zero accidental breaking change shipped in 6 months.

Content platform — Content moderation pipeline

Setup: SDK batch process user content generation — check voice, flag issue before publish.

  • Kết quả: Brand voice consistency automated, 3x publishing velocity.

Game dev — Asset metadata extractor

Setup: SDK script scan new game assets, extract metadata, generate catalog JSON for engine.

  • Kết quả: Asset pipeline 10x faster than manual tagging.

SDK vs CLI — Decision tree

Need automation?
│
├── Chạy trong terminal, 1 lần?
│    └── CLI (claude) — interactive
│
├── Chạy trong shell script?
│    └── CLI headless (claude --print)
│
├── Chạy trong code (Node.js/Python app)?
│    └── SDK — structured output
│
├── Chạy trong CI/CD?
│    └── GitHub Action (Bài 4.11) hoặc CLI headless
│
└── Chạy trong hook của Claude Code?
     └── SDK (như ví dụ Bài 4.16)

Anti-patterns

Grant allowedTools: ["*"] cho SDK

Rủi ro
SDK chạy không supervise có thể làm destructive action. Mất code, leak data.
Cách đúng
Minimum permission. Chỉ grant tool thực sự cần cho task.

Ignore maxTurns

Không set maxTurns → SDK có thể loop vô hạn, tốn $$$.

Cách đúng: maxTurns: 10-30 cho task thường, 50-100 cho task phức tạp. Cap là bắt buộc.

Không handle error của SDK

SDK throw khi API fail, quota exhausted. Không catch → script crash.

Cách đúng:

try {
  for await (const msg of query({...})) {...}
} catch (err) {
  console.error("SDK failed:", err);
  // fallback / retry / alert
}

Run SDK trong loop không rate limit

100 file cần process → 100 SDK call song song → API rate limit.

Cách đúng: Process sequential hoặc batch nhỏ (5-10 song song max).

Hardcode API key trong code

process.env.ANTHROPIC_API_KEY = "sk-ant-..."; // ❌

Cách đúng: Env var / secret manager, không hardcode.

Mẹo nâng cao

Mẹo 1: Structured output với JSON mode

Khi cần response có structure cố định:

for await (const msg of query({
  prompt: `Return JSON with shape: { status: 'ok'|'fail', reason: string }
          
          Analyze ${file} and return your analysis.`,
  options: {
    outputFormat: "json",
  }
})) {
  const parsed = JSON.parse(msg.text);
  // ...
}

Dễ parse trong code downstream.

Mẹo 2: Session resumption

SDK hỗ trợ resume conversation:

const sessionId = "abc123";
const firstRun = await query({ prompt: "Start analysis", sessionId });
// ... later ...
const continuation = await query({ prompt: "Continue where you left off", sessionId });

Task dài nhiều step có thể phân tách.

Mẹo 3: Stream để UX responsive

Thay vì wait final, stream text real-time:

for await (const msg of query({...})) {
  if (msg.type === 'text_delta') {
    process.stdout.write(msg.text);  // print as it comes
  }
}

Perfect cho chatbot / tool interactive.

Mẹo 4: Budget & monitoring

Instrument SDK call với cost tracking:

let tokensUsed = 0;
for await (const msg of query({...})) {
  if (msg.type === 'usage') tokensUsed += msg.tokens;
}
console.log(`Spent: $${(tokensUsed * 0.003 / 1000).toFixed(2)}`);

Tránh bill sốc.

Áp dụng ngay

Bài tập 1: Script SDK đầu tiên (20 phút)

Bước 1: Trong uigen (hoặc project của bạn):

npm install @anthropic-ai/claude-code

Bước 2: Tạo scripts/explore.ts:

import { query } from "@anthropic-ai/claude-code";

for await (const msg of query({
  prompt: "Analyze this codebase. Report: (1) LOC by language, (2) largest 5 files, (3) dependencies with no tests.",
  options: {
    allowedTools: ["Read", "Grep", "Glob", "Bash"],
    maxTurns: 15,
  }
})) {
  if (msg.type === 'text') console.log(msg.text);
}
Bước 3
Run npx tsx scripts/explore.ts.
Bước 4
Ghi:
  • Kết quả: ____________
  • Tokens used: ____________
  • Latency: ____________

Bài tập 2 (optional, 25 phút): Automation script

Chọn task lặp thực tế trong workflow bạn:

  • Generate weekly report
  • Scan for tech debt
  • Check documentation freshness

Implement bằng SDK. Run 1 lần, verify output quality. Nếu OK → schedule cron/CI.

Tóm tắt bài học

Những điều cốt lõi
  • SDK = Claude Code programmatic — TypeScript/Python/CLI headless.
  • Default read-only — phải grant allowedTools cho write/execute.
  • 5 automation pattern: git hook, cron job, chatbot, doc generator, CI gate.
  • maxTurns là mandatory — tránh loop vô hạn, chi phí kiểm soát.
  • SDK + hook = self-improving Claude — Claude review output Claude.

Tài liệu tham khảo

Kiểm tra nhanh2 câu hỏi · chọn đáp án để xem giải thích
    Bạn đã hoàn thành bài này chưa?Tiến độ lưu trên trình duyệt của bạn.