Claude Code SDK — Claude Code programmatic

6 — Automation & Wrap-upNâng cao30 phút

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

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

SDK là gì?

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

Available cho:

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.

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

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

Setup

Code

analyze.ts:

npm install @anthropic-ai/claude-code

Code

Run

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

Output

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

npx tsx analyze.ts

Output

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

{
  "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."
}

Permissions — SDK default là read-only

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

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

Grant permission qua allowedTools

Grant qua settings

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

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

Grant qua settings

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

MCP tools

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

MCP tools

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

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

Python SDK

Tương tự:

Giống shape, khác syntax.

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())

CLI headless mode

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

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

Shell script ví dụ

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

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:

Flow:

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

  • Dev git commit
  • Hook kick Claude review diff
  • Nếu clean → auto pass
  • Nếu có issue → print + ask confirm
#!/bin/bash
# Chạy Claude Code review diff trước commit

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

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

Setup

scripts/weekly-audit.ts:

Cron

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

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

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

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

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

Setup

Server Node.js với Slack Bolt:

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

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);

Setup

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:

Run:

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!");

Setup

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

npx tsx scripts/gen-docs.ts

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

Setup

.github/workflows/ci.yml:

Use case

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

- 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 }}

Case studies theo ngành

💼 Fintech — Compliance scanner SDK

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

🏥 Healthcare — Data flow mapper

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

🛠️ Platform engineering — API breaking change detector

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

📣 Content platform — Content moderation pipeline

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

🎮 Game dev — Asset metadata extractor

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

  • Kết quả: Compliance reports automated, save 20 hours/week.
  • Kết quả: Data flow diagram auto-updated, SOC2 audit evidence.
  • Kết quả: Zero accidental breaking change shipped in 6 months.
  • Kết quả: Brand voice consistency automated, 3x publishing velocity.
  • 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:

❌ 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

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

❌ Hardcode API key trong code

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

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

Mẹo nâng cao

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

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

Dễ parse trong code downstream.

Mẹo 2: Session resumption

SDK hỗ trợ resume conversation:

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);
  // ...
}

Mẹo 2: Session resumption

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:

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

Mẹo 3: Stream để UX responsive

Perfect cho chatbot / tool interactive.

Mẹo 4: Budget & monitoring

Instrument SDK call với cost tracking:

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

Mẹo 4: Budget & monitoring

Tránh bill sốc.

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)}`);

Á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):

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

npm install @anthropic-ai/claude-code

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

Bước 3: Run npx tsx scripts/explore.ts.

Bước 4: Ghi:

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

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

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

  • Kết quả: ____________
  • Tokens used: ____________
  • Latency: ____________
  • Generate weekly report
  • Scan for tech debt
  • Check documentation freshness
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);
}

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

🎯 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
  • Claude Code SDK TS docs
  • Claude Code SDK Python docs
  • Headless automation talk — Code w/ Claude 2025
  • Bài 4.11 — GitHub Actions (SDK in CI)
  • Bài 4.16 — SDK in hooks (Claude reviews Claude)
Nội dung này có hữu ích không?