shunt · Claude Code

Model đắt không nên làm việc bưng bê file. Stop paying a frontier model to move files around.

Spotify cắt khoảng 90% token đọc file bằng một ý tưởng duy nhất: chặn việc đọc ngay tại ranh giới tool, đẩy phần I/O sang một model rẻ, và chỉ giữ lại phần suy luận cho model đắt. Spotify cut roughly 90% of its file-reading tokens with one idea: block the read at the tool boundary, push the I/O to a cheap model, and keep only the reasoning on the expensive one.

Claude Code → PreToolUse hook → bulk-read / code-write → worker model ngoài context của Claude outside Claude's context Claude Code model đắt expensive model Read · cat · head · tail PreToolUse hook > 350 ? cho qua passes file vào context file enters context gửi lại ở mọi lượt re-sent each turn chặn blocked bulk-read file + câu hỏi → XML files + question → XML bullets worker model rẻ cheap worker model temp 0.2 · bullets only Claude gọi thẳng, called by Claude, không qua cổng no gate code-write spec + reference (bắt buộc) spec + reference (required) disk — Claude không đọc lại disk — Claude never reads it
~90% token tiết kiệm (bulk-read)tokens saved (bulk-read) 350 dòng, ngưỡng mặc địnhlines, default threshold 10–30s mỗi lần uỷ thácper delegation

Trước hết: có thể bạn không cần gì cảFirst: you may need none of this

Phần lớn dự án dừng ở đây, và đó là kết quả đúng. Chỉ đi tiếp khi bạn đã làm hết mục này mà hoá đơn vẫn đau.Most projects stop here, and that is the right outcome. Go further only once you have exhausted this list and the bill still hurts.

  • Repo nhỏ. File trung bình dưới 350 dòng thì cổng chặn không bao giờ kích hoạt.Small repo. If the average file is under 350 lines, the gate never fires.
  • Đã biết cần đoạn nào. Read với offset + limit nạp đúng phần cần — rẻ nhất và chính xác nhất, không qua model trung gian.You know the section. Read with offset + limit loads exactly that — cheapest and most accurate, no intermediate model.
  • Câu hỏi trả lời được bằng tìm kiếm. rg -n trả về vài dòng thay vì cả file. Grep rẻ hơn mọi loại uỷ thác.Search answers the question. rg -n returns a few lines instead of a file. Grep beats every form of delegation.
  • Phiên ngắn. /clear sau mỗi task thì chi phí nhân-với-số-lượt không kịp tích tụ.Short sessions. /clear after each task and the multiply-by-turns effect never accumulates.
  • Việc cần suy luận sâu. Debug, kiến trúc, code liên quan an toàn — uỷ thác ở đây là mất tiền để mua rủi ro.Work that needs real reasoning. Debugging, architecture, safety-critical code — delegating there spends money to buy risk.
1 đọc có mục tiêu + rg — 0 công, 0 độ trễ
2 /clear thường xuyên, task nhỏ — 0 công
3 subagent cho khảo sát rộng — có sẵn
4 script uỷ thác + worker rẻ — nửa ngày
5 hook chặn cứng — thêm nửa ngày + bảo trì
1 targeted reads + rg — no effort, no latency
2 /clear often, smaller tasks — no effort
3 sub-agents for broad exploration — built in
4 delegation scripts + cheap worker — half a day
5 hard blocking hook — another half day + upkeep

Chọn cái nào, trong 30 giâyWhat to use, in 30 seconds

Đây là thứ dùng hằng ngày. Phần tra cứu chi tiết nằm bên dưới.This is the part you use daily. The reference sits below it.

