- 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:
- 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.
- 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.
- 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 Cloud — configurable (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 đủ:
- Bạn hỏi: "main.go có code gì?"
- Coding assistant thêm tool instructions vào request.
- Language model đáp:
ReadFile: main.go. - Coding assistant đọc file thật và gửi nội dung file ngược lại cho model.
- 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ì và 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:
- Viết code trong một notebook để soi định dạng dữ liệu.
- Chạy code và xem kết quả.
- Thêm cell, chạy từng cái để dẫn dắt phân tích.
- 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 và 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ọng và file 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.md có hai mục đích:
- Dẫn đường Claude qua codebase — chỉ ra lệnh quan trọng, kiến trúc, coding style.
- Đư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/memoryhoặc sửaCLAUDE.mdtay. (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.md ở dò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.mdcủ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ặpCLAUDE.md(commit, luật chung) vsCLAUDE.local.md(cá nhân, không commit) đúng bằng ranh giới tôi vẫn kẻ giữa "chuẩn team" và "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) và đ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+V— kể cả trên macOS cũng làCtrl+V, KHÔNG phảiCmd+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:
plankhácautovà ngược hẳnbypassPermissions.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ẽ:
- Đọc nhiều file hơn trong project.
- Lập một plan chi tiết.
- Trình bày đúng ý định nó định làm.
- 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 reasoning và tool 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;
/efforthiệ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ùngultrathinkcho 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 để
maxchạ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:
Escapeđể dừng response hiện tại.- Chạy
/memory(hoặc sửaCLAUDE.mdtrực tiếp) — ghi lại cách làm đúng. - 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:
- Query của bạn gửi tới model kèm tool definitions.
- Claude quyết dùng tool → trả về một formatted response.
- 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 trongCLAUDE.md. Cùng bộ ba vị trí (global / project / project-local) nhưng khác file, khác vai:CLAUDE.mdlà lời dặn cho model;settings.jsonlà cấ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:
- Chọn PreToolUse hay PostToolUse — Pre ngăn được tool call chạy; Post chạy sau khi tool đã dùng.
- 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). - 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).
- (Nếu cần) command trả feedback cho Claude — exit 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_name và tool_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 + exit2→ 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èmGrep; bản text hiện hành đã bỏ, chỉ cònRead. Lý do: mỗi tool gửi input shape khác nhau —Readgửi{ file_path };Grepgửi{ pattern, path }vớipathlà thư mục tìm kiếm, không phải file;Bashgửi{ command }. Nên một check trênfile_pathbắt đượcReadnhưng không chặn đượcgrep API_KEYtoàn project haycat .envtrong 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ùngpermissions.denyvớ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_pathrồ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 checkfile_pathchỉ chặnRead;grep API_KEYtoàn project (Grepdùngpath= thư mục) haycat .env(Bashdùngcommand) 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ùngpermissions.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.mdmà 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ấmrm -rfbậ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àosettings.jsoncommit 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/ có 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 interception và binary 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ặpCLAUDE.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.jslà 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ệnhnode <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.js và hooks/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:
- Chạy
tsc --noEmitđể kiểm type error. - Capture lỗi tìm được.
- Feed lỗi ngược cho Claude ngay.
- 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:
- Trigger khi Claude sửa file trong
./queries. - Khởi chạy một instance Claude Code THỨ HAI (programmatically, qua Agent SDK).
- Nhờ instance thứ hai review thay đổi + kiểm query tương tự đã có.
- Nếu trùng → feed feedback cho instance gốc.
- 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.jslà deterministic 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.jslà probabilistic 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:
- Theo loại hook (
PreToolUse,PostToolUse,Notification,Stop…) — mỗi loại field khác nhau. - Theo tool được gọi (chỉ với Pre/Post) —
tool_inputkhá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:
SessionStartnạp context/env đầu phiên;UserPromptSubmitchèn context hoặc chặn prompt trước khi Claude đọc;Stopping tôi / chạy check cuối khi Claude xong;PreCompactlưu state trước khi lịch sử bị nén;Notificationbáo desktop khi Claude đang chờ tôi;SubagentStopgom 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àoPostToolUsematcher*). 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ênjq . > log.jsonquan 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 hooks —
query_hook.jsnhú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 Actionsallowed_tools, SDKoptions.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ỗiquery()là một lượt model tính tiền; một hook gọiquery()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 packageclaude-code(CLI) vsclaude-agent-sdk(thư viện) đúng bằng comment cảnh báo trongsdk.tscủ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:
- Tìm thư mục
.claudetrong project. - Tạo thư mục con
commandsbên trong. - 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:
- Chạy
npm audit— tìm package đã cài có lỗ hổng. - Chạy
npm audit fix— áp update. - 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 command là quy 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/reviewbám đúng checklist, một/deploy-checkchạ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.jsonlà file cá nhân, KHÔNG commit (giốngCLAUDE.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:
- Mở browser và navigate tới app.
- Generate một test component.
- Soi visual styling + code quality.
- Update chính prompt sinh code dựa trên quan sát.
- 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__playwrightlà mở nguyên quyền một server điều khiển browser — tiện nhưng để trongsettings.local.jsoncá 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:
- Install the Claude Code app trên GitHub.
- Add your API key.
- 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 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 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ẻ (VDmcp__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_toolsliệt kê tường minh chính là least-privilege — bot đứng ngoài tầm mắt, cầmfull 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ết → chờ 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.json → permissions.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 stdin → exit 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 (Read→file_path, Grep→pattern+path là thư mục, Bash→command) 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ÔNG có tool_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ử".