Learn > Claude > Claude Code in Action

Claude Code in Action

AI-assisted coding, terminal, debugging, CI/CD thực chiến.

  • Coding assistant không chỉ là công cụ viết code mà là một hệ thống dùng language model (LM) để giải task lập trình, theo quy trình như dev người thật: Gather context → Formulate a plan → Take an action, rồi lặp (iterate).
  • Bên trong Assistant = Language Model + Set of tools. Đa số assistant dùng LM host từ xa; Claude Code dùng Claude series, host ở Anthropic, AWS hoặc Google Cloud (configurable).
  • Tool Use Challenge: LM tự thân chỉ text-in/text-out, không thật sự đọc file hay chạy lệnh. Tool use giải bằng cách coding assistant chèn instruction dạy LM cách request action (VD "ReadFile: main.go"), assistant thực thi hộ rồi trả kết quả ngược lại cho LM.
  • Không phải LM nào cũng dùng tool giỏi như nhau. Claude series (Opus, Sonnet, Haiku) đặc biệt mạnh ở hiểu và dùng tool — kể cả tool chưa từng thấy.
  • Lợi ích tool use mạnh: tackle task khó hơn (kết hợp nhiều tool), extensible platform (thêm tool mới dễ), và better security (navigate codebase không cần indexing → thường không gửi cả codebase lên server ngoài).
  • Claude Code ship kèm bộ built-in tools: Agent, Bash, Edit, Glob (tìm file theo pattern), Grep (tìm nội dung file), LS, MultiEdit, NotebookEdit/NotebookRead, Read, TodoRead/TodoWrite, WebFetch, WebSearch, Write — harness khai báo cho model ở mỗi request.
  • Sức mạnh nằm ở chuỗi nhiều tool và mở rộng bằng MCP: data analysis qua notebook (viết code → chạy → thêm cell → summary), UI styling qua Playwright MCP (điều khiển browser: mở, navigate, screenshot), review PR qua GitHub MCP, và đọc xuyên Terraform/IaC để soi luồng dữ liệu across hệ thống (DB → Lambda → S3).
  • Context management là kỹ năng cốt lõi: project có hàng trăm file nhưng quá nhiều context không liên quan lại LÀM GIẢM hiệu năng Claude — phải dẫn nó tới đúng file. Chạy /init để Claude phân tích codebase và sinh CLAUDE.md (mục đích, kiến trúc, lệnh & file trọng yếu, coding patterns).
  • CLAUDE.md được nhét vào MỌI request → như system prompt bền vững cho project; 3 vị trí: CLAUDE.md (commit, chia sẻ team), CLAUDE.local.md (cá nhân, không commit), ~/.claude/CLAUDE.md (mọi project trên máy). Sửa qua /memory hoặc edit tay; nhắc file bằng @path để tự chèn nội dung file vào request.
  • Thực thi thay đổi hiệu quả: dán screenshot bằng Ctrl+V (kể cả macOS, KHÔNG phải Cmd+V) để chỉ đúng vùng UI; bật Planning Mode (/plan hoặc Shift+Tab 2 lần) để Claude khảo sát codebase → lập plan chi tiết → chờ duyệt trước khi sửa (Ctrl+G mở plan ra sửa tay, Claude dùng bản cuối).
  • Effort level điều khiển độ sâu suy luận: /effort xem & chỉnh (low nhanh/rẻ ↔ max nghĩ lâu nhất), ultrathink để nghĩ thêm cho 1 prompt lẻ, Ctrl+O xem reasoning. Mental model: Planning = bề RỘNG (nhiều file/bước), Effort = chiều SÂU (logic/debug/thuật toán khó); cả hai đều tốn thêm token.
  • Điều hướng hội thoại để giữ Claude tập trung: Escape ngắt giữa chừng để bẻ lái; Escape 2 lần hoặc /rewind để tua về điểm trước; /compact nén lịch sử mà giữ thông tin cốt (task liên quan); /clear mở hội thoại mới sạch context (task khác hẳn) — vẫn /resume lại được hội thoại cũ.
  • Hook: chạy command của riêng bạn NGAY TRƯỚC (PreToolUse) hoặc NGAY SAU (PostToolUse) khi Claude gọi một tool. PreToolUse CHẶN được (cho phép, hoặc block + gửi error message ngược lại cho Claude); PostToolUse KHÔNG chặn được (tool đã chạy rồi) — chỉ làm follow-up (VD format file vừa sửa) + feedback cho Claude. matcher chỉ định tool bị nhắm (VD "Write|Edit", dấu | = OR). Khai báo trong settings.json (global ~/.claude / project / project-local) hoặc gõ /hooks. Câu chốt: Pre = kiểm soát Claude ĐƯỢC LÀM GÌ; Post = tăng cường thứ ĐÃ LÀM.
  • Dựng một hook = 4 bước: (1) chọn Pre/Post, (2) xác định tool cần canh (matcher), (3) viết command nhận JSON tool call qua standard input (stdin), (4) dùng exit code báo allow/block. JSON gồm session_id, transcript_path, hook_event_name, tool_name, tool_input. Exit code 0 = allow; exit code 2 = block (CHỈ PreToolUse), và khi exit 2 thì mọi thứ ghi ra standard error (stderr) được gửi cho Claude làm feedback giải thích vì sao bị chặn. Ví dụ chặn đọc .env (bản hiện hành của khoá) chỉ cover tool Read qua tool_input.file_path; mỗi tool có input shape khác nhau (Grep gửi pattern + path là thư mục, Bash gửi command) nên check file_path KHÔNG bắt được grep/cat .env — muốn phủ đồng đều thì dùng permissions.deny "Read(**/.env)".
  • Gotcha bảo mật hook: docs khuyến nghị dùng absolute path (KHÔNG relative) cho script hook → giảm path interception + binary planting attack. Nhưng absolute path khó share (mỗi máy để project ở thư mục khác). Cách giải: settings.example.json chứa placeholder $PWD; npm run setup chạy scripts/init-claude.js thay $PWD bằng absolute path máy bạn rồi copy & đổi tên thành settings.local.json — vừa share được (commit template) vừa giữ absolute path.
  • Hai hook thực chiến giải điểm yếu AI-assisted dev: (1) TypeScript type-checking hook (PostToolUse) chạy tsc --noEmit sau mỗi edit → capture type error → feed lại Claude để sửa call site nó quên (VD đổi signature ở schema.ts nhưng quên main.ts); typed language dùng type checker, untyped thì dùng automated tests. (2) Query duplication hook dùng Agent SDK khởi chạy một Claude THỨ HAI review file trong ./queries, phát hiện query trùng → feedback bắt Claude tái dùng hàm có sẵn (VD getPendingOrders). Query hook nặng (tốn API mỗi edit) → chỉ monitor thư mục quan trọng. Nguyên tắc: compiler/linter = deterministic gate; AI review = probabilistic gate cho việc không có ground truth.
  • Ngoài Pre/PostToolUse còn 7 hook event phủ vòng đời session: Notification (Claude xin quyền dùng tool, hoặc idle 60 giây), Stop (Claude trả lời xong), SubagentStop (subagent = "Task" trong UI chạy xong), PreCompact (trước compact thủ công/tự động), UserPromptSubmit (user submit prompt, TRƯỚC khi Claude xử lý), SessionStart (bắt đầu/resume session), SessionEnd (session kết thúc). Cấu trúc stdin đổi theo 2 trục: theo loại hook (Stop chỉ có hook_event_name + stop_hook_active, không có tool_name/tool_input) và theo tool được gọi (tool_input khác nhau; PostToolUse còn có thêm tool_response). Mẹo soi input: gắn tạm hook matcher "*" với 'jq . > post-log.json' để ghi input ra file mà xem shape thật.
  • Agent SDK: chạy Claude Code programmatically từ app/script của bạn (TypeScript + Python), trao đúng agent loop CLI dùng (đọc/sửa file, tool use) dưới quyền bạn. Package = @anthropic-ai/claude-agent-sdk (KHÔNG phải @anthropic-ai/claude-code — đó là CLI, không import được). Dùng query({ prompt }) như async iterator, stream ra JSON message (tool call, tool result, text). Giới hạn tool bằng options.allowedTools (VD ["Read","Glob"]) = bản SDK của --allowedTools. SDK hỗ trợ đủ như CLI: custom system prompt, MCP, hooks, subagents, session resumption. Đây là thứ query_hook.js dùng để một Claude review một Claude khác.
  • Custom command: tự tạo slash command bằng file Markdown trong .claude/commands/ (tên file = tên lệnh, VD audit.md → /audit; tự nhận, không cần restart). Nhận tham số qua placeholder $ARGUMENTS (string bất kỳ, không chỉ file path). Lợi ích: automation, consistency, context, flexibility; commit vào repo để cả team dùng chung.
  • Thêm MCP server bằng `claude mcp add <name> <command>` chạy trong TERMINAL (không trong Claude Code); VD Playwright: claude mcp add playwright npx @playwright/mcp@latest. Pre-approve khỏi bị hỏi mỗi lần bằng cách thêm "mcp__playwright" (HAI gạch dưới) vào permissions.allow của .claude/settings.local.json (file cá nhân, không commit). Lợi thế Playwright: Claude thấy output hình ảnh thật nên tự cải thiện prompt/styling.
  • Official GitHub integration cho Claude Code chạy trong GitHub Actions (trên cloud, không chỉ local): cài bằng /install-github-app (install app + add API key + tự sinh PR chứa file workflow). Có 2 action mặc định — Mention Action (@claude trong issue/PR → analyze + task plan → thực thi với full codebase access → phản hồi tại chỗ) và Pull Request Action (tạo PR → review changes → analyze impact → post báo cáo).
  • Tuỳ biến workflow qua 4 field: Project Setup (bước chuẩn bị môi trường), custom_instructions (context về setup), mcp_config (cắm MCP server), và allowed_tools. ⚠️ Khác local: GitHub Actions KHÔNG có shortcut permission — từng tool của từng MCP server phải liệt kê tường minh trong allowed_tools (VD mcp__playwright__browser_snapshot, mcp__playwright__browser_click).

Claude Code in Action là gì? Là khoá thực chiến tiếp nối Claude Code 101, đi sâu vào coding với sự hỗ trợ của AI trong thực tế. Đây là ghi chú tiếng Việt tóm tắt toàn khoá, thuật ngữ giữ nguyên tiếng Anh kèm chú thích.

TL;DR — Một coding assistant không chỉ viết code; nó là hệ thống ghép language model (LM) với một set of tools, chạy vòng Gather context → Formulate a plan → Take an action rồi lặp. Mấu chốt: LM tự thân chỉ text-in/text-out, không đọc file hay chạy lệnh được — nó "làm được việc" nhờ tool use: assistant dạy LM trả về text đúng định dạng (VD ReadFile: main.go), rồi assistant thực thi hộ và đưa kết quả ngược lại. Claude series (Opus/Sonnet/Haiku) đặc biệt giỏi tool use, mang lại task khó hơn, dễ mở rộng, và bảo mật tốt hơn (không cần index cả codebase).

Coding assistant thực sự là gì

Một coding assistant không chỉ là công cụ viết code — nó là một hệ thống tinh vi dùng language model để giải các task lập trình phức tạp. Hiểu cách nó vận hành phía sau giúp nhận ra điều gì làm nên một "coding companion" thật sự mạnh.

Coding assistant làm việc thế nào

Khi nhận một task — VD fix một bug từ error message — coding assistant đi theo quy trình giống hệt một dev người thật:

  1. Gather context (thu thập ngữ cảnh) — hiểu error trỏ tới cái gì, phần nào của codebase bị ảnh hưởng, và file nào liên quan.
  2. Formulate a plan (lập kế hoạch) — quyết cách giải: sửa code chỗ nào, rồi chạy test để verify fix.
  3. Take an action (hành động) — thực sự hiện thực giải pháp: update file và chạy lệnh.

Rồi iterate (lặp) tới khi xong. Điểm mấu chốt: bước 1 và 3 buộc assistant phải tương tác với thế giới ngoài — đọc file, fetch documentation, chạy lệnh, hoặc sửa code.

Bên trong khối Assistant có hai thành phần: một Language Model và một Set of tools. Về nơi host model:

  • Đa số coding assistant dùng language model host từ xa (remotely hosted).
  • Claude Code dùng Claude series of models, host ở Anthropic, AWS, hoặc Google Cloudconfigurable (cấu hình được).

The Tool Use Challenge — vì sao cần tool

Đây là chỗ thú vị. Language model tự thân chỉ xử lý text và trả về text — nó không thật sự đọc file hay chạy lệnh được. Nếu bảo một LM trần "đọc file này", nó sẽ nói nó không có khả năng đó.

Vậy coding assistant giải bài toán này ra sao? Bằng một hệ thống khéo léo gọi là "tool use".

Tool use chạy như thế nào

Khi bạn gửi request tới coding assistant, nó tự động chèn thêm instruction vào message để dạy language model cách request một action. VD nó thêm dòng: "If you want to read a file, respond with ReadFile: name of file" (muốn đọc file thì trả lời ReadFile: tên file).

Flow đầy đủ:

  1. Bạn hỏi: "main.go có code gì?"
  2. Coding assistant thêm tool instructions vào request.
  3. Language model đáp: ReadFile: main.go.
  4. Coding assistant đọc file thật và gửi nội dung file ngược lại cho model.
  5. Language model đưa ra câu trả lời cuối dựa trên nội dung file.

Hệ thống này cho phép language model "đọc file", "viết code", "chạy lệnh" một cách hiệu quả — dù thực chất nó chỉ đang sinh ra các text response được định dạng cẩn thận. Người thực thi hành động là coding assistant, không phải model.

Vì sao tool use của Claude tạo khác biệt

Không phải language model nào cũng dùng tool giỏi ngang nhau. Claude series of models đặc biệt mạnh ở việc hiểu tool làm gìdùng chúng hiệu quả để hoàn thành task phức tạp. Sức mạnh này mang lại vài lợi ích then chốt cho Claude Code:

  • Tackles harder tasks (kham task khó hơn) — Claude kết hợp nhiều tool để xử việc phức tạp, và dùng được cả tool nó chưa từng thấy.
  • Extensible platform (nền tảng mở rộng được) — thêm tool mới vào Claude Code dễ dàng, và Claude tự thích ứng khi workflow thay đổi.
  • Better security (bảo mật tốt hơn) — Claude Code navigate codebase mà không cần indexing, nghĩa là thường không phải gửi toàn bộ codebase lên server ngoài.

Key takeaways

  • Coding assistant dùng language model để hoàn thành các task khác nhau.
  • Language model cần tool để kham hầu hết task lập trình thực tế.
  • Không phải LM nào dùng tool cũng giỏi như nhau.
  • Tool use mạnh của Claude mở ra bảo mật tốt hơn, tuỳ biến cao hơn, và độ bền (longevity) lâu hơn trong Claude Code.

Chính khả năng tool use này biến một model chỉ-sinh-text thành một coding assistant thực thụ: đọc được file, hiểu codebase, và tạo thay đổi có ý nghĩa cho dự án.

Áp dụng thực tế: hiểu "LM chỉ sinh text, assistant mới thực thi" giúp debug đúng chỗ khi Claude Code hành xử lạ: nếu nó hiểu sai việc cần làm thì đó là vấn đề model/prompt (context, mô tả); còn nếu nó muốn làm đúng nhưng thao tác trượt (đọc nhầm file, lệnh lỗi) thì đó là tầng tool/permission. Hai tầng, hai cách sửa. Về mặt Delivery, ý "better security nhờ không cần indexing" là điểm tôi hay nhấn khi thuyết phục khách Nhật: mã nguồn không bị đẩy nguyên khối lên server ngoài để build index — một khác biệt bảo mật cụ thể, không phải khẩu hiệu.

Bộ tool sẵn có trong Claude Code

Claude Code ship kèm một bộ tool tiêu chuẩn (built-in) — chính là "tay chân" mặc định. Claude tự chọn tool phù hợp cho từng bước:

Tool Công dụng
Agent Khởi chạy một subagent lo một task
Bash Chạy một shell command
Edit Sửa một file
Glob Tìm file theo một pattern
Grep Tìm trong nội dung file
LS Liệt kê file & thư mục
MultiEdit Nhiều sửa đổi cùng lúc
NotebookEdit Ghi vào một cell trong Jupyter notebook
NotebookRead Đọc một cell
Read Đọc một file
TodoRead Đọc một mục trong to-do đã tạo
TodoWrite Cập nhật danh sách to-do
WebFetch Lấy nội dung từ một URL
WebSearch Tìm kiếm web
Write Ghi ra một file

Nối với bài trước: những tool này không nằm sẵn trong model — Claude Code (harness) khai báo chúng cho model ở mỗi request; model đọc mô tả rồi quyết gọi cái nào. Nhớ cặp dễ nhầm: Glob = tìm file theo pattern, còn Grep = tìm nội dung bên trong file.

Claude Code phối hợp tool ra sao — 4 ví dụ thực chiến

Sức mạnh không nằm ở từng tool lẻ, mà ở việc Claude tự chuỗi (chain) nhiều tool để hoàn thành một task lớn. Bốn ví dụ minh hoạ:

1. Data analysis task (built-in + notebook)

Task: "Phân tích dữ liệu trong file streaming.csv" (tìm insight về user của một video streaming platform). Claude Code tự đi:

  1. Viết code trong một notebook để soi định dạng dữ liệu.
  2. Chạy code và xem kết quả.
  3. Thêm cell, chạy từng cái để dẫn dắt phân tích.
  4. Viết final summary.

→ Dùng NotebookEdit / NotebookRead + Bash + Read; Claude chạy thử → đọc kết quả → quyết bước tiếp (đúng agentic loop).

2. UI styling task (Playwright MCP Server)

Task: "Cải thiện design của app này, tập trung vào chat interface và header." Cắm thêm Playwright MCP Server = bộ tool cho phép Claude điều khiển browser. Claude Code: Open browser → Navigate tới app → Take a screenshot → Update styling.

→ Điểm học: sửa CSS "mù" (chỉ đọc code) thì được tạm ổn, nhưng cho Claude tự nhìn UI qua screenshot thì nó verify được bằng mắt — đúng tinh thần "add tools" ở Claude Code 101.

3. GitHub integration (GitHub MCP Server)

Task: "Review các thay đổi trong pull request." Cắm GitHub MCP Server = bộ tool cho Claude tương tác với GitHub (kể cả tạo comment). Claude Code: Đọc changes trong PR → đánh giá code quality / performance → viết summary report.

4. Đọc xuyên hạ tầng — soi luồng dữ liệu (Infrastructure-as-Code)

Ví dụ cảnh báo: một DynamoDB Table (userId, email, plansViewed, registrationDate) → một Lambda Function ghi dữ liệu ra một S3 Bucket dùng chung → được cả Internal Marketing Team External Marketing Partner truy cập. Vì hạ tầng được định nghĩa trong Terraform files (infrastructure-as-code) mà Claude Code đọc dễ dàng, Claude có thể lần theo luồng dữ liệu xuyên nhiều tầng (DB → code → cloud config) và chỉ ra rủi ro — VD partner ngoài đang chạm tới dữ liệu không nên chạm.

→ Điểm học lớn nhất: vì Claude Code đọc trực tiếp code + IaC, nó reason trên cả hệ thống, không chỉ một file đơn lẻ — thứ mà một công cụ chỉ-đọc-một-file không làm được.

Áp dụng thực tế: cách tôi đọc 4 ví dụ này = cùng một Claude Code, khác nhau ở bộ tool được trao. Built-in lo việc trong repo; MCP mở rộng ra ngoài (browser, GitHub, cloud). Với khách Nhật, ví dụ số 4 là điểm tôi hay dùng để định vị Claude Code như một reviewer hạ tầng: nó đọc được Terraform + Lambda + schema DB nên soi được luồng dữ liệu nhạy cảm (VD PII rò sang partner ngoài) — thứ review tay xuyên nhiều repo / nhiều dịch vụ rất dễ bỏ sót.

Context management — cho Claude đúng thứ nó cần

Một project có thể có hàng chục đến hàng trăm file, nhưng Claude chỉ cần đúng phần thông tin liên quan. Điểm phản trực giác: quá nhiều context không liên quan thực ra làm giảm hiệu năng của Claude. Vì vậy, biết cách dẫn Claude tới đúng file & tài liệu là kỹ năng cốt lõi — và đó là chỗ CLAUDE.md cùng cú pháp @ phát huy tác dụng.

Lệnh /init — sinh CLAUDE.md tự động

Khi mới mở Claude trong một project, chạy /init. Claude sẽ phân tích toàn bộ codebase để hiểu:

  • Mục đích & kiến trúc của project.
  • Các lệnh quan trọngfile trọng yếu (critical files).
  • Coding patterns và cấu trúc.

Xong, Claude viết một summary và ghi vào file CLAUDE.md. Khi Claude xin quyền tạo file, có 2 lựa chọn: Enter để duyệt từng thao tác ghi, hoặc Shift+Tab để cho Claude tự ghi file thoải mái suốt session (chế độ auto-accept).

CLAUDE.md — "system prompt" bền vững cho project

File CLAUDE.mdhai mục đích:

  1. Dẫn đường Claude qua codebase — chỉ ra lệnh quan trọng, kiến trúc, coding style.
  2. Đưa chỉ thị riêng/tùy biến cho Claude.

Mấu chốt: file này được nhét vào MỌI request — nên nó hoạt động như một system prompt bền vững cho riêng project này.

Claude nhận biết 3 file CLAUDE.md ở 3 vị trí:

File Phạm vi Chia sẻ với team?
CLAUDE.md Sinh bởi /init, commit vào source control ✅ Có — luật chung cả team
CLAUDE.local.md Chỉ thị & tùy biến cá nhân ❌ Không commit
~/.claude/CLAUDE.md Áp cho mọi project trên máy (máy cá nhân)

Thêm chỉ thị tùy biến + lệnh /memory

Muốn đổi cách Claude hành xử thì thêm chỉ thị vào CLAUDE.md. Ví dụ Claude comment quá nhiều → sửa file. Hai cách: edit CLAUDE.md trực tiếp trong editor, hoặc chạy /memory trong Claude Code để mở file ra sửa. Thêm một dòng như:

Use comments sparingly. Only comment complex code

Claude đọc file này đầu mỗi conversation, nên thay đổi có hiệu lực từ message kế tiếp.

⚠️ Freshness: video khoá học còn cho thấy shortcut cũ # ("memory mode") để ghi nhanh vào CLAUDE.md — shortcut này đã bị gỡ. Hiện tại dùng /memory hoặc sửa CLAUDE.md tay. (Claude Code đổi nhanh; đây là chỗ tài liệu cũ hay sai.)

Nhắc file bằng @

Khi cần Claude nhìn đúng một file, dùng @ + đường dẫn — nó tự chèn nội dung file đó vào request. Ví dụ hỏi về hệ thống auth:

How does the auth system work? @auth

Claude sẽ hiện danh sách file liên quan (auth-*) để chọn, rồi đưa file được chọn vào hội thoại.

Nhắc file ngay trong CLAUDE.md

Cũng dùng @ ngay trong CLAUDE.md để trỏ tới file luôn-liên-quan với nhiều phần của project. Ví dụ với file schema DB:

The database schema is defined in the @prisma/schema.prisma file.
Reference it anytime you need to understand the structure of data stored in the database.

Khi nhắc kiểu này, nội dung file tự vào mọi request → Claude trả lời về cấu trúc dữ liệu ngay, khỏi phải search + đọc lại schema mỗi lần.

Mẹo tương thích: repo đã có sẵn AGENTS.md (cho tool khác) thì không cần chép lại — đặt @AGENTS.mddòng đầu CLAUDE.md, Claude load nội dung đó trước, rồi viết chỉ thị riêng cho Claude bên dưới.

Áp dụng thực tế: chính CLAUDE.md của repo này (nguyenchau.dev) là ví dụ sống của bài — nó tự nhận là "điểm vào tin cậy" rồi trỏ sang các doc con (docs/learn.md, SEO.md) thay vì nhồi tất cả vào một file. Đó cũng là cách tôi quản context budget: CLAUDE.md + mọi @import đi vào mọi request nên tốn token mỗi lượt — tôi chỉ @ những file cross-cutting thật sự (schema DB, coding rule dùng khắp nơi), không import bừa file to. Về mặt Delivery, cặp CLAUDE.md (commit, luật chung) vs CLAUDE.local.md (cá nhân, không commit) đúng bằng ranh giới tôi vẫn kẻ giữa "chuẩn team""sở thích từng dev" — để không ai đẩy preference riêng vào luật chung của repo.

Thực thi thay đổi — screenshot, Planning Mode & Effort

Làm trên project có sẵn thì liên tục phải sửa đổi. Bài này gom mấy kỹ thuật để "ra lệnh" chính xác hơn: giao tiếp bằng hình ảnh (screenshot)điều khiển cách Claude suy nghĩ (Planning Mode + Effort).

Screenshot — chỉ tận mắt thay vì tả bằng lời

Cách nhanh nhất để nói "chỗ này này" với Claude là dán screenshot. Muốn sửa một mảng UI cụ thể, chụp màn hình rồi dán vào — Claude thấy đúng chỗ đang chỉ, khỏi tả lòng vòng.

  • Dán bằng Ctrl+Vkể cả trên macOS cũng là Ctrl+V, KHÔNG phải Cmd+V (đây là phím riêng để dán ảnh vào khung chat).
  • Dán xong, bảo Claude sửa đúng vùng đó.

Planning Mode — khảo sát & lập kế hoạch TRƯỚC khi ra tay

Với task phức tạp cần hiểu rộng nhiều chỗ trong codebase, bật Planning Mode để Claude thăm dò kỹ trước khi sửa.

Bật bằng: gõ /plan, hoặc bấm Shift+Tab để luân phiên qua các permission mode tới khi dòng chỉ báo dưới màn hình hiện "plan mode on". Thứ tự cycle: default (Manual) → acceptEdits (auto-accept) → plan (→ auto/bypassPermissions nếu đã bật) — nên từ default bấm 1 lần ra acceptEdits, 2 lần ra plan.

⚠️ Đừng lẫn: plan khác autongược hẳn bypassPermissions. plan = read-only, chỉ khảo sát + lập kế hoạch, không sửa gì; bypassPermissions = bỏ qua mọi câu hỏi permission (nguy hiểm). Plan là mode an toàn nhất, không phải bypass.

Ở plan mode Claude sẽ:

  1. Đọc nhiều file hơn trong project.
  2. Lập một plan chi tiết.
  3. Trình bày đúng ý định nó định làm.
  4. Chờ duyệt rồi mới làm.

→ Đây là cơ hội để review và bẻ lái nếu Claude bỏ sót gì hoặc chưa tính tới một tình huống.

💡 Tip: khi xem plan, bấm Ctrl+G để mở plan trong text editor, sửa tay cho chính xác rồi submit — Claude dùng đúng bản cuối được gửi.

Effort level — chỉnh Claude "nghĩ" sâu tới đâu

Mặc định Claude reason (suy luận) trước khi trả lời — thấy gợi ý kiểu "still thinking". Muốn xem thực sự nó nghĩ gì, bấm Ctrl+O để mở transcript viewer — xem chi tiết các bước reasoningtool execution (lưu ý: trên desktop/GUI phím có thể khác terminal; docs nói "shortcuts may vary by platform").

Độ sâu suy luận điều khiển được bằng effort level. Gõ /effort để xem mức hiện tại và chỉnh:

  • low — nhanh & rẻ hơn (ít token).
  • max — nghĩ lâu nhất, dành cho bài khó.
  • Mức mặc định tùy model + gói; /effort hiện đúng mức đang dùng.

Nếu chỉ muốn Claude nghĩ thêm cho ĐÚNG một prompt, thả từ khoá ultrathink vào câu đó. Nó báo Claude reason nhiều hơn turn này thôi, không đổi effort level của cả session.

⚠️ Freshness: video còn dùng các keyword "think / think harder" cũ để ép nghĩ nhiều — những keyword đó nay không còn tác dụng. Cách đúng hiện tại: chỉnh /effort, và dùng ultrathink cho từng prompt lẻ.

Planning vs Effort — hai loại "khó" khác nhau

Chỗ dễ lẫn nhất, nên tách bạch rõ — hai tính năng giải quyết hai loại độ phức tạp khác nhau:

Planning Mode = bề RỘNG Tăng Effort = chiều SÂU
Giải quyết Cần hiểu rộng codebase Cần nghĩ sâu một bài hóc
Hợp với Task nhiều bước; đổi nhiều file/component Logic phức tạp, debug bug khó, bài thuật toán

Kết hợp cả hai khi task vừa cần rộng vừa cần sâu. Nhưng nhớ: cả hai đều ngốn thêm token → cân nhắc chi phí.

Áp dụng thực tế: mental model tôi ghim: Planning = Claude nhìn RỘNG tới đâu; Effort = Claude nghĩ SÂU tới đâu — hai trục độc lập. Plan mode thực chất ép quy trình "chốt phương án trước khi code", giống việc tôi bắt review spec/design trước khi build; với khách Nhật thì cực hợp văn hoá "xác nhận rồi mới làm", tránh Claude (hay dev) lao vào sửa 10 file rồi mới lộ sai hướng. Effort là nút vặn ngân sách suy nghĩ: đừng để max chạy suốt (đốt token vô ích cho việc vặt) — chỉ vặn cao khi gặp bug logic thật sự hóc. Và Ctrl+O đọc reasoning là công cụ audit: khi Claude ra kết quả lạ, mở reasoning xem nó hiểu sai từ bước nào rồi sửa trúng chỗ đó, thay vì prompt lại từ đầu.

Điều hướng hội thoại — Escape, rewind, /compact, /clear

Nếu context management ở trên lo phần trước khi hỏi (nạp đúng file), thì phần này lo phần trong lúc hội thoại chạy: cách lái để Claude khỏi lan man và giữ context sạch. Bốn kỹ thuật.

Ngắt Claude bằng Escape

Claude đi sai hướng hoặc ôm quá nhiều việc một lúc → bấm Escape để dừng giữa response và bẻ lái. Rất hữu ích khi muốn Claude tập trung đúng một task. VD: nhờ viết test cho nhiều hàm mà Claude bắt đầu vẽ nguyên một kế hoạch đồ sộ cho tất cả → ngắt, yêu cầu nó làm từng hàm một.

Escape + Memories — dập lỗi lặp lại

Ứng dụng mạnh nhất của Escape: sửa lỗi Claude tái phạm qua nhiều conversation. Quy trình:

  1. Escape để dừng response hiện tại.
  2. Chạy /memory (hoặc sửa CLAUDE.md trực tiếp) — ghi lại cách làm đúng.
  3. Tiếp tục hội thoại với thông tin đã sửa.

→ Nhờ vậy các conversation sau trên project không lặp lại cùng lỗi đó. (Freshness: video dùng shortcut # cũ để thêm memory — đã gỡ, giờ dùng /memory.)

Rewind — tua lại hội thoại

Hội thoại dài thường tích context nhiễu (VD một màn debug lằng nhằng không còn cần cho task kế). Bấm Escape hai lần hoặc gõ /rewind → hiện mọi message đã gửi, cho nhảy về một điểm trước rồi tiếp tục từ đó. Kỹ thuật này giúp: giữ được context giá trị (Claude đã hiểu codebase), bỏ phần lịch sử gây nhiễu, và giữ Claude tập trung vào task hiện tại.

/compact — nén hội thoại, giữ cái cốt

Lệnh /compact tóm tắt toàn bộ lịch sử hội thoại nhưng giữ lại thông tin then chốt Claude đã học. Lý tưởng khi:

  • Claude đã nắm nhiều kiến thức về project.
  • Muốn tiếp tục các task liên quan.
  • Hội thoại đã dài nhưng chứa context quan trọng.

/clear — bắt đầu tinh khôi

Lệnh /clear mở một conversation mới với context sạch hoàn toàn. Hợp nhất khi:

  • Chuyển sang một task khác hẳn, không liên quan.
  • Context hiện tại có thể làm Claude rối cho task mới.

Vẫn quay lại hội thoại cũ được bằng /resume/clear không xoá nó khỏi session history.

/compact /clear
Làm gì Tóm tắt + giữ thông tin cốt Xoá sạch, khởi tạo context mới
Khi nào Task liên quan, cần giữ hiểu biết Task khác hẳn, không cần context cũ

Khi nào dùng cả cụm này: hội thoại dài context bị nhiễu, lúc chuyển task, khi Claude lặp lỗi, và trong project phức tạp cần giữ tập trung vào từng component. Đây không chỉ là tiện ích — chúng là công cụ thiết yếu để duy trì một session AI-assisted hiệu quả.

Áp dụng thực tế: cả bài này lẫn bài context management ở trên đều xoay quanh cùng một tài nguyên hữu hạn: context window. Cách tôi phân vai: /compact = "chốt biên bản cuộc họp rồi đi tiếp" (giữ kết luận, bỏ tranh luận thừa) — dùng khi làm chuỗi task liên quan; /clear = "đổi sang phòng họp mới" — khi nhảy sang việc chẳng dính dáng. Còn vòng Escape → /memory → tiếp tục chính là một vòng cải tiến liên tục: mỗi lần Claude sai một kiểu, tôi không sửa tay lần đó rồi thôi, mà ghi luật vào CLAUDE.md để lỗi không tái diễn — y hệt tinh thần retro/CAPA trong quản lý delivery: chặn lỗi tại nguồn, không chữa cháy lặp lại.

Hooks — chạy lệnh của bạn TRƯỚC/SAU khi Claude gọi tool

Hook cho phép bạn chạy command của riêng mình ngay trước hoặc ngay sau khi Claude định thực thi một tool. Cực hữu ích để tự động hoá workflow: chạy code formatter sau khi Claude sửa file, chạy test khi file đổi, hoặc chặn truy cập file cụ thể.

Hook chen vào luồng ở đâu

Nhớ lại luồng bình thường khi bạn nói chuyện với Claude Code:

  1. Query của bạn gửi tới model kèm tool definitions.
  2. Claude quyết dùng tool → trả về một formatted response.
  3. Claude Code thực thi tool đó và trả kết quả.

Hook chen vào ngay quanh bước 3 — cho bạn chạy code just-before hoặc just-after lúc tool được thực thi. Hai loại phổ biến nhất (còn loại khác ở lesson sau):

  • PreToolUse — chạy TRƯỚC khi tool được gọi.
  • PostToolUse — chạy SAU khi tool được gọi.

Khai báo hook ở đâu

Hook định nghĩa trong các Claude settings file — đúng bộ ba vị trí quen thuộc như CLAUDE.md:

File Phạm vi Chia sẻ team?
~/.claude/settings.json Global — mọi project (máy cá nhân)
.claude/settings.json Project ✅ commit, chia sẻ team
.claude/settings.local.json Project — cá nhân ❌ không commit

Viết tay trong file, hoặc dùng lệnh /hooks ngay trong Claude Code.

⚠️ Đừng lẫn: hook khai trong settings.json, KHÁC với chỉ thị tự nhiên đặt trong CLAUDE.md. Cùng bộ ba vị trí (global / project / project-local) nhưng khác file, khác vai: CLAUDE.mdlời dặn cho model; settings.jsoncấu hình tất định cho harness.

PreToolUse — chạy TRƯỚC, chặn được

"PreToolUse": [
  {
    "matcher": "Read",
    "hooks": [
      { "type": "command", "command": "node /home/hooks/read_hook.js" }
    ]
  }
]

matcher chỉ định loại tool nào bị nhắm (ở đây là Read). Trước khi tool Read chạy, command được gọi. Command nhận được chi tiết về tool call Claude định thực hiện, rồi bạn có 2 lựa chọn:

  • Cho phép thao tác chạy bình thường.
  • Block tool call và gửi một error message ngược lại cho Claude.

PostToolUse — chạy SAU, KHÔNG chặn được

"PostToolUse": [
  {
    "matcher": "Write|Edit",
    "hooks": [
      { "type": "command", "command": "node /home/hooks/edit_hook.js" }
    ]
  }
]

matcher "Write|Edit" nhắm nhiều tool cùng lúc (Write HOẶC Edit — dấu | như regex). Vì tool call đã xảy ra rồi, PostToolUse KHÔNG block được thao tác. Nhưng nó vẫn:

  • Chạy follow-up operations (VD format lại file vừa sửa).
  • Cấp feedback thêm cho Claude về tool use đó.

Dựng một hook — 4 bước

Hook chặn/kiểm soát tool call trước hoặc sau khi nó thực thi → kiểm soát chi tiết Claude được và không được làm gì. Tạo một hook gồm 4 bước:

  1. Chọn PreToolUse hay PostToolUse — Pre ngăn được tool call chạy; Post chạy sau khi tool đã dùng.
  2. Xác định loại tool call cần canh — chỉ rõ đúng tool nào sẽ kích hoạt hook (chính là matcher).
  3. Viết một command nhận tool call — command này nhận JSON data về tool call đề xuất qua standard input (stdin).
  4. (Nếu cần) command trả feedback cho Claudeexit code của command báo Claude allow hay block thao tác.

💡 Muốn biết chính xác tool nào đang có trong setup hiện tại (để đặt matcher)? Hỏi thẳng Claude liệt kê — đặc biệt cần thiết vì danh sách tool thay đổi khi bạn thêm custom MCP server.

Dữ liệu tool call — JSON qua stdin

Khi hook command chạy, Claude gửi một khối JSON qua standard input mô tả tool call đề xuất:

{
  "session_id": "2d6a1e4d-6...",
  "transcript_path": "/Users/sg/...",
  "hook_event_name": "PreToolUse",
  "tool_name": "Read",
  "tool_input": {
    "file_path": "/code/queries/.env"
  }
}

Command đọc JSON từ stdin → parse → quyết định allow/block dựa trên tool_nametool_input. (Ví dụ trên: Claude định Read file /code/queries/.env.)

Exit code — allow hay block

Command giao tiếp ngược lại với Claude bằng exit code:

Exit code Ý nghĩa
0 Ổn — cho phép tool call chạy tiếp
2 Block tool call (chỉ PreToolUse)

Khi exit 2 trong một PreToolUse hook, mọi error message ghi ra standard error (stderr) sẽ được gửi tới Claude như feedback — giải thích vì sao thao tác bị chặn.

Ví dụ: chặn Claude đọc file .env

Use case kinh điển: ngăn Claude đọc file nhạy cảm như .env. Bản hiện hành của khoá chỉ chặn tool Read — matcher "Read", hook đọc tool_input.file_path:

  • Path an toàn → exit 0 (cho qua).
  • Path chứa .env → ghi lý do ra stderr + exit 2 → Claude bị chặn và nhận được lời giải thích.
"PreToolUse": [
  {
    "matcher": "Read",
    "hooks": [ { "type": "command", "command": "node $PWD/hooks/read_hook.js" } ]
  }
]
// hooks/read_hook.js
process.stdin.setEncoding("utf8");
let input = "";
process.stdin.on("data", (d) => (input += d));
process.stdin.on("end", () => {
  const toolArgs = JSON.parse(input);
  const readPath = toolArgs.tool_input?.file_path || "";
  if (readPath.includes(".env")) {
    console.error("You cannot read the .env file"); // stderr -> Claude thấy
    process.exit(2);                                // exit 2 = chặn
  }
  process.exit(0);
});

⚠️ Vì sao chỉ Read? (điểm dễ nhầm — video cũ khác text mới) Video của khoá bản cũ có kèm Grep; bản text hiện hành đã bỏ, chỉ còn Read. Lý do: mỗi tool gửi input shape khác nhauRead gửi { file_path }; Grep gửi { pattern, path } với paththư mục tìm kiếm, không phải file; Bash gửi { command }. Nên một check trên file_path bắt được Read nhưng không chặn được grep API_KEY toàn project hay cat .env trong Bash. Muốn phủ đủ: hoặc viết matcher riêng cho từng tool (soi đúng field của nó), hoặc — gọn hơn — dùng permissions.deny với rule như "Read(**/.env)" (áp đồng đều trên mọi tool). Xem hooks guide.

Áp dụng thực tế: đây là lúc "hook = guardrail tất định" trở nên cụ thể: chốt chặn KHÔNG nằm ở việc dặn Claude ("đừng đọc .env") — mà ở một script bên ngoài đọc tool_input.file_path rồi exit 2. Model có thể lơ lời dặn, nhưng không vượt được exit code. Hai điểm tôi luôn soi khi review một PreToolUse guard: (1) input shape của mỗi tool khác nhau → matcher = attack surface. Một hook check file_path chỉ chặn Read; grep API_KEY toàn project (Grep dùng path = thư mục) hay cat .env (Bash dùng command) vẫn lọt. Vì thế với thứ phải chặn tuyệt đối như secret, tôi không cố ghép nhiều matcher hook (dễ sót một shape) mà dùng permissions.deny "Read(**/.env)" — rule áp đồng đều mọi tool, hook chỉ là lớp bổ trợ/feedback; (2) thông điệp stderr phải nói rõ lý do để Claude tự đổi hướng thay vì thử lại mù. Với khách Nhật, "chặn ngay tại tầng harness + log lại" là câu trả lời gọn cho "làm sao đảm bảo AI không chạm dữ liệu mật?" — không phải niềm tin, mà là cơ chế.

Ứng dụng thực tế của hook

  • Code formatting — tự format file sau khi Claude sửa.
  • Testing — tự chạy test khi file thay đổi.
  • Access control — chặn Claude đọc/sửa file cụ thể.
  • Code quality — chạy linter/type checker rồi feedback cho Claude.
  • Logging — ghi lại file nào Claude access/modify.
  • Validation — kiểm naming convention / coding standard.

⭐ Insight cốt lõi: PreToolUse = kiểm soát Claude ĐƯỢC LÀM GÌ (control what Claude can do); PostToolUse = tăng cường thứ Claude ĐÃ LÀM (enhance what Claude has done).

Áp dụng thực tế: hook là guardrail tất định — nó luôn chạy, không phụ thuộc Claude có "nhớ" hay không (khác chỉ thị mềm trong CLAUDE.md mà model có thể lơ). Cách tôi phân vai với hai loại: PreToolUse là chốt bảo vệ — vì chỉ nó block được, tôi đặt ở đây mọi thứ phải chặn tại nguồn: cấm đọc .env/secret, cấm sửa file sinh tự động (bài học repo này: đừng để build churn lọt vào commit), cấm rm -rf bậy. PostToolUse là chốt chuẩn hoá — nó không cứu được thao tác đã lỡ, nên đừng đặt "bảo vệ" ở đây; hợp nhất là auto-format/lint/typecheck + log để mọi thay đổi của Claude ra đúng chuẩn team mà không ai phải nhớ chạy tay. Về mặt Delivery, đây là "policy-as-code": thay vì viết một tài liệu "nhớ format trước khi push" rồi cầu mong đội tuân, tôi mã hoá luật vào settings.json commit chung — máy enforce, người khỏi cãi.

Gotchas — bảo mật hook & chia sẻ settings

Sau khi chạy npm run setup, trong .claude/hai file settings: settings.example.json (template, commit) và settings.local.json (sinh ra, cá nhân không commit). Vì sao tách ra? Do một khuyến nghị bảo mật hook trong docs Claude Code.

Khuyến nghị: dùng absolute path (KHÔNG dùng relative path) cho script hook. Lý do bảo mật: giảm path interceptionbinary planting attack — kẻ xấu đặt một script/binary giả trùng tên vào một thư mục (trên PATH hoặc thư mục tương đối) để hook chạy nhầm nó. Absolute path khoá cứng đúng file cần chạy.

Nhưng absolute path làm khó việc share settings.json: đường dẫn tuyệt đối tới script trên máy bạn khác máy người khác (mỗi người để project ở thư mục khác nhau).

Cách project này giải: settings.example.json đặt placeholder $PWD ở chỗ đường dẫn script. Khi chạy npm run setup: (1) cài dependencies, (2) chạy scripts/init-claude.js — script này thay $PWD bằng absolute path tới project trên máy bạn, copy settings.example.json rồi đổi tên thành settings.local.json.

→ Nhờ vậy vừa share được settings (commit template có $PWD), vừa giữ absolute path như khuyến nghị.

Áp dụng thực tế: đây là pattern "template + machine-specific generator" — commit cái khuôn (settings.example.json), sinh cái thực thi theo từng máy (settings.local.json, không commit — đúng cặp CLAUDE.local.md/settings.local.json). Điểm architect: bảo mật (absolute path) và tính chia-sẻ-được kéo ngược nhau, init-claude.js là cầu nối. Và bản thân generator ấy phải portable: khi tôi chạy trên Windows, $PWD = D:\... (dấu \ là escape trong JSON ⇒ vỡ JSON.parse) lại còn có dấu cách trong path ⇒ lệnh node <path> đứt giữa chừng — phải forward-slash + quote path mới chạy. Bài học: một khuyến nghị bảo mật đúng vẫn có thể tạo bug vận hành nếu bỏ qua khác biệt OS. Với khách Nhật, "hook script luôn absolute path" là một gạch đầu dòng supply-chain hardening cụ thể (chống binary planting), không phải khẩu hiệu.

Hai hook thực chiến — TypeScript check & chống query trùng

Hook giải được vài điểm yếu kinh điển của AI-assisted dev trên project lớn. Hai ví dụ dưới đây chính là hooks/tsc.jshooks/query_hook.js trong project thực hành.

1. TypeScript type-checking hook (PostToolUse)

Vấn đề gốc: khi Claude đổi một function signature, nó thường không cập nhật hết call site. VD nhờ thêm param verbose vào một hàm trong schema.ts → Claude sửa được definition nhưng quên call site ở main.ts → sinh type error mà Claude không bắt ngay.

Giải: một PostToolUse hook chạy TypeScript compiler sau mỗi lần sửa file:

  1. Chạy tsc --noEmit để kiểm type error.
  2. Capture lỗi tìm được.
  3. Feed lỗi ngược cho Claude ngay.
  4. Prompt Claude đi sửa các file khác (call site).

→ Áp dụng cho mọi typed language có type checker. Ngôn ngữ untyped thì thay bằng automated tests.

2. Query duplication prevention hook (Agent SDK)

Vấn đề: project lớn nhiều query → Claude đôi khi viết trùng chức năng thay vì tái dùng code có sẵn — nhất là khi task phức tạp nhiều bước mà thao tác DB chỉ là một mảnh. VD "tạo Slack integration cảnh báo đơn pending > 3 ngày" → Claude viết query mới thay vì dùng getPendingOrders() đã tồn tại.

Giải: một review process:

  1. Trigger khi Claude sửa file trong ./queries.
  2. Khởi chạy một instance Claude Code THỨ HAI (programmatically, qua Agent SDK).
  3. Nhờ instance thứ hai review thay đổi + kiểm query tương tự đã có.
  4. Nếu trùng → feed feedback cho instance gốc.
  5. Prompt Claude bỏ bản trùng, dùng lại code có sẵn.

Cân nhắc (trade-offs):

TypeScript hook Query duplication hook
Chi phí Nhẹ, chạy nhanh Nặng — mỗi lần sửa ./queries khởi chạy 1 Claude mới (tốn time + API usage)
Lời khuyên Bật thoải mái Chỉ monitor thư mục quan trọng để giảm overhead

Cả hai dùng Agent SDK để một Claude review công việc của Claude khác — "AI reviews AI".

Nguyên tắc mở rộng (áp cho project của bạn):

  • Dùng compiler/linter output làm feedback tức thì.
  • Dựng code review bằng AI instance riêng.
  • Focus monitor thư mục giá trị cao (nơi tính nhất quán quan trọng nhất).
  • Cân bằng lợi ích tự động hoá vs chi phí hiệu năng.

Áp dụng thực tế: hai hook này là hai archetype tôi luôn tách bạch. tsc.jsdeterministic gate — trong sandbox nó gọi TS compiler API (ts.createProgram + noEmit), lỗi type là ground truth, đúng/sai không cãi; loại này tôi bật rộng tay vì rẻ và chắc. query_hook.jsprobabilistic gate — nó query() qua Agent SDK để một Claude khác phán đoán trùng lặp; mạnh cho thứ không có compiler (trùng ngữ nghĩa, style), nhưng tốn tiền + latency + có thể sai, nên trong sandbox nó bị process.exit(0) tắt sẵn cho khỏi đốt credit. Quy tắc của tôi: việc nào có ground truth (type/test/lint) thì dùng cổng tất định; việc mờ mới nhờ AI, và luôn giới hạn ở thư mục critical để chi phí không phình. Với Delivery, đây là "shift-left": bắt lỗi ngay lúc sửa (call site lệch, query trùng) thay vì để lộ ở review/CI muộn hơn.

Còn hook nào nữa? Toàn bộ event + mẹo soi input

Pre/PostToolUse chỉ là hai loại phổ biến. Claude Code còn nhiều hook event phủ toàn bộ vòng đời session:

Hook event Chạy khi
Notification Claude Code gửi notification — khi cần xin quyền dùng tool, hoặc sau khi idle 60 giây
Stop Claude Code trả lời xong
SubagentStop Một subagent (hiện là "Task" trong UI) chạy xong
PreCompact Trước một thao tác compact (thủ công hoặc tự động)
UserPromptSubmit User submit prompt, TRƯỚC khi Claude xử lý
SessionStart Bắt đầu hoặc resume một session
SessionEnd Một session kết thúc

Chỗ rối: cấu trúc stdin đổi theo 2 trục:

  1. Theo loại hook (PreToolUse, PostToolUse, Notification, Stop…) — mỗi loại field khác nhau.
  2. Theo tool được gọi (chỉ với Pre/Post) — tool_input khác nhau tuỳ tool.

VD một PostToolUse canh TodoWrite (tool Claude dùng để quản to-do) — có tool_name, tool_input.todos, và thêm tool_response:

{
  "hook_event_name": "PostToolUse",
  "tool_name": "TodoWrite",
  "tool_input": { "todos": [{ "content": "write a readme", "status": "pending", "id": "1" }] },
  "tool_response": { "oldTodos": [], "newTodos": [{ "content": "write a readme", "status": "pending", "id": "1" }] }
}

Còn một Stop hook thì không có tool_name/tool_input, chỉ:

{ "hook_event_name": "Stop", "stop_hook_active": false }

→ Shape khác nhau nhiều nên bạn có thể không biết trước command sẽ nhận cấu trúc gì.

Mẹo: hook "soi input". Gắn tạm một hook matcher: "*" chỉ để ghi input ra file:

"PostToolUse": [
  { "matcher": "*", "hooks": [ { "type": "command", "command": "jq . > post-log.json" } ] }
]

Nó ghi nguyên input vào post-log.json → mở ra xem chính xác dữ liệu nào được feed vào → viết command đúng field. (Chính là các dòng pre-log.json/post-log.json trong settings.example.json của sandbox.)

Áp dụng thực tế: mấy event ngoài-tool này mở ra tự động hoá cả vòng đời phiên, không chỉ tool call: SessionStart nạp context/env đầu phiên; UserPromptSubmit chèn context hoặc chặn prompt trước khi Claude đọc; Stop ping tôi / chạy check cuối khi Claude xong; PreCompact lưu state trước khi lịch sử bị nén; Notification báo desktop khi Claude đang chờ tôi; SubagentStop gom kết quả Task. Nguyên tắc tôi ghim: chọn event HẸP nhất cho đúng tín hiệu cần (đừng nhét mọi thứ vào PostToolUse matcher *). Và kỷ luật quan trọng nhất bài này dạy: đừng đoán schema — log nó ra rồi đọc. Cùng phản xạ debug với bài "JSON qua stdin", nay tổng quát hoá: hợp đồng input là theo-từng-event, nên jq . > log.json quan sát trước, code sau là bước bắt buộc, không phải tuỳ chọn.

Agent SDK — chạy Claude Code bằng code

Agent SDK cho phép chạy Claude Code programmatically từ app/script của bạn — có cho TypeScript và Python. Nó trao đúng agent loop mà CLI dùng (đọc file, sửa file, tool use) nhưng dưới quyền điều khiển của bạn. Đây chính là thứ query_hook.js (bài "hai hook thực chiến") dùng để một Claude review một Claude khác.

⚠️ Freshness — tên package đã đổi: video khoá dùng tên cũ không còn chạy. Package hiện hành là @anthropic-ai/claude-agent-sdk. Đừng nhầm với @anthropic-ai/claude-code — đó là CLI, không import được.

Cài đặt

mkdir sdk-demo && cd sdk-demo
npm init -y
npm install @anthropic-ai/claude-agent-sdk

Ví dụ tối giản

Tạo index.mjs:

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

const prompt = "List the files in the current directory";

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

Chạy node index.mjs → thấy một stream JSON messages — đúng các conversation event như trong CLI: tool call, tool result, và text của Claude. (query() trả về một async iterator, for await để duyệt.)

Giới hạn tool — allowedTools

Mặc định SDK có full tool set. Thu hẹp bằng allowedTools:

for await (const message of query({
  prompt,
  options: { allowedTools: ["Read", "Glob"] },
})) {
  // ...
}

Đây là bản SDK của flag --allowedTools trên CLI (và cùng tinh thần allowed_tools trong GitHub Actions).

Còn gì nữa

SDK làm được mọi thứ CLI làm: custom system prompts, MCP servers, hooks, subagents, và session resumption. Xem Agent SDK documentation cho reference đầy đủ.

Áp dụng thực tế: SDK là cái seam biến Claude Code từ công cụ tương tác thành building block nhúng được vào hệ thống của mình. Ba góc tôi ghim: (1) vòng khép kín với bài hooksquery_hook.js nhúng thẳng SDK bên trong một hook, tức Claude Code gọi Claude Code; "AI reviews AI" chỉ là API này, không có gì huyền bí; (2) allowedTools = một cần gạt least-privilege dùng khắp nơi — CLI --allowedTools, GitHub Actions allowed_tools, SDK options.allowedTools; học một lần, và luôn thu hẹp tool cho tác vụ tự động (một script chỉ cần đọc thì cho đúng ["Read","Glob"], đừng để full set); (3) kỷ luật chi phí — mỗi query() là một lượt model tính tiền; một hook gọi query() mỗi lần edit (như query_hook) nhân chi phí âm thầm, nên production phải bọc rate/spend guard. Và cái bẫy tên package claude-code (CLI) vs claude-agent-sdk (thư viện) đúng bằng comment cảnh báo trong sdk.ts của sandbox — import nhầm là fail ngay.

Custom command — tự đóng gói slash command của riêng mình

Claude Code có sẵn nhiều built-in command (gõ / để xem). Nhưng ta còn tự tạo được custom command để tự động hoá các task lặp đi lặp lại hay chạy.

Tạo một custom command

Chỉ cần dựng đúng cấu trúc thư mục trong project:

  1. Tìm thư mục .claude trong project.
  2. Tạo thư mục con commands bên trong.
  3. Tạo một file Markdown đặt tên theo command muốn có (VD audit.md).

Tên file = tên command: audit.md sinh ra lệnh /audit. Claude Code tự nhận ngay — KHÔNG cần restart.

Ví dụ: lệnh /audit

Một command soi lỗ hổng dependency, làm 3 việc:

  1. Chạy npm audit — tìm package đã cài có lỗ hổng.
  2. Chạy npm audit fixáp update.
  3. Chạy test — verify update không làm vỡ gì.

Nội dung file chỉ là văn bản chỉ thị (prompt) dặn Claude làm 3 bước đó.

Command có tham số — $ARGUMENTS

Custom command nhận argument qua placeholder $ARGUMENTS → linh hoạt, tái dùng được. VD write_tests.md:

Write comprehensive tests for: $ARGUMENTS

Testing conventions:
* Use Vitest with React Testing Library
* Place test files in a __tests__ directory in the same folder as the source file
* Name test files as [filename].test.ts(x)
* Use @/ prefix for imports

Coverage:
* Test happy paths
* Test edge cases
* Test error states

Chạy: /write_tests the use-auth.ts file in the hooks directory → phần chuỗi sau lệnh được thế vào $ARGUMENTS. Argument không nhất thiết là file path — bất kỳ string nào để cấp context/direction cho task.

Bốn lợi ích

  • Automation — workflow lặp → gói thành một lệnh.
  • Consistency — đảm bảo cùng các bước mỗi lần.
  • Context — nhét sẵn chỉ thị + convention của project.
  • Flexibility — dùng argument cho input khác nhau.

Đặc biệt hợp cho workflow riêng của dự án: chạy test suite, deploy code, hay sinh boilerplate theo convention của team.

Ngoài project-level .claude/commands/, còn có user-level ~/.claude/commands/ cho lệnh cá nhân dùng xuyên mọi project — đúng cặp phân cấp như CLAUDE.md. (Khoá gốc không nhắc; biết để linh hoạt.)

Áp dụng thực tế: custom command = đóng gói một SOP thành một nút bấm. Đặt cạnh hai cơ chế đã học: hook là việc bắt buộc, tất định (luôn chạy); custom commandquy trình gọi-khi-cần, lại nhận được tham số. Vì file nằm trong .claude/commands/ commit được vào repo, cả team dùng chung một bộ lệnh — y như cách chia sẻ CLAUDE.md/hooks. Tôi hay dùng để chuẩn hoá những thứ đội dễ làm lệch tay: một /review bám đúng checklist, một /deploy-check chạy đúng thứ tự bước trước khi ship. Nó biến "tài liệu quy trình mà không ai đọc" thành "một lệnh ai cũng gõ".

Thêm MCP server vào Claude Code — thực hành với Playwright

Ở phần "4 ví dụ thực chiến" ta đã thấy MCP mở rộng bộ tool; giờ là cách thực sự thêm một MCP server. Lấy Playwright MCP (cho Claude điều khiển web browser) làm ví dụ — mở ra nhiều khả năng cho workflow web.

Cài Playwright MCP server

Chạy lệnh sau trong terminal — KHÔNG phải trong Claude Code:

claude mcp add playwright npx @playwright/mcp@latest

Lệnh làm 2 việc: (1) đặt tên server là playwright; (2) cấp command khởi chạy server local trên máy.

Pre-approve permission — bớt bị hỏi mỗi lần

Lần đầu dùng tool của một MCP server, Claude hỏi phép mỗi lần. Ngán thì pre-approve server: mở file .claude/settings.local.json và thêm server vào mảng allow:

{
  "permissions": {
    "allow": ["mcp__playwright"],
    "deny": []
  }
}

⚠️ Chú ý HAI dấu gạch dưới trong mcp__playwright. Nhờ đó Claude dùng tool Playwright khỏi phải hỏi mỗi lần.

Nối bài trước: settings.local.json là file cá nhân, KHÔNG commit (giống CLAUDE.local.md) — nên pre-approve này chỉ áp cho máy mình, không đẩy quyết định "bỏ chốt permission" lên cả team.

Ví dụ thực chiến — Claude tự cải thiện prompt sinh UI

Thay vì tự tay test rồi tinh chỉnh prompt, giao cho Claude một vòng khép kín:

  1. Mở browser và navigate tới app.
  2. Generate một test component.
  3. Soi visual styling + code quality.
  4. Update chính prompt sinh code dựa trên quan sát.
  5. Test prompt mới bằng một component khác.

Prompt mẫu:

"Navigate to localhost:3000, generate a basic component, review the styling, and update the generation prompt at @src/lib/prompts/generation.tsx to produce better components going forward."

Claude dùng browser tools tương tác với app, xem output thật, rồi sửa file prompt để lần sau sinh component đẹp hơn.

Kết quả

Thay vì mãi gradient tím-xanh generic + pattern Tailwind mặc định, Claude update prompt để khuyến khích: warm sunset gradients (orange→pink→purple), ocean depth (teal→emerald→cyan), asymmetric design + overlapping elements, spacing & layout phá cách.

⭐ Lợi thế then chốt: Claude thấy được output hình ảnh THẬT, không chỉ code → quyết định về styling sát thực tế hơn hẳn.

MCP ecosystem — không chỉ Playwright

Playwright chỉ là một ví dụ. Hệ MCP còn có server cho: database interactions, API testing & monitoring, file system operations, cloud service integrations, dev tool automation. Chọn server hợp nhu cầu → biến Claude từ "code assistant" thành development partner tương tác cả hệ công cụ của mình.

Áp dụng thực tế: insight lớn nhất trùng đúng mạch "verify bằng mắt" đã gặp: cho Claude thấy kết quả thật (screenshot/browser) thì nó tự sửa được, thay vì đoán mù qua code. Nhưng tôi luôn kèm hai chốt: (1) mỗi MCP server ăn context (bài Claude Code 101 đã cảnh báo) — cắm cái nào thật cần, không cắm bừa; (2) pre-approve mcp__playwrightmở nguyên quyền một server điều khiển browser — tiện nhưng để trong settings.local.json cá nhân là đúng, đừng biến "bỏ chốt" thành mặc định của cả repo.

Tích hợp GitHub — Claude Code như một "đồng đội tự động"

Từ đầu khoá tới giờ Claude Code chạy local trong terminal. Phần này mở ra hướng khác: official GitHub integration cho Claude Code chạy bên trong GitHub Actions — tức Claude làm việc trên hạ tầng của GitHub, tự động phản hồi issue/PR mà không cần bạn mở máy. Có hai workflow chính: mention support cho issue & PR, và automatic pull request reviews.

Cài đặt — /install-github-app

Chạy /install-github-app ngay trong Claude. Nó dẫn qua ba bước:

  1. Install the Claude Code app trên GitHub.
  2. Add your API key.
  3. Tự sinh một pull request chứa sẵn các file workflow.

PR sinh ra thêm hai GitHub Actions vào repo. Merge PR đó xong → có các file workflow trong thư mục .github/workflows.

Hai default GitHub Actions

1. Mention Action — mention Claude ở bất kỳ issue/PR nào bằng @claude. Khi được nhắc, Claude:

  • Analyze request và lập task plan.
  • Thực thi task với full access to your codebase.
  • Phản hồi kết quả trực tiếp trong issue/PR.

2. Pull Request Actionmỗi khi bạn tạo một PR, Claude tự động:

  • Review các thay đổi.
  • Phân tích impact của thay đổi.
  • Post một báo cáo chi tiết lên PR.

Tuỳ biến workflow

Sau khi merge PR khởi tạo, chỉnh file workflow cho hợp project. Bốn thứ hay tuỳ biến:

a) Project Setup — thêm bước chuẩn bị môi trường trước khi Claude chạy:

- name: Project Setup
  run: |
    npm run setup
    npm run dev:daemon

b) Custom Instructions — cấp context về setup của project:

custom_instructions: |
  The project is already set up with all dependencies installed.
  The server is already running at localhost:3000. Logs from it
  are being written to logs.txt. If needed, you can query the
  db with the 'sqlite3' cli. If needed, use the mcp__playwright
  set of tools to launch a browser and interact with the app.

c) MCP Server Configuration — cắm MCP server để trao thêm năng lực:

mcp_config: |
  {
    "mcpServers": {
      "playwright": {
        "command": "npx",
        "args": ["@playwright/mcp@latest", "--allowed-origins", "localhost:3000;cdn.tailwindcss.com;esm.sh"]
      }
    }
  }

d) Tool Permissions — ⭐ chỗ dễ vấp nhất. Khi chạy trong GitHub Actions, bắt buộc liệt kê tường minh MỌI tool được phép:

allowed_tools: "Bash(npm:*),Bash(sqlite3:*),mcp__playwright__browser_snapshot,mcp__playwright__browser_click,..."

⚠️ Khác local: trong GitHub Actions KHÔNG có shortcut permission. Ở local bạn pre-approve cả server bằng mcp__playwright (bài trước); nhưng trong Actions từng tool của từng MCP server phải liệt kê riêng lẻ (VD mcp__playwright__browser_snapshot, mcp__playwright__browser_click…).

Best practices

  • Bắt đầu từ default workflow, tuỳ biến dần dần.
  • Dùng custom instructions để cấp context riêng của project.
  • Explicit về tool permission khi dùng MCP server.
  • Test với task đơn giản trước rồi mới tới task phức tạp.
  • Cân nhắc nhu cầu riêng của project khi thêm bước.

Áp dụng thực tế: đặt cạnh hook (bài Claude Code 101) và custom command ở trên, GitHub integration là tầng tự động thứ ba — nhưng khác chỗ chạy trên cloud, event-driven từ GitHub (issue/PR), không phải trên máy tôi. Repo này deploy kiểu push-main → Cloudflare Pages, nên tôi đọc Pull Request Action như một reviewer gác cổng chạy trước khi merge — đúng vai trò tôi muốn ở một CI review. Hai chốt tôi luôn nhấn với khách Nhật: (1) allowed_tools liệt kê tường minh chính là least-privilege — bot đứng ngoài tầm mắt, cầm full codebase access + API key (lưu dạng secret), nên "cho phép cả bộ" là rủi ro; ép khai từng tool là một security control, không phải phiền hà; (2) "test task đơn giản trước" = tôi cho bot review vài PR nhỏ để canh giọng/độ nhiễu trước khi thả nó gác toàn bộ repo.

Từ khoá cần thuộc

🔴 Core: coding assistant (hệ thống dùng LM, không chỉ viết code) · quy trình Gather context → Formulate a plan → Take an action + iterate · bước 1 & 3 tương tác thế giới ngoài (đọc file, fetch docs, chạy lệnh, sửa code) · Language Model + Set of tools (2 thành phần trong Assistant) · Tool Use Challenge (LM tự thân chỉ text-in / text-out, không đọc file/chạy lệnh) · tool use (assistant chèn instruction dạy LM request action) · flow 5 bước (ReadFile: main.go = LM nói, assistant làm rồi trả nội dung ngược lại) · Claude series đặc biệt mạnh tool use · better security = navigate codebase không cần indexing (không gửi cả codebase ra ngoài) · built-in tools (harness khai báo cho model mỗi request): Agent · Bash · Edit · Glob · Grep · LS · MultiEdit · NotebookEdit · NotebookRead · Read · TodoRead · TodoWrite · WebFetch · WebSearch · Write · Glob = tìm file theo pattern vs Grep = tìm nội dung trong file · MCP server mở rộng bộ tool (Playwright MCP = control browser; GitHub MCP = interact with GitHub) · Claude Code đọc IaC (Terraform)reason xuyên cả hệ thống, không chỉ 1 file · context management (quá nhiều context không liên quan → giảm hiệu năng) · /init (phân tích toàn codebase → sinh CLAUDE.md) · CLAUDE.md nhét vào MỌI request (system prompt bền vững cho project) · 3 vị trí: CLAUDE.md (commit, share team) / CLAUDE.local.md (cá nhân, không commit) / ~/.claude/CLAUDE.md (mọi project trên máy) · @path = tự chèn nội dung file vào request · @ trong CLAUDE.md = file cross-cutting tự vào mọi request (VD @prisma/schema.prisma) · screenshot (dán Ctrl+V, kể cả macOS — không Cmd+V) chỉ đúng vùng UI · Planning Mode (/plan hoặc Shift+Tab 2 lần): đọc nhiều file → plan chi tiếtchờ duyệt trước khi sửa · effort level (/effort: low nhanh/rẻ ↔ max nghĩ lâu nhất) · ultrathink = nghĩ thêm 1 prompt lẻ (không đổi effort session) · Planning = bề RỘNG (nhiều file/bước) vs Effort = chiều SÂU (logic/debug/thuật toán) · cả hai tốn thêm token · Escape = ngắt Claude giữa chừng để bẻ lái · Escape 2 lần / /rewind = tua về điểm trước, dọn context nhiễu · /compact = tóm tắt + giữ cốt (task liên quan) vs /clear = context sạch mới (task khác hẳn) · /resume = quay lại hội thoại cũ (/clear không xoá nó) · custom command (tự tạo slash command) · .claude/commands/<name>.md (Markdown; tên file = tên lệnh, VD audit.md/audit; tự nhận KHÔNG cần restart) · $ARGUMENTS (placeholder nhận tham số — string bất kỳ, không chỉ file path) · thêm MCP server: claude mcp add playwright npx @playwright/mcp@latest (chạy trong terminal, KHÔNG trong Claude Code) · pre-approve permission trong .claude/settings.local.jsonpermissions.allow: ["mcp__playwright"] (HAI gạch dưới mcp__) · Playwright MCP = control browser; lợi thế = Claude thấy visual output THẬT, không chỉ code · official GitHub integration = Claude Code chạy trong GitHub Actions (cloud, không chỉ local) · /install-github-app (3 bước: install app + add API key + tự sinh PR chứa file workflow) · file workflow ở .github/workflows (sau khi merge PR) · Mention Action (@claude trong issue/PR → analyze + task plan → thực thi với full codebase access → phản hồi tại chỗ) · Pull Request Action (tạo PR → review changes → analyze impact → post báo cáo) · allowed_tools phải liệt kê tường minh MỌI tool · KHÔNG có shortcut permission trong GitHub Actions (khác local — từng tool của từng MCP server phải liệt kê riêng, VD mcp__playwright__browser_snapshot) · hook = chạy command của bạn trước/sau khi Claude gọi tool · PreToolUse (chạy TRƯỚC, CHẶN được → cho phép, hoặc block + gửi error message về Claude) · PostToolUse (chạy SAU, KHÔNG chặn được vì tool đã chạy → chỉ follow-up như format + feedback cho Claude) · matcher = chỉ định tool bị nhắm (VD "Read", "Write|Edit" — dấu | = OR) · hook khai trong settings.json (3 vị trí: ~/.claude/settings.json global / .claude/settings.json project-commit / .claude/settings.local.json cá nhân) hoặc gõ /hooks · Pre = kiểm soát Claude ĐƯỢC LÀM GÌ vs Post = tăng cường thứ ĐÃ LÀM · dựng hook 4 bước: chọn Pre/Post → xác định tool (matcher) → viết command nhận JSON tool call qua stdinexit code báo allow/block · JSON fields: session_id · transcript_path · hook_event_name · tool_name · tool_input · exit 0 = allow, exit 2 = block (CHỈ PreToolUse) · exit 2 → stderr gửi cho Claude làm feedback (giải thích vì sao chặn) · ví dụ chặn .env (bản hiện hành): matcher "Read" + hook kiểm tool_input.file_path (.includes(".env")exit 2, stderr "You cannot read the .env file") · mỗi tool khác input shape (Readfile_path, Greppattern+paththư mục, Bashcommand) nên check file_path chỉ bắt Read · phủ đồng đều = permissions.deny "Read(**/.env)" (áp mọi tool) · gotcha bảo mật: dùng absolute path (KHÔNG relative) cho script hook → chống path interception + binary planting attack · $PWD placeholder trong settings.example.json · npm run setup → chạy scripts/init-claude.js thay $PWD = absolute path máy bạn → copy & đổi tên thành settings.local.json · 2 file: settings.example.json (template, commit) vs settings.local.json (sinh, cá nhân không commit) · TypeScript type-checking hook (PostToolUse): chạy tsc --noEmit sau mỗi edit → capture error → feed lại Claude sửa call site nó quên (đổi signature ở schema.ts nhưng quên main.ts) · query duplication hook: dùng Agent SDK khởi chạy Claude instance thứ HAI review file trong ./queries → phát hiện query trùng → feedback bắt tái dùng (VD getPendingOrders()) = "AI reviews AI" · trade-off: TS hook nhẹ/nhanh; query hook nặng (mỗi edit tốn time + API) → chỉ monitor thư mục quan trọng · 7 hook event khác: Notification (xin quyền tool / idle 60s) · Stop (trả lời xong) · SubagentStop (subagent = "Task" xong) · PreCompact (trước compact thủ công/tự động) · UserPromptSubmit (user submit prompt, TRƯỚC khi Claude xử lý) · SessionStart (bắt đầu/resume) · SessionEnd (kết thúc) · stdin shape đổi theo 2 trục: (1) loại hook, (2) tool được gọi (tool_input) · Stop hook: chỉ hook_event_name + stop_hook_active, KHÔNGtool_name/tool_input · PostToolUse có thêm tool_response (oldTodos/newTodos) · mẹo soi input: matcher "*" + jq . > post-log.json · Agent SDK = chạy Claude Code programmatically (TypeScript + Python) · cùng agent loop CLI (đọc/sửa file, tool use) dưới quyền bạn · package @anthropic-ai/claude-agent-sdk · ⚠️ @anthropic-ai/claude-code = CLI, KHÔNG import được (tên cũ đã đổi — freshness) · query({ prompt }) = async iterator, for await → stream JSON messages (tool call, tool result, text) · giới hạn tool: options.allowedTools: ["Read","Glob"] = bản SDK của --allowedTools.

🟡 Important: Opus · Sonnet · Haiku (Claude series) · tackles harder tasks (kết hợp tool + dùng cả tool chưa từng thấy) · extensible platform (thêm tool mới dễ, Claude tự thích ứng) · model host configurable: Anthropic / AWS / Google Cloud · đa số assistant dùng LM remote-hosted · LM sinh text được định dạng cẩn thận (không thật sự "chạy") · assistant là bên thực thi action · notebook workflow (viết code → chạy → thêm cell từng bước → final summary) · dùng screenshot để verify UI (Playwright) · PR review flow (đọc changes → đánh giá quality/perf → summary report; GitHub MCP tạo được comment) · Agent tool = spawn subagent · MultiEdit = nhiều sửa đổi cùng lúc · Shift+Tab = cho Claude tự ghi file suốt session (vs Enter duyệt từng thao tác) · /memory mở CLAUDE.md để sửa (hoặc edit tay) · Claude đọc CLAUDE.md đầu mỗi conversation → áp dụng từ message kế · @auth → Claude hiện danh sách file để chọn · @AGENTS.md ở dòng đầu CLAUDE.md = nạp file tool khác, khỏi trùng · Ctrl+G mở plan ra editor sửa tay → Claude dùng bản cuối · Ctrl+O mở transcript viewer (chi tiết reasoning + tool execution) · default effort tùy model + gói · Shift+Tab 1 lần nếu đang auto-accept · Planning để review & bẻ lái trước khi Claude làm · Escape + /memory = dập lỗi lặp lại (ghi cách đúng vào CLAUDE.md) · 4 lợi ích custom command: Automation · Consistency · Context · Flexibility · ví dụ /audit (npm audit → audit fix → test) và /write_tests <path> · commit .claude/commands/ cho cả team dùng chung · MCP hỏi phép mỗi lần tới khi pre-approve · vòng tự cải thiện prompt sinh UI: navigate → generate → review → update prompt (@src/lib/prompts/generation.tsx) → test lại · tuỳ biến GitHub workflow: Project Setup (bước run: npm run setup/dev:daemon), custom_instructions (context về setup), mcp_config (JSON cắm MCP server) · best practices GitHub: default trước → tuỳ biến dần, explicit tool permission, test task đơn giản trước · ứng dụng hook: code formatting · testing · access control · code quality (lint/type check) · logging · validation · viết hook tay hoặc dùng /hooks · PostToolUse: follow-up + feedback, không block · command của hook nhận chi tiết tool call Claude định làm · command đọc JSON từ stdin → parse → quyết allow/block theo tool_name + tool_input · hỏi thẳng Claude liệt kê tool đang có (đổi khi thêm MCP server) · bước 3–4: nhận JSON qua stdin, phản hồi qua exit code · absolute path = đánh đổi: bảo mật cao nhưng khó share (thư mục mỗi máy khác) → pattern template + generator giải · init-claude.js nằm trong scripts/, copy example → rename local · typed language dùng type checker; untyped dùng automated tests · nguyên tắc mở rộng: compiler/linter = feedback tức thì · code review bằng AI instance riêng · focus thư mục giá trị cao · cân bằng automation vs cost · matcher chỉ có nghĩa với Pre/Post (lọc theo tool name); Stop/Session… không có tool để match · TodoWrite = tool Claude quản to-do · event ngoài-tool mở tự động hoá vòng đời: SessionStart nạp context, UserPromptSubmit chèn/chặn prompt, Stop báo xong, PreCompact lưu state, Notification ping khi Claude chờ · SDK hỗ trợ đủ như CLI: custom system prompt · MCP servers · hooks · subagents · session resumption · SDK mặc định có full tool set · SDK là thứ query_hook.js dùng (AI reviews AI) · allowedTools = cùng cần gạt ở CLI/GitHub Actions/SDK.

🟢 Good-to-know: ẩn dụ "như dev người thật" · longevity (độ bền theo thời gian) · coding companion · standalone LM sẽ nói "không có khả năng đọc file" · tool instruction được tự động thêm vào message · TodoRead/TodoWrite quản danh sách to-do · NotebookEdit/NotebookRead cho Jupyter · S3 bucket dùng chung → rủi ro External Marketing Partner chạm dữ liệu (ví dụ data-governance) · /init sinh CLAUDE.md, CLAUDE.md được commit & chia sẻ · shortcut cũ # "memory mode" đã bị gỡ (dùng /memory) · ví dụ chỉ thị tùy biến: Use comments sparingly. Only comment complex code · keyword "think / think harder" cũ đã vô hiệu (dùng /effort) · "still thinking" hint khi Claude đang reason · kết hợp Plan + Effort cho task vừa rộng vừa sâu · /clear không xoá hội thoại khỏi session history · các kỹ thuật điều hướng hợp lúc: hội thoại dài, chuyển task, Claude lặp lỗi, project phức tạp · user-level ~/.claude/commands/ (lệnh cá nhân xuyên project) · custom command vs hook: gọi-khi-cần + có tham số vs tất định luôn chạy · MCP ecosystem: database · API testing/monitoring · file system · cloud · dev tool automation · "code assistant → development partner" · kết quả prompt sinh UI đẹp hơn: warm sunset / ocean depth / asymmetric / spacing phá cách · GitHub integration biến Claude thành "automated team member" · allowed-origins trong mcp_config (localhost:3000;cdn.tailwindcss.com;esm.sh) · dev:daemon chạy server nền + logs.txt + sqlite3 cli trong custom_instructions · API key add lúc cài (lưu dạng secret) · allowed_tools least-privilege = một security control · hook còn loại khác ("you'll see other hooks in a later lesson") · ví dụ command hook: node /home/hooks/read_hook.js, node /home/hooks/edit_hook.js · "type": "command" trong hook · luồng thường: query + tool definitions → Claude formatted response → Claude Code execute tool → result · hook khai trong settings.json (KHÁC CLAUDE.md) · access control → đặt ở PreToolUse (chỉ loại này chặn được); formatting/logging → PostToolUse · ví dụ JSON: hook_event_name: "PreToolUse", tool_name: "Read", tool_input.file_path: "/code/queries/.env" · exit 2 ở PostToolUse vô nghĩa (tool đã chạy) · video khoá bản cũ có kèm Grep, text hiện hành bỏ, chỉ Read (freshness) · Grep.path = thư mục tìm kiếm (không phải file) → không hợp check kiểu file_path · hook = lớp feedback, permissions.deny mới là lớp chặn đồng đều · link: hooks guide code.claude.com/docs/en/hooks-guide · $PWD trên Windows = path có \ (escape JSON) + dấu cách → generator phải forward-slash + quote path (portability gotcha thực tế) · tsc.js dùng **TS compiler API** (ts.createProgram + noEmit) không phải gọi CLI · query_hook.js tắt sẵn bằng process.exit(0) để khỏi tốn API · **deterministic gate** (tsc: có ground truth) vs **probabilistic gate** (LLM review: việc mờ, có thể sai) · "shift-left": bắt lỗi lúc sửa thay vì ở CI muộn · stop_hook_active field trong Stop hook · transcript_path có trong mọi input · kỷ luật "log-first": jq ghi input rồi đọc, đừng đoán schema · chọn event HẸP nhất cho đúng tín hiệu · SDK install: npm install @anthropic-ai/claude-agent-sdk · index.mjs + node index.mjs · JSON stream = same event như CLI · mỗi query() = một lượt model tính tiền (production bọc rate/spend guard).


Nguồn: Claude Code in Action (Anthropic Academy) — Copyright Anthropic. Phần đề thi thử cho khoá này nằm ở tab "Đề thi thử".

Câu hỏi thường gặp

Coding assistant hoạt động thế nào bên trong?
Coding assistant là một hệ thống dùng language model để giải task lập trình, theo quy trình như dev người thật: Gather context (hiểu error, xác định file và phần codebase liên quan), Formulate a plan (quyết cách sửa và cách verify), rồi Take an action (sửa file, chạy lệnh) — lặp lại tới khi xong. Bước gather context và take action bắt buộc phải tương tác với thế giới ngoài như đọc file, fetch documentation, chạy lệnh hay sửa code.
Tool use trong coding assistant là gì và giải quyết vấn đề gì?
Language model tự thân chỉ nhận text và trả text — nó không thật sự đọc file hay chạy lệnh được. Tool use giải vấn đề đó: khi bạn gửi request, coding assistant tự chèn thêm instruction dạy LM cách yêu cầu một action, ví dụ "nếu muốn đọc file thì trả lời ReadFile: tên file". LM đáp lại bằng text đúng định dạng đó (VD "ReadFile: main.go"), coding assistant đọc file thật rồi gửi nội dung ngược lại cho LM để nó đưa câu trả lời cuối. Nhờ vậy LM "đọc file / viết code / chạy lệnh" được dù thực chất chỉ sinh text theo quy ước.
Vì sao khả năng dùng tool của Claude lại quan trọng với Claude Code?
Không phải language model nào cũng dùng tool giỏi như nhau. Claude series (Opus, Sonnet, Haiku) đặc biệt mạnh ở việc hiểu tool làm gì và dùng chúng hiệu quả để hoàn thành task phức tạp. Điều này mang lại ba lợi ích cho Claude Code: tackle được task khó hơn (kết hợp nhiều tool, dùng cả tool chưa từng thấy), là extensible platform (thêm tool mới dễ, Claude tự thích ứng), và better security (navigate codebase không cần indexing nên thường không phải gửi toàn bộ codebase lên server ngoài).
Claude Code dùng model nào và host ở đâu?
Claude Code dùng Claude series of models. Khác với đa số coding assistant dùng language model host từ xa cố định, Claude Code cho phép cấu hình (configurable) nơi host model: Anthropic, AWS, hoặc Google Cloud.
Claude Code có sẵn những tool nào (built-in)?
Bộ built-in gồm: Agent (khởi chạy subagent lo một task), Bash (chạy shell command), Edit (sửa file), Glob (tìm file theo pattern), Grep (tìm nội dung trong file), LS (liệt kê file & thư mục), MultiEdit (nhiều sửa đổi cùng lúc), NotebookEdit (ghi vào cell Jupyter), NotebookRead (đọc cell), Read (đọc file), TodoRead và TodoWrite (đọc/cập nhật danh sách to-do), WebFetch (lấy nội dung từ URL), WebSearch (tìm web), và Write (ghi ra file). Lưu ý dễ nhầm: Glob tìm FILE theo pattern, còn Grep tìm NỘI DUNG bên trong file.
Làm sao Claude Code làm được việc ngoài repo như điều khiển browser hay thao tác GitHub?
Bằng cách cắm thêm MCP server để mở rộng bộ tool. Ví dụ Playwright MCP Server cung cấp bộ tool cho Claude điều khiển browser (mở browser, navigate tới app, chụp screenshot, cập nhật styling) trong task cải thiện UI; GitHub MCP Server cung cấp bộ tool tương tác với GitHub (đọc thay đổi trong pull request, đánh giá chất lượng code, tạo comment, viết summary report) trong task review PR. Cùng một Claude Code, chỉ khác nhau ở bộ tool được trao.
Vì sao Claude Code có thể soi luồng dữ liệu xuyên nhiều dịch vụ cloud?
Vì Claude Code đọc trực tiếp cả code lẫn infrastructure-as-code. Trong ví dụ DynamoDB → Lambda → S3 bucket dùng chung (được cả Internal Marketing Team và External Marketing Partner truy cập), hạ tầng được định nghĩa trong các file Terraform mà Claude Code đọc dễ dàng. Nhờ đó Claude lần theo được luồng dữ liệu xuyên nhiều tầng và chỉ ra rủi ro như partner ngoài đang chạm tới dữ liệu không nên chạm — thứ mà công cụ chỉ đọc một file đơn lẻ khó phát hiện.
Lệnh /init trong Claude Code làm gì?
Chạy /init khi mới mở project để Claude phân tích toàn bộ codebase — hiểu mục đích & kiến trúc, các lệnh quan trọng và file trọng yếu, coding patterns — rồi viết một bản summary vào file CLAUDE.md. Khi Claude xin quyền tạo file, nhấn Enter để duyệt từng thao tác ghi, hoặc Shift+Tab để cho Claude tự ghi file thoải mái suốt session (auto-accept).
File CLAUDE.md dùng để làm gì và có mấy loại?
CLAUDE.md có hai mục đích: dẫn đường Claude qua codebase (lệnh, kiến trúc, coding style) và cho bạn đưa chỉ thị tùy biến. Nó được nhét vào MỌI request nên hoạt động như một system prompt bền vững cho project. Có 3 vị trí: CLAUDE.md (sinh bởi /init, commit vào source control, chia sẻ cả team), CLAUDE.local.md (chỉ thị cá nhân, không commit), và ~/.claude/CLAUDE.md (áp cho mọi project trên máy). Sửa bằng cách edit file trực tiếp hoặc chạy /memory trong Claude Code — lưu ý shortcut cũ "#" (memory mode) đã bị gỡ.
Nhắc file bằng @ trong Claude Code hoạt động thế nào?
Gõ @ kèm đường dẫn để tự động chèn nội dung file đó vào request, ví dụ "How does the auth system work? @auth" — Claude hiện danh sách file liên quan để chọn rồi đưa vào hội thoại. Dùng chính cú pháp @ ngay trong CLAUDE.md để trỏ tới file luôn-liên-quan (VD @prisma/schema.prisma): nội dung file sẽ tự vào mọi request nên Claude trả lời ngay mà không phải search + đọc lại mỗi lần. Nếu repo đã có AGENTS.md cho tool khác, đặt @AGENTS.md ở dòng đầu CLAUDE.md để nạp lại, khỏi chép trùng.
Làm sao chỉ cho Claude đúng vùng UI cần sửa?
Dán một screenshot vào khung chat — Claude nhìn thấy đúng chỗ bạn muốn đổi, khỏi tả bằng lời. Lưu ý phím dán là Ctrl+V, kể cả trên macOS cũng là Ctrl+V chứ không phải Cmd+V (đây là phím riêng để dán ảnh vào chat). Dán xong thì bảo Claude sửa đúng vùng đó.
Planning Mode khác Effort level thế nào, khi nào dùng cái nào?
Hai tính năng giải quyết hai loại độ phức tạp khác nhau. Planning Mode lo bề RỘNG: bật bằng /plan hoặc Shift+Tab hai lần, Claude sẽ đọc nhiều file, lập một plan chi tiết, cho bạn xem ý định rồi chờ duyệt — hợp với task nhiều bước, thay đổi nhiều file/component. Effort level lo chiều SÂU: chạy /effort để chỉnh (low nhanh & rẻ, max reason lâu nhất) — hợp với logic phức tạp, debug bug khó, bài thuật toán. Task vừa rộng vừa sâu thì kết hợp cả hai; nhưng cả hai đều tốn thêm token nên cân nhắc chi phí.
Làm sao để Claude suy nghĩ kỹ hơn và xem nó đang nghĩ gì?
Mặc định Claude đã reason trước khi trả lời (thấy dòng "still thinking"). Bấm Ctrl+O để mở transcript viewer, xem chi tiết reasoning + tool execution. Muốn nó nghĩ sâu hơn thì chỉnh effort level bằng /effort (mức mặc định tùy model + gói), hoặc thả từ khoá ultrathink vào một prompt để nghĩ thêm chỉ cho lượt đó mà không đổi effort của cả session. Lưu ý các keyword "think / think harder" kiểu cũ trong video nay đã không còn tác dụng — dùng /effort và ultrathink thay thế.
/compact khác /clear thế nào, khi nào dùng cái nào?
/compact tóm tắt toàn bộ lịch sử hội thoại nhưng giữ lại thông tin cốt lõi Claude đã học — dùng khi chuyển sang task LIÊN QUAN và muốn giữ hiểu biết về project (hội thoại đã dài nhưng chứa context quan trọng). /clear mở một hội thoại mới với context sạch hoàn toàn — dùng khi chuyển sang task KHÁC HẲN, không liên quan, mà context cũ có thể làm Claude rối. /clear không xoá hội thoại cũ khỏi session; vẫn quay lại được bằng /resume.
Làm sao dừng Claude giữa chừng và dập lỗi nó lặp đi lặp lại?
Bấm Escape để ngắt Claude giữa response và bẻ lái — hữu ích khi nó ôm quá nhiều việc một lúc, giúp ép nó tập trung một task. Với lỗi Claude tái phạm qua nhiều hội thoại: Escape để dừng, chạy /memory (hoặc sửa CLAUDE.md trực tiếp) ghi lại cách làm đúng, rồi tiếp tục — nhờ vậy các hội thoại sau trên project không lặp lại lỗi đó. Muốn dọn lịch sử nhiễu (như màn debug lằng nhằng) mà vẫn giữ context giá trị thì Escape hai lần hoặc /rewind để tua về điểm trước.
Làm sao tạo một custom slash command trong Claude Code?
Tạo một file Markdown trong thư mục .claude/commands/ của project — tên file chính là tên lệnh (audit.md tạo ra /audit). Nội dung file là chỉ thị (prompt) cho Claude thực hiện. Claude Code tự nhận command mới ngay, KHÔNG cần restart. Vì file nằm trong .claude/commands/ nên commit vào repo là cả team dùng chung một bộ lệnh. Ngoài project-level còn có user-level ~/.claude/commands/ cho lệnh cá nhân xuyên mọi project.
Placeholder $ARGUMENTS trong custom command dùng để làm gì?
$ARGUMENTS là chỗ để truyền tham số vào command, giúp nó linh hoạt và tái dùng được. Ví dụ chạy "/write_tests the use-auth.ts file in the hooks directory" thì phần chuỗi sau tên lệnh được thế vào $ARGUMENTS trong file command. Argument không nhất thiết là file path — có thể là bất kỳ string nào để cấp context và định hướng cho task.
Làm sao thêm một MCP server (VD Playwright) vào Claude Code, và chạy lệnh ở đâu?
Chạy lệnh claude mcp add playwright npx @playwright/mcp@latest trong TERMINAL — KHÔNG phải bên trong Claude Code. Lệnh đặt tên server là "playwright" và cấp command khởi chạy server local trên máy. Playwright MCP cho Claude điều khiển web browser (mở, navigate, screenshot), hữu ích cho workflow web.
Làm sao pre-approve một MCP server để Claude khỏi hỏi phép mỗi lần?
Mở file .claude/settings.local.json và thêm server vào mảng permissions.allow, ví dụ "mcp__playwright" — lưu ý HAI dấu gạch dưới trong mcp__playwright. Nhờ vậy Claude dùng tool của server đó khỏi hỏi phép mỗi lần. Vì settings.local.json là file cá nhân (không commit), pre-approve này chỉ áp cho máy của bạn.
Hook trong Claude Code là gì và chen vào luồng ở đâu?
Hook cho phép bạn chạy command của riêng mình ngay trước hoặc ngay sau khi Claude định gọi một tool. Luồng bình thường: query của bạn gửi tới model kèm tool definitions, Claude quyết dùng tool (trả một formatted response), rồi Claude Code thực thi tool và trả kết quả. Hook chen vào ngay quanh bước thực thi tool đó — cho bạn chạy code just-before (PreToolUse) hoặc just-after (PostToolUse). Rất hữu ích để format code sau khi sửa, chạy test khi file đổi, hoặc chặn truy cập file cụ thể.
PreToolUse khác PostToolUse thế nào, loại nào chặn được thao tác?
PreToolUse chạy TRƯỚC khi tool được gọi và CHẶN được: command của bạn nhận chi tiết về tool call Claude định làm, rồi bạn cho phép thao tác chạy bình thường, hoặc block nó và gửi một error message ngược lại cho Claude. PostToolUse chạy SAU khi tool đã thực thi nên KHÔNG chặn được nữa (thao tác đã xảy ra) — nhưng nó vẫn chạy được follow-up (VD format file vừa sửa) và cấp thêm feedback cho Claude. Câu chốt: PreToolUse kiểm soát Claude ĐƯỢC LÀM GÌ; PostToolUse tăng cường thứ Claude ĐÃ LÀM.
Khai báo hook ở đâu, và matcher để làm gì?
Hook định nghĩa trong các Claude settings file, đúng bộ ba vị trí như CLAUDE.md: ~/.claude/settings.json (global, mọi project), .claude/settings.json (project, commit & chia sẻ team), và .claude/settings.local.json (cá nhân, không commit). Bạn viết tay hoặc dùng lệnh /hooks ngay trong Claude Code. Trong mỗi hook, matcher chỉ định loại tool nào bị nhắm — ví dụ "Read" nhắm tool Read, còn "Write|Edit" dùng dấu | kiểu regex để nhắm cả Write lẫn Edit.
Hook thường dùng vào những việc gì?
Sáu ứng dụng điển hình: code formatting (tự format file sau khi Claude sửa), testing (tự chạy test khi file đổi), access control (chặn Claude đọc/sửa file cụ thể), code quality (chạy linter/type checker rồi feedback cho Claude), logging (ghi lại file nào Claude chạm/sửa), và validation (kiểm naming convention / coding standard). Access control nên đặt ở PreToolUse vì chỉ loại đó chặn được; formatting/logging hợp với PostToolUse vì chạy theo sau.
Dựng một hook gồm những bước nào?
Bốn bước. (1) Chọn PreToolUse hay PostToolUse — Pre ngăn được tool call chạy, Post chạy sau khi tool đã dùng. (2) Xác định loại tool call cần canh — chỉ rõ đúng tool nào kích hoạt hook (chính là matcher). (3) Viết một command nhận tool call — command này nhận JSON data về tool call đề xuất qua standard input (stdin). (4) Nếu cần, command trả feedback cho Claude — exit code của command báo Claude allow hay block thao tác.
Hook command nhận dữ liệu về tool call như thế nào?
Khi hook command chạy, Claude gửi một khối JSON qua standard input (stdin) mô tả tool call đề xuất, gồm các field session_id, transcript_path, hook_event_name (VD "PreToolUse"), tool_name (VD "Read") và tool_input (VD { "file_path": "/code/queries/.env" }). Command đọc JSON từ stdin, parse nó, rồi quyết định allow hay block dựa trên tool_name và tool_input.
Exit code trong hook nghĩa là gì?
Command giao tiếp ngược lại với Claude bằng exit code. Exit code 0 = mọi thứ ổn, cho phép tool call chạy tiếp. Exit code 2 = block tool call, nhưng CHỈ có tác dụng với PreToolUse hook (PostToolUse chạy sau khi tool đã thực thi nên không chặn được). Khi exit 2 trong một PreToolUse hook, mọi error message bạn ghi ra standard error (stderr) sẽ được gửi tới Claude như feedback giải thích vì sao thao tác bị chặn.
Hook chặn Read .env có chặn luôn được Grep và Bash không?
Không — bản hiện hành của bài chỉ chặn tool Read (kiểm tool_input.file_path). Lý do: mỗi tool gửi input shape khác nhau. Read gửi { file_path }; Grep gửi { pattern, path } với path là THƯ MỤC tìm kiếm chứ không phải file; Bash gửi { command }. Nên một check trên file_path bắt được Read nhưng không chặn được grep API_KEY toàn project hay cat .env trong Bash. Muốn phủ đủ, hoặc viết matcher riêng cho từng tool và soi đúng field của nó, hoặc dùng permissions.deny với rule như "Read(**/.env)" — loại rule này áp đồng đều trên mọi tool nên gọn và chắc hơn.
Vì sao sau npm run setup lại có hai file settings trong .claude?
Vì một khuyến nghị bảo mật hook của Claude Code: nên dùng absolute path (không dùng relative path) cho script hook, để giảm path interception và binary planting attack. Nhưng absolute path lại khó share vì đường dẫn tuyệt đối trên mỗi máy khác nhau. Nên project giữ settings.example.json (template, có commit và chia sẻ) chứa placeholder $PWD; khi chạy npm run setup, ngoài việc cài dependencies nó còn chạy scripts/init-claude.js để thay $PWD bằng absolute path trên máy bạn, rồi copy và đổi tên thành settings.local.json (file cá nhân, không commit). Nhờ vậy vừa share được settings vừa giữ absolute path.
Vì sao nên dùng absolute path thay vì relative path cho script hook?
Vì lý do bảo mật: absolute path khoá cứng đúng file cần chạy, giảm rủi ro path interception và binary planting attack — tức kẻ xấu đặt một script hay binary giả trùng tên vào một thư mục (trên PATH hoặc thư mục tương đối) để hook vô tình chạy nhầm nó. Đánh đổi là absolute path khó chia sẻ giữa các máy, nên mới cần cơ chế $PWD + init-claude.js để sinh path đúng theo từng máy.
TypeScript type-checking hook giải quyết vấn đề gì và làm thế nào?
Vấn đề: khi Claude đổi một function signature, nó thường không cập nhật hết call site — ví dụ thêm param verbose vào một hàm trong schema.ts thì Claude sửa được definition nhưng quên chỗ gọi ở main.ts, tạo type error. Giải: một PostToolUse hook chạy trình biên dịch TypeScript (tsc --noEmit) sau mỗi lần sửa file: nó kiểm type error, capture lỗi, feed lỗi ngược lại cho Claude ngay, và prompt Claude đi sửa các file khác. Cách này áp dụng cho mọi typed language có type checker; với ngôn ngữ untyped thì thay bằng automated tests.
Query duplication prevention hook hoạt động thế nào, và dùng gì?
Nó dùng Claude Agent SDK để triển khai một review process. Khi Claude sửa file trong thư mục ./queries, hook khởi chạy một instance Claude Code THỨ HAI (programmatically), nhờ instance đó review thay đổi và kiểm xem có query tương tự đã tồn tại chưa (VD getPendingOrders). Nếu phát hiện trùng, nó feed feedback về instance gốc và prompt Claude bỏ bản trùng, dùng lại code có sẵn. Đây là mô hình "AI review AI". Nhược điểm: nặng — mỗi lần sửa ./queries tốn thêm thời gian và API usage, nên chỉ nên monitor các thư mục quan trọng.
Vì sao nên chỉ monitor thư mục quan trọng với query duplication hook?
Vì query hook khởi chạy một instance Claude riêng cho mỗi lần review, tốn thêm thời gian và chi phí API mỗi lần có edit trong thư mục được canh. Lợi ích là codebase sạch hơn, ít trùng lặp; nhưng để cân bằng lợi ích tự động hoá với chi phí hiệu năng, chỉ nên áp nó cho các thư mục giá trị cao nơi tính nhất quán quan trọng nhất (như ./queries), thay vì canh toàn bộ project. Khác với nó, TypeScript hook nhẹ và chạy nhanh nên bật thoải mái hơn.
Ngoài PreToolUse và PostToolUse, Claude Code còn những hook event nào?
Còn bảy event nữa, phủ toàn bộ vòng đời phiên làm việc. Notification chạy khi Claude Code gửi notification — lúc cần xin quyền dùng tool, hoặc sau khi idle 60 giây. Stop chạy khi Claude trả lời xong. SubagentStop chạy khi một subagent (hiện là "Task" trong UI) xong. PreCompact chạy trước một thao tác compact (thủ công hoặc tự động). UserPromptSubmit chạy khi user submit prompt, trước khi Claude xử lý. SessionStart chạy khi bắt đầu hoặc resume một session, và SessionEnd khi session kết thúc.
Vì sao viết hook lại khó vì cấu trúc stdin thay đổi?
Vì input đổi theo hai trục. Một, theo loại hook: PreToolUse, PostToolUse, Notification, Stop… mỗi loại có field khác nhau — ví dụ một Stop hook chỉ có hook_event_name và stop_hook_active, KHÔNG có tool_name hay tool_input; còn một PostToolUse thì có tool_name, tool_input và thêm cả tool_response. Hai, với Pre/PostToolUse thì tool_input còn khác nhau tuỳ tool được gọi (VD TodoWrite gửi tool_input.todos). Vì vậy bạn thường không biết trước command của mình sẽ nhận đúng cấu trúc gì.
Làm sao biết chính xác dữ liệu mà hook của mình sẽ nhận?
Dùng một "hook soi input": gắn tạm một hook với matcher "*" và command 'jq . > post-log.json'. Nó ghi nguyên khối input mà hook nhận vào file post-log.json, để bạn mở ra xem chính xác shape dữ liệu rồi mới viết command inspect đúng field. Đây là kỷ luật "quan sát trước, code sau" — đừng đoán schema. (Chính là các dòng pre-log.json/post-log.json trong settings.example.json của project thực hành.)
Agent SDK là gì và dùng được với ngôn ngữ nào?
Agent SDK cho phép chạy Claude Code programmatically từ chính app hay script của bạn — có cho TypeScript và Python. Nó trao đúng agent loop mà CLI dùng (đọc file, sửa file, tool use) nhưng dưới quyền điều khiển của bạn. Bạn gọi query({ prompt }) và duyệt kết quả như một async iterator; nó stream ra các JSON message giống hệt event trong CLI: tool call, tool result, và text của Claude. SDK hỗ trợ đủ những gì CLI làm: custom system prompt, MCP server, hooks, subagents, và session resumption.
Package Agent SDK tên là gì, và điểm dễ nhầm ở đâu?
Package hiện hành là @anthropic-ai/claude-agent-sdk (cài bằng npm install @anthropic-ai/claude-agent-sdk). Điểm dễ nhầm: gói tên gần giống @anthropic-ai/claude-code CHÍNH LÀ CLI, không import được vào code. Video cũ của khoá dùng tên package cũ nay đã đổi và không còn chạy — nhớ dùng claude-agent-sdk.
Làm sao giới hạn tool khi dùng Agent SDK?
Mặc định SDK có full tool set. Muốn thu hẹp, truyền options.allowedTools, ví dụ query({ prompt, options: { allowedTools: ["Read", "Glob"] } }). Đây là bản SDK của flag --allowedTools trên CLI, và cùng tinh thần least-privilege với allowed_tools trong GitHub Actions — nên với tác vụ tự động chỉ nên cấp đúng tool cần thiết.
Làm sao cài official GitHub integration cho Claude Code?
Chạy /install-github-app ngay trong Claude. Nó dẫn qua ba bước: install Claude Code app trên GitHub, add API key, và tự sinh một pull request chứa sẵn các file workflow. Merge PR đó xong, bạn sẽ có hai GitHub Action nằm trong thư mục .github/workflows của repo. Từ đó Claude Code chạy được bên trong GitHub Actions (trên cloud) chứ không chỉ local trong terminal.
Hai workflow mặc định của GitHub integration làm gì?
Mention Action — mention @claude trong bất kỳ issue hay pull request nào; Claude sẽ analyze request và lập task plan, thực thi task với full access to codebase, rồi phản hồi kết quả ngay trong issue/PR. Pull Request Action — mỗi khi bạn tạo một PR, Claude tự động review các thay đổi, phân tích impact của chúng, rồi post một báo cáo chi tiết lên PR. Nó biến Claude từ trợ lý dev thành một "automated team member" ngay trong GitHub workflow.
Tuỳ biến workflow GitHub Action bằng những field nào?
Bốn field hay dùng. Project Setup — thêm bước chuẩn bị môi trường trước khi Claude chạy (VD npm run setup, npm run dev:daemon). custom_instructions — cấp context về setup của project (server đã chạy ở localhost:3000, log ghi vào logs.txt, có sqlite3 cli, dùng bộ tool mcp__playwright…). mcp_config — JSON cấu hình các MCP server để trao thêm năng lực (VD playwright với --allowed-origins). allowed_tools — danh sách tool được phép.
Cấp quyền tool trong GitHub Actions khác local thế nào?
Trong GitHub Actions bạn PHẢI liệt kê tường minh mọi allowed_tools — KHÔNG có shortcut như local. Ở local có thể pre-approve nguyên một MCP server bằng mcp__playwright; nhưng trong Actions, từng tool của từng MCP server phải liệt kê riêng lẻ, ví dụ mcp__playwright__browser_snapshot, mcp__playwright__browser_click… Đây là điểm khác biệt quan trọng và dễ vấp nhất khi chuyển từ local lên CI. Best practice: bắt đầu từ default workflow, tuỳ biến dần, explicit về tool permission, và test với task đơn giản trước.

Đề thi thử (107 câu)

Đề thi thử tự biên soạn, bám sát đề thi chứng chỉ thật — trích 20 câu đầu dưới đây. Bản tương tác — chấm điểm, đáp án & giải thích từng câu — nằm ở tab “Đề thi thử” trên trang.

  1. How Coding Assistants Work How is a coding assistant best described?

    • A. A simple text editor with syntax highlighting
    • B. A sophisticated system that uses language models to tackle complex programming tasks, not just a tool that writes code
    • C. A compiler that turns prompts directly into machine code
    • D. A database of pre-written code snippets
  2. How Coding Assistants Work When solving a task like fixing a bug, what three-step process does a coding assistant follow, similar to a human developer?

    • A. Compile, run, debug
    • B. Gather context, formulate a plan, take an action
    • C. Read, summarize, reply
    • D. Index, search, deploy
  3. How Coding Assistants Work Which steps of the coding assistant's process specifically require interacting with the outside world?

    • A. Only the 'formulate a plan' step
    • B. The 'gather context' and 'take an action' steps — e.g. reading files, fetching docs, running commands, editing code
    • C. None of the steps; everything happens inside the language model
    • D. Only the final answer step
  4. How Coding Assistants Work Inside the 'Assistant', which two components work together?

    • A. A database and a web server
    • B. A language model and a set of tools
    • C. A compiler and a linter
    • D. A frontend and a backend
  5. How Coding Assistants Work Where are the Claude models used by Claude Code hosted?

    • A. Only on the user's local machine
    • B. At Anthropic, AWS, or Google Cloud (configurable)
    • C. Only on Anthropic's servers, with no other option
    • D. On a peer-to-peer network of user devices
  6. The Tool Use Challenge What is the fundamental limitation of a language model by itself?

    • A. It can only process images, not text
    • B. It can only process text and return text — it cannot actually read files or run commands
    • C. It can read files but cannot generate text
    • D. It can run commands but cannot understand natural language
  7. How Tool Use Works How does a coding assistant teach a language model to request an action?

    • A. By fine-tuning the model on the user's codebase before every request
    • B. By automatically adding instructions to the message, e.g. 'If you want to read a file, respond with ReadFile: name of file'
    • C. By giving the model direct network access to the file system
    • D. By compiling the request into a binary tool
  8. How Tool Use Works You ask: "What code is written in the main.go file?" What does the language model itself actually produce when it wants to read the file?

    • A. It directly opens and reads main.go from disk
    • B. It produces a formatted text response such as 'ReadFile: main.go', which the coding assistant then executes
    • C. It sends an email requesting the file
    • D. It compiles main.go and returns the binary
  9. How Tool Use Works In the tool use flow, what happens right after the language model responds with 'ReadFile: main.go'?

    • A. The model gives its final answer immediately with no file contents
    • B. The coding assistant reads the actual file and sends its contents back to the model
    • C. The session ends and waits for a new prompt
    • D. The model asks the user to paste the file manually
  10. Why Claude's Tool Use Matters According to the course, what is true about language models and tool use?

    • A. All language models use tools with exactly the same skill level
    • B. Not all language models are equally good at using tools; the Claude series is particularly strong at it
    • C. Only models running locally can use tools
    • D. Tool use makes all models perform identically
  11. Benefits of Strong Tool Use Which of the following is a security benefit of Claude Code's strong tool use?

    • A. It encrypts every file on your disk
    • B. It can navigate codebases without requiring indexing, which often means not sending your entire codebase to external servers
    • C. It blocks all network access permanently
    • D. It requires two-factor authentication for every tool call
  12. Benefits of Strong Tool Use What does it mean that Claude Code is an 'extensible platform'?

    • A. You can easily add new tools, and Claude will adapt to use them as your workflow evolves
    • B. It can only ever use a fixed, built-in set of tools
    • C. It automatically rewrites your entire codebase
    • D. It extends the context window to unlimited size
  13. Key Takeaways Which statement best captures the key takeaway about tool use?

    • A. Tool use replaces the need for a language model entirely
    • B. Tool-use capability transforms a simple text-generating model into a powerful coding assistant that can read files, understand the codebase, and make meaningful changes
    • C. Tool use only matters for writing documentation
    • D. Tool use slows the assistant down and should be avoided
  14. Tools with Claude Code What does the built-in Agent tool do in Claude Code?

    • A. Runs a shell command
    • B. Launches a subagent to handle a task
    • C. Reads a file
    • D. Searches the web
  15. Tools with Claude Code In Claude Code's built-in tools, what is the difference between Glob and Grep?

    • A. Glob searches the contents of a file; Grep finds files by pattern
    • B. Glob finds files based upon a pattern; Grep searches the contents of a file
    • C. Both find files by name; they are interchangeable
    • D. Glob lists directories; Grep edits files
  16. Tools with Claude Code Which built-in tool lets Claude Code make several edits at the same time?

    • A. Edit
    • B. MultiEdit
    • C. Write
    • D. NotebookEdit
  17. Tools with Claude Code What is the difference between the WebFetch and WebSearch tools?

    • A. WebFetch searches the web; WebSearch fetches from a URL
    • B. WebFetch fetches content from a specific URL; WebSearch searches the web
    • C. Both fetch from a fixed URL
    • D. WebFetch reads a local file; WebSearch reads a remote file
  18. Tools with Claude Code Which pair of built-in tools is used to manage a to-do list in Claude Code?

    • A. NotebookRead and NotebookEdit
    • B. Read and Write
    • C. TodoRead and TodoWrite
    • D. Glob and Grep
  19. Data analysis task In the streaming.csv data analysis example, what workflow does Claude Code follow?

    • A. It sends the entire CSV to an external server for analysis
    • B. It writes code in a notebook to examine the data format, runs it and examines results, adds cells executing each to guide its analysis, then writes a final summary
    • C. It only prints the first row and stops
    • D. It converts the CSV to a screenshot
  20. UI styling task In the UI styling task, what does the Playwright MCP Server provide to Claude Code?

    • A. A set of tools that allow Claude to control a browser (open browser, navigate, take a screenshot)
    • B. A faster language model for styling
    • C. A database of CSS templates
    • D. A tool to deploy the app to production

…và 87 câu nữa trong bản đề thi thử đầy đủ (107 câu) — mở tab “Đề thi thử” trên trang để làm toàn bộ, có chấm điểm & giải thích.