Bạn sắp nạp thứ gì vào context?What are you about to load into context?

  • Biết chính xác đoạn cần đọc?Know the exact section? → Read với offset + limit. Dừng.→ Read with offset + limit. Stop.
  • Chỉ cần tìm một định danh, một chuỗi?Just hunting an identifier or a string? → rg -n. Dừng.Stop.
  • Cần hiểu nhiều file, nhưng sau đó sẽ SỬA chúng?Need several files, but you will EDIT them after? → Đọc trực tiếp. Bạn cần số dòng thật.→ Read directly. You need real line numbers.
  • Là debug, kiến trúc, hay code liên quan an toàn?Debugging, architecture, or safety-critical code? → Đọc trực tiếp. Đừng uỷ thác suy luận.→ Read directly. Never delegate reasoning.
  • Cần một bản đồ để định vị trong nhiều file?Need a map to orient across many files? → bulk-read, rồi đọc có mục tiêu phần quan trọng.→ bulk-read, then targeted-read what matters.
  • Cần sinh code lặp, và có file mẫu để chỉ vào?Generating repetitive code with a file to point at? → code-write --reference <mẫu>, chạy test ngay.→ code-write --reference <pattern>, run tests right after.
  • Cần sinh code nhưng chưa có mẫu?Generating code with no pattern yet? → Viết bằng model chính. Giữ file đó làm mẫu lần sau.→ Write it with the main model. Keep it as next time's pattern.

Sáu khái niệmSix concepts

Màu ở viền trái cho biết khái niệm thuộc nhóm nào — quy ước ghi ở cuối trang.The left edge colour says which family a concept belongs to — the convention is at the foot of the page.

01

PreToolUse hook

Cưỡng chếEnforcement

Một chương trình bên ngoài, chạy trước mỗi lần Claude gọi tool, nhận mô tả lời gọi qua stdin và có quyền huỷ lời gọi đó.An external program that runs before every tool call, receives the call description on stdin, and can cancel it.

Read(file_path="Service.java")
        │
        ▼   stdin: {"tool_name":"Read", ...}
   ┌─────────────┐
   │    hook     │
   └──┬───────┬──┘
 exit 0│       │exit 2 + stderr
      ▼       ▼
 tool chạy   huỷ lời gọi, stderr → Claude
 tool runs   call cancelled, stderr → Claude

Dùng choGood for

  • Chặn đọc nguyên file lớnBlocking whole-file reads
  • Chặn cat file khổng lồBlocking cat on huge files
  • Chặn đọc .env, khoá riêngBlocking .env and key reads

ĐượcGains

  • Hiệu lực không phụ thuộc model có chịu đọc hướng dẫnForce that doesn't depend on the model reading instructions
  • Bản thân hook tiêu 0 tokenThe hook itself costs zero tokens

MấtCosts

  • Sai exit code là hỏng cả luật, không có dấu hiệu nàoA wrong exit code kills the rule silently
  • Không kích hoạt với file tham chiếu bằng @Doesn't fire for files referenced with @

Đánh đổi.Trade-off. Chọn hook là đổi khả năng model tự xử lý ngoại lệ lấy sự chắc chắn rằng luật luôn được thi hành.A hook trades the model's ability to handle exceptions for the certainty that the rule is always enforced.

Dấu hiệu: nếu câu trả lời cho “model phớt lờ luật này thì sao?” là “hỏng”, luật đó thuộc về hook, không thuộc về prompt.Cue: if the answer to “what if the model ignores this?” is “something breaks”, the rule belongs in a hook, not a prompt.

02

Ngưỡng định tuyếnRouting threshold

Cưỡng chếEnforcement

Một số nguyên phân đôi thế giới: dưới ngưỡng đọc thẳng, trên ngưỡng uỷ thác. Mặc định 350 dòng, đổi qua SHUNT_MIN_LINES.One integer that splits the world: below it read directly, above it delegate. Default 350 lines, set via SHUNT_MIN_LINES.

5.000 dòng, đọc nguyên       → CHẶN
5,000 lines, whole file      → BLOCKED
5.000 dòng, offset+limit     → cho qua / passes
120 dòng / 120 lines         → cho qua / passes
cat huge.json                → CHẶN / BLOCKED
cat huge.json | jq '.name'   → cho qua / passes

Dùng choGood for

  • Repo Java/Kotlin file dài: ngưỡng thấp có lợiLong-file Java/Kotlin repos: low pays off
  • Repo JS/TS file nhỏ: nâng ngưỡng lênSmall-file JS/TS repos: raise it

ĐượcGains

  • Một con số chỉnh toàn bộ hành vi, không đụng logicOne number tunes everything, no logic change
  • Giữ nguyên đường đọc chính xác cho việc sửa codeKeeps the exact-read path for editing

MấtCosts

  • Số dòng là proxy tồi cho số tokenLine count is a poor proxy for tokens
  • Quá thấp: mọi thao tác nhỏ thành một lần chờ 10–30 giâyToo low: every small read becomes a 10–30s wait

Đánh đổi.Trade-off. Hạ ngưỡng là đổi độ trễ tương tác lấy token tiết kiệm được; nâng ngưỡng là đổi ngược lại.Lowering the threshold trades interactive latency for saved tokens; raising it trades the other way.

Dấu hiệu: nếu thời gian bạn ngồi chờ uỷ thác lớn hơn thời gian tiết kiệm được, ngưỡng đang quá thấp.Cue: if the wait for a delegation exceeds the time it saves, the threshold is too low.

03

bulk-read

Uỷ thácDelegation

Bọc mỗi file trong thẻ XML, gửi cả cụm kèm câu hỏi sang worker model, chỉ mang về câu trả lời dạng bullet.Wraps each file in XML tags, sends the set plus a question to the worker model, and brings back only bullets.

bulk-read --question "..." --paths A.java B.java

gửi / sent   → 1500 lines of code + question
             → worker (temp 0.2)
nhận / back  → • A.java:41 — handles signup webhook
               • B.java:23 — retries 3x, backoff

1500 dòng không bao giờ chạm phiên đắt tiền.
1500 lines never touch the expensive session.

Dùng choGood for

  • “Luồng xác thực đi qua file nào?”“Which files does the auth flow touch?”
  • “Chỗ nào gọi xuống database?”“Where do we call the database?”
  • Khảo sát thư mục lạ trước khi đọc kỹSurveying an unfamiliar directory

ĐượcGains

  • ~90% token trên kịch bản bulk-read (monorepo Java, 4 kịch bản)~90% of tokens on bulk-read scenarios (Java monorepo, 4 tests)
  • Hỏi tiếp trên cùng bộ file gần như miễn phíFollow-ups over the same files are near-free

MấtCosts

  • Tóm tắt không có số dòng đáng tin → không sửa code đượcNo reliable line numbers → you cannot edit from it
  • Worker bỏ lọt lỗi tinh vi (một lỗi thread-safety trong thử nghiệm)The worker misses subtle bugs (a thread-safety bug in testing)

Đánh đổi.Trade-off. Chọn bulk-read là đổi độ phân giải chi tiết và số dòng chính xác lấy khoảng 90% token đầu vào.bulk-read trades fine detail and exact line numbers for roughly 90% of the input tokens.

Dấu hiệu: bạn sắp nạp nhiều file chỉ để rút ra vài câu, và sẽ không sửa phần lớn số file đó.Cue: you're loading many files to extract a few sentences, and you won't edit most of them.

04

code-write

Uỷ thácDelegation

Nhận spec và một file tham chiếu bắt buộc, gửi sang worker, cắt bỏ markdown fence, ghi thẳng ra đĩa. Claude không đọc lại.Takes a spec and a required reference file, sends both to the worker, strips markdown fences, writes straight to disk. Claude never reads it back.

code-write --spec "tests for UserService" \
           --reference tests/OrderTest.java \
           --target    tests/UserTest.java

Claude thấy / sees      : "wrote tests/UserTest.java"
Claude KHÔNG thấy / not : 340 dòng test vừa sinh
                          the 340 generated lines

Dùng choGood for

  • File test thứ 21 giống 20 file bên cạnhThe 21st test file beside twenty others
  • Stub cấu hình, DTO, type định nghĩaConfig stubs, DTOs, type definitions
  • Sinh i18n cho ngôn ngữ mới từ file gốci18n files for a new locale

ĐượcGains

  • Cắt cả token vào lẫn token ra — loại đắt nhấtCuts input and output tokens — the expensive kind
  • Bám quy ước sẵn có vì luôn có mẫu đi kèmFollows existing conventions via the pattern

MấtCosts

  • Claude không biết nội dung vừa sinh; sửa sau là phải đọc lạiClaude doesn't know what it made; editing later means reading it
  • Không ai đọc trước khi file nằm trên đĩa — test là lưới duy nhấtNobody reviews before it lands — tests are the only net

Đánh đổi.Trade-off. Chọn code-write là đổi việc Claude nắm được nội dung vừa tạo lấy phần token output đắt nhất trong phiên.code-write trades Claude's awareness of what it just created for the most expensive output tokens in the session.

Dấu hiệu: bạn chỉ được vào một file và nói “giống cái này, nhưng cho X” — và câu đó đủ cho người mới làm đúng.Cue: you can point at a file and say “like this, but for X” — and a new hire would get it right from that.

05

Mode — worker khai báoMode — a declared worker

Uỷ thácDelegation

Agent khai báo: instructions, model, temperature, MCP tool. Chạy trên runtime tạm thời, gọi từ CLI hoặc API. Không server, không API key rải rác.A declarative agent: instructions, model, temperature, MCP tools. Runs on an ephemeral runtime, callable from CLI or API. No servers, no scattered API keys.

name: bulk-reader
model: gemini-2.5-flash
resourceLimits:
  temperature: 0.2
instructions: |
  Chỉ xuất bullet có cấu trúc. Không chào hỏi,
  không văn xuôi. Mỗi bullet bắt đầu bằng tên,
  kiểu, hoặc số dòng chính xác.
  Output structured bullets only. No greetings,
  no prose. Lead every bullet with the exact
  name, type, or line number.

Dùng choGood for

  • bulk-reader, code-writer
  • reviewer: đọc diff, trả rủi ro, không sửareviewer: read a diff, return risks, change nothing
  • doc-writer, translatordoc-writer, translator

ĐượcGains

  • Định tuyến model thành việc cấu hình, không phải dựng hạ tầngRouting becomes configuration, not infrastructure
  • Đổi worker chỉ là sửa một dòng; plugin không đổiSwapping the worker is one line; the plugin is untouched

MấtCosts

  • Gắn vào một nền tảng cụ thể (Portal, AiKA)Ties you to one platform (Portal, AiKA)
  • Hợp đồng đầu ra viết lỏng thì kết quả không dùng lại được bằng máyA loose output contract leaves output nothing can parse

Đánh đổi.Trade-off. Chọn mode là đổi sự độc lập nền tảng lấy việc không phải vận hành hạ tầng cho worker model.Modes trade platform independence for not having to operate worker infrastructure.

Dấu hiệu: dán cùng một đoạn hướng dẫn vào chat lần thứ ba thì nó nên là một mode.Cue: pasting the same instruction block a third time means it should be a mode.

06

Ba lớpThree layers

Chỉ dẫn → luậtAdvice → law

Ba cơ chế có mức hiệu lực khác nhau, xếp chồng để hệ thống suy giảm êm thay vì hỏng hoàn toàn.Three mechanisms with different levels of force, stacked so the system degrades gracefully instead of failing outright.

HOOK    chạy trước tool, có quyền từ chối   ← LUẬT
        runs before the tool, can refuse    ← LAW
SCRIPT  gọi CLI, báo token đã dùng          ← ĐƯỜNG
        calls the CLI, reports tokens       ← PATH
SKILL   markdown: khi nào, gọi thế nào      ← KHUYÊN
        markdown: when and how to call      ← ADVICE

v1: cùng luật đó nằm trong CLAUDE.md → bị bỏ qua
v1: the same rule in CLAUDE.md → ignored

Dùng choGood for

  • Luật bạn cần được tuân thủ, không chỉ mongRules you need obeyed, not merely hoped for
  • Quy ước cho cả team, chính sách bảo mậtTeam-wide conventions, security policy

ĐượcGains

  • Hỏng một lớp không làm sập cả hệ thốngOne layer failing doesn't take the system down
  • Cài một lần cho mọi repoInstalled once for every repo

MấtCosts

  • Ba thứ phải bảo trì và gỡ lỗiThree things to maintain and debug
  • Lệch giữa các lớp: hook chặn một luật, skill dạy luật khácDrift: the hook enforces one rule, the skill teaches another

Đánh đổi.Trade-off. Chọn ba lớp là đổi sự đơn giản của một file hướng dẫn lấy khả năng hệ thống vẫn đúng khi model không hợp tác.Three layers trade the simplicity of one instruction file for a system that holds when the model doesn't cooperate.

Dấu hiệu: viết luật vào markdown rồi thấy nó vẫn bị vi phạm — đó là lúc luật cần rơi xuống lớp dưới.Cue: the rule is in markdown and still gets violated — that's the rule asking to move down a layer.

Bảng đánh đổiTrade-off table

Cột đáng nhìn nhất là “mức cưỡng chế”. Hai hàng đầu tiết kiệm nhiều nhất mỗi lần dùng, nhưng phụ thuộc hoàn toàn vào việc model có tự giác hay không.The column worth staring at is “force”. The first two rows save the most per use, but depend entirely on the model choosing to comply.

Cơ chếMechanism Token tiết kiệmTokens saved Độ trễ thêmAdded latency Rủi ro sai lệchRisk of drift Công dựngBuild cost Mức cưỡng chếForce
Đọc có mục tiêuTargeted read CaoHigh0 Rất thấpVery low0 Tự giácVoluntary
rg / grep Rất caoVery high0 Rất thấpVery low0 Tự giácVoluntary
Luật trong CLAUDE.mdRules in CLAUDE.md Không đoán đượcUnpredictable0 ThấpLow Vài phútMinutes Khuyến nghịAdvisory
Skill Không đoán đượcUnpredictable0 ThấpLow Vài giờHours Khuyến nghịAdvisory
bulk-read ~90% đầu vào~90% of input 10–30 s Trung bìnhMedium Nửa ngàyHalf a day Con đường sẵnPath of least resistance
code-write Cắt cả đầu raCuts output too 10–30 s Cao nếu thiếu referenceHigh without a reference Nửa ngàyHalf a day Con đường sẵnPath of least resistance
Hook chặn cứngHard blocking hook Cao và ổn địnhHigh and stable0 ThấpLow Nửa ngàyHalf a day LuậtLaw

← kéo ngang để xem hết bảng← scroll sideways for the rest

Anti-patterns

Mười cách phổ biến để tự phá hỏng khoản tiết kiệm.Ten common ways to undo your own savings.

Viết luật định tuyến vào CLAUDE.md rồi coi là xongPutting routing rules in CLAUDE.md and calling it done

Luật ở đó là khuyến nghị; model bỏ qua được và mỗi repo cần một bản copy.Rules there are advisory; the model can ignore them and every repo needs a copy.

Hạ luật xuống lớp hook, giữ markdown làm phần hướng dẫn cú pháp.Move the rule down to the hook layer; keep markdown for syntax guidance.

Hook thoát bằng exit code 1 khi muốn chặnExiting a hook with code 1 to block

Chỉ exit 2 mới chặn; mã khác bị coi là lỗi không chặn và tool vẫn chạy.Only exit 2 blocks; other codes count as non-blocking errors and the tool still runs.

Dùng exit 2 kèm lý do ra stderr, hoặc JSON permissionDecision: "deny".Use exit 2 with the reason on stderr, or JSON permissionDecision: "deny".

Đặt ngưỡng rất thấp cho “tiết kiệm tối đa”Setting a very low threshold for “maximum savings”

Mỗi lần uỷ thác tốn 10–30 giây; dưới ngưỡng, phí tổn vượt khoản tiết kiệm.Every delegation costs 10–30 seconds; below the threshold the overhead exceeds the saving.

Đo phân bố độ dài file và p50 độ trễ, rồi chỉnh SHUNT_MIN_LINES.Measure file-length distribution and p50 latency, then tune SHUNT_MIN_LINES.

Gọi code-write không kèm --referenceCalling code-write without --reference

Không có mẫu, worker sinh code không khớp quy ước nào trong dự án.With no pattern, the worker generates code that matches nothing in the project.

Coi --reference là bắt buộc; thiếu thì script báo lỗi ngay.Treat --reference as mandatory; fail loudly in the script if it's missing.

Uỷ thác việc sửa codeDelegating edits

Tóm tắt của worker không có số dòng đáng tin.The worker's summaries carry no reliable line numbers.

Uỷ thác phần hiểu, đọc trực tiếp phần sửa.Delegate the understanding, read directly for the editing.

Uỷ thác debug và quyết định kiến trúcDelegating debugging and architecture

Worker bắt mẫu bề mặt; một lỗi thread-safety trong thử nghiệm đã bị bỏ lọt.The worker finds surface patterns; a thread-safety bug slipped past it in testing.

Loại trừ tường minh: debug, kiến trúc, code an toàn luôn ở model chính.Exclude explicitly: debugging, architecture and safety-critical code stay on the main model.

Để worker trả về markdown fence và lời giải thíchLetting the worker return markdown fences and prose

Phần dọn dẹp phía sau ăn lại chính khoản token vừa tiết kiệm.The cleanup downstream eats the tokens you just saved.

Ghi “chỉ xuất code” vào instruction và strip fence trong script.Put “output only the code” in the instruction and strip fences in the script.

Tin vào con số 90% cho repo của mìnhTrusting the 90% figure for your own repo

90% là trung bình trên monorepo Java nhiều mẫu lặp — gần với trường hợp tốt nhất.90% is a mean on a pattern-heavy Java monorepo — close to the best case.

Đo trên chính repo của bạn, trên vài kịch bản thật.Measure on your own repo, across a few real scenarios.

Không báo token đã dùngNot reporting token usage

Không đo thì không biết mình tiết kiệm hay chỉ chuyển chi phí sang chỗ khác.Without measurement you can't tell saving from cost-shifting.

Script in token usage ra stderr mỗi lần gọi.Have the script print token usage to stderr on every call.

Ghi đè file thật ngay từ lần chạy đầuOverwriting real files on the first run

Sai đường dẫn hoặc output tệ sẽ phá code đang chạy.A wrong path or a bad generation damages working code.

Chạy ra stdout trước, ghi vào đường dẫn mới, để git diff làm trọng tài.Run to stdout first, write to a new path, let git diff be the referee.

Ba câu cần nhớThree sentences to remember

  1. Phần lớn chi phí của một coding agent là I/O, không phải suy nghĩ — và I/O là thứ có thể chuyển sang model rẻ mà không mất gì đáng kể.Most of a coding agent's cost is I/O, not thinking — and I/O is exactly the part you can move to a cheap model without losing anything that matters.
  2. Cưỡng chế ở ranh giới tool, không cưỡng chế trong prompt — hướng dẫn là lời khuyên, hook là luật, và chỉ một trong hai còn hiệu lực khi model quyết định khác bạn.Enforce at the tool boundary, not in the prompt — instructions are advice, hooks are law, and only one of those still applies when the model decides otherwise.
  3. Uỷ thác việc hiểu, đừng uỷ thác việc sửa và việc suy luận — tóm tắt không có số dòng đáng tin, và model rẻ sẽ bỏ lọt đúng loại lỗi mà bạn thuê model đắt để bắt.Delegate understanding, never editing or reasoning — summaries carry no trustworthy line numbers, and the cheap model will miss exactly the class of bug you pay the expensive one to catch.