Empat prompt yang kamu ketik ulang jadi empat file
Ekstensi Claude Code adalah file yang bisa disimpan sebuah repo supaya kamu berhenti mengetik prompt yang sama berulang kali: sebuah skill, sebuah hook, sebuah subagent, dan sebuah server MCP. Kami menjalankan empat tugas yang sering berulang di satu repo nyata, sebuah API invoice kecil dengan file JSON sebagai databasenya. Setiap tugas awalnya diberi ekstensi yang salah, dan pilihan yang salah itu gagal di layar setiap kali. Lalu tiap tugas dijadikan file yang di-commit. Halaman ini membahas keempat caranya dan kartu pemilih yang menentukan jenis mana yang dipakai.
Dua hasil membingkai semua yang ada di bawah. Hook sering digambarkan sebagai jaminan dan aturan di memory file sebagai permintaan, tetapi hook pertama kami jalan, mencetak peringatannya, dan penulisan tetap lolos. Apa yang mengubah hook yang sekadar jalan menjadi hook yang memblokir dibahas di bagian hook. Server docs pertama yang kami pasang tidak mengubah apa pun, dan yang menjawab adalah server docs milik tool itu sendiri. Resep hook yang paling banyak disalin juga butuh file script terpisah, tetapi hook kami muat seluruhnya di file settings.
Sebelum menulis satu pun dari keempat file itu, kamu perlu tahu apa yang sudah dimuat sesimu.
Apa keempatnya, dan apa yang sudah dimuat sesimu
Ekstensi Claude Code adalah file yang kamu tambahkan ke repo supaya tidak perlu mengetik ulang instruksi yang sama ke kotak prompt. Ada empat jenis, dan pembaca yang sudah mengenalnya boleh langsung ke bagian berikutnya.
- Skill adalah runbook yang disimpan di repo-mu. Claude memuat langkahnya hanya saat pekerjaan itu muncul, dan kamu bisa menjalankannya dengan mengetik namanya.
- Hook mirip commit hook di git, tetapi untuk tindakan Claude sendiri. Ini script yang jalan pada sebuah event, seperti sebuah edit, apa pun niat Claude.
- Subagent adalah kontraktor dengan meja kosong. Ia menerima brief-mu, melakukan pembacaan, dan mengirim balik laporan, bukan tumpukannya.
- Server MCP adalah klien API yang bisa dipanggil Claude, untuk data yang tidak ada di disk-mu, seperti database atau docs sebuah tool.
Untuk mengukur apa pun, kamu perlu baseline dulu. Buka sesi baru dan jalankan perintah context. Ia mencetak tabel semua yang sudah dimuat sebelum kata pertamamu. Di bench kami, totalnya 26.2k token dari window 1m, tanpa baris memory files dan tanpa baris MCP sama sekali. Setiap tugas yang kamu berikan ke Claude mulai sekarang akan menambah satu baris ke tabel itu atau membiarkannya apa adanya.
Tugas pertama: checklist rilis jadi skill
Skill adalah checklist yang disimpan di foldernya sendiri dan baru dibaca Claude saat kamu memanggilnya. Tugas pertama adalah checklist rilis yang terus kamu tempel ke kotak prompt: typecheck, tes, naikkan versi, tambah satu baris changelog, commit, dan tag.
Tempat yang paling jelas adalah memory file, dan itu pilihan yang salah, karena semua isi file itu dimuat di setiap giliran dari setiap sesi. Kami taruh langkah-langkahnya di sana dan membaca lagi tabel context. Tabel itu bertambah satu baris Memory files sebesar 210 token, yang dimuat entah kamu sedang rilis atau tidak. Docs juga bilang begitu: ketika satu bagian file itu sudah tumbuh jadi prosedur, tempatnya di skill.
Pilihan yang benar adalah satu folder di bawah direktori skills dengan langkah-langkahnya di .claude/skills/release/SKILL.md, deskripsi singkat di bagian atas, dan satu baris frontmatter tambahan, disable-model-invocation: true. Baris itu menjauhkan skill dari daftar milik Claude sendiri, jadi hanya kamu yang bisa memulainya, dan itu yang kamu mau untuk sesuatu yang commit dan tag. Lalu kamu ketik garis miring dan namanya, dan checklist berjalan.
| Pembacaan context | Total | Baris Memory files |
|---|---|---|
| Baseline, sesi baru | 26.2k / 1m | tidak ada |
| Checklist di memory file | 26.4k / 1m | 210 token |
| Checklist sebagai skill | 26.2k / 1m | tidak ada, skill tidak terdaftar |
Saat kami menjalankannya, Claude menyelesaikan keenam langkah dalam waktu kurang dari semenit: typecheck, 34 tes, naik versi dari 0.4.0 ke 0.4.1, baris changelog, commit, dan tag. Ia juga menangkap kekurangan di checklist kami sendiri. Perintah commit seperti yang tertulis melewatkan file yang belum dilacak, jadi Claude men-stage changelog baru lebih dulu dan mengatakannya. Rilis kini jadi perintah yang kamu ketik, tersimpan di repo untuk seluruh tim, dan tidak memakan context sama sekali sampai kamu mengetiknya.
Tugas kedua: aturan yang harus tegak jadi hook
Hook adalah script yang dijalankan Claude Code sebelum sebuah tool aktif, di sini sebelum edit atau write apa pun, dan jawaban script itu menentukan apa yang terjadi berikutnya. Tugas kedua adalah aturan yang tidak boleh dilanggar: di repo ini file data tersimpan tidak pernah diedit manual, dan setiap perubahan lewat migrasi.
Menulis aturan itu dengan huruf kapital di memory file tidak menegakkannya. Docs tegas soal ini: file itu adalah context, bukan konfigurasi yang ditegakkan, dan instruksi seperti "jangan pernah edit file ini" adalah permintaan, bukan jaminan, sedangkan hook yang memblokir edit adalah penegakan.
Hook pertama yang paling jelas adalah yang kami tulis. Di file settings, ia memantau penulisan ke file data, mencetak peringatan, dan keluar dengan exit code nol, seperti script logging. Lalu kami minta Claude mengubah jumlah sebuah invoice langsung di file, tanpa migrasi. Hook jalan dan peringatan tercetak, tetapi penulisan lolos: harga satuan invoice ketiga berubah dari 8000 jadi 12000. Balasan Claude tidak pernah menyebut hook itu, karena hook yang keluar bersih dan tidak mencetak apa-apa tidak membuat keputusan, dan peringatannya tidak pernah sampai ke Claude.
Jaminannya bukan hook yang jalan, melainkan jawaban yang dikembalikannya. Perbaikannya mempertahankan hook yang sama dan membuatnya mengembalikan keputusan deny: satu baris JSON pendek berisi alasan yang ingin kamu agar Claude baca. Keluar dengan exit code dua memblokir dengan cara yang sama. Seluruh hook adalah satu perintah inline di .claude/settings.json, tanpa file script:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -c 'if (.tool_input.file_path // \"\") | test(\"data/.*\\\\.json$\") then {hookSpecificOutput: {hookEventName: \"PreToolUse\", permissionDecision: \"deny\", permissionDecisionReason: \"Stored data is never edited by hand: write a migration in src/store/migrations.ts (README § Conventions).\"}} else empty end'"
}
]
}
]
}
}
Dengan permintaan yang sama, edit ditolak dan file data tetap utuh. Claude melihat error ini: PreToolUse:Edit hook error: Stored data is never edited by hand: write a migration in src/store/migrations.ts (README § Conventions). Ia bilang tidak mengubah apa pun dan bertanya apakah pagar pengaman ini mau di-override atau migrasinya ditulis.
Batasnya, yang disebut Claude sendiri: hook ini hanya memantau tool edit dan write, dan pada run berikutnya Claude menawarkan membuat perubahan itu lewat shell. Hook harus mencakup shell juga, atau shell harus dijauhkan dari daftar allow-mu, karena penjagaan yang hanya menutup satu pintu tetap hanyalah permintaan. Hook tidak memakan context sama sekali, karena ia jalan di luar percakapanmu.
Tugas ketiga: audit yang membanjiri jadi subagent
Subagent adalah sesi Claude terpisah dengan context kosongnya sendiri. Ia menerima brief-mu, membaca yang ia perlukan, dan hanya ringkasan yang kembali. Tugas ketiga adalah audit yang membanjiri thread-mu: cek setiap file di folder source terhadap konvensi README, dan daftar setiap pelanggaran lengkap dengan file dan barisnya.
Kalau diminta inline, Claude membaca setiap file ke dalam percakapanmu, dan semua isi itu tetap di sana sepanjang sisa sesi. Pada run kami, Claude membaca ke-19 file source, baris Messages di tabel context membengkak, dan temuannya terkubur di bawah tumpukan.
Pilihan yang benar adalah file di bawah .claude/agents/, di sini .claude/agents/conventions-auditor.md, dengan nama, deskripsi kapan dipakai, tool yang boleh dipakainya, dan model yang di-pin. Mem-pin model itu penting, karena kalau tidak, subagent mewarisi model apa pun yang dipakai sesimu, dan sebagian besar tugas membaca tidak butuh yang besar.
Kami mengajukan pertanyaan yang persis sama lagi, dan Claude membaca file itu sendiri. Dalam kedua percobaan ia tidak pernah memanggil agent itu, padahal terdaftar: 0 dari 2 delegasi. Yang berhasil adalah menyebut namanya di awal prompt: "use the conventions auditor subagent". Satu panggilan keluar dan ringkasan pendek kembali.
| Run | Total context | Baris Messages |
|---|---|---|
| Audit inline | 46.1k | 19.3k |
| Subagent yang disebut namanya | 34.1k | 7.2k |
Temuannya sama bagusnya: subagent menangkap bug path yang terlewat di run inline, dan melewatkan satu yang ditemukan run inline. Jadi file membuat subagent itu ada, dan prompt-mu membuat Claude memakainya; sampai Claude memilihnya sendiri, kamu yang menyebut namanya. Satu batasan: tagihannya tidak bergerak. Kedua run biayanya sama, karena pembacaan tetap terjadi, hanya tidak di window-mu.
Tugas keempat: data yang tak terjangkau Claude jadi server MCP
Server MCP adalah klien API yang bisa dipanggil Claude, dan tugas yang membuatnya ada adalah data yang lebih baru dari model atau data yang berada di luar disk-mu. Pilihan refleks di sini salah, jadi kami membuatnya lebih dulu.
Kami memasang server docs publik untuk library tes kami dan meminta Claude membuat tes dengan fake timer. Tidak ada yang berubah: Claude sudah mengenal library itu, dan hanya memanggil server saat kami menyebutnya. Docs yang sudah diketahui model bukan data yang tak terjangkau olehnya.
Ujian yang sebenarnya adalah pertanyaan tentang Claude Code sendiri, tentang setting hook yang lebih baru dari model: setting mana yang membuat hook yang gagal memblokir, versi berapa yang menambahkannya, dan JSON persisnya seperti apa. Tanpa server, Claude membaca schema settings dari instalasinya sendiri, tidak menemukan apa-apa, dan menjawab bahwa ia tidak menemukan setting itu dan tidak akan menebak. Jawaban itu jujur tetapi tidak berguna, karena setting itu ada; ia datang setelah pengetahuan model.
Perbaikannya adalah menambahkan server docs milik Claude Code sendiri ke repo, dengan scope project supaya konfigurasinya masuk ke file di root repo yang didapat seluruh timmu:
claude mcp add --transport http claude-docs --scope project https://code.claude.com/docs/mcp
Ini menulis .mcp.json. Claude Code mencantumkan server sebagai pending sampai kamu menyetujuinya di sesi berikutnya, dan sejak itu tool-nya tersedia untuk Claude. Kami mengajukan pertanyaan yang sama dengan kata-kata biasa, tanpa menyebut nama server. Claude mencari di docs, menemukan halamannya, dan menjawab dengan setting, versi, dan JSON yang harus ditambahkan, beserta tautannya.
Setting-nya adalah "onFailure": "block", yang membuat hook yang gagal memblokir tindakan alih-alih membiarkannya lolos. Setting ini muncul di v2.1.295, sementara instalasi kami masih 2.1.294. Itulah batasnya: Claude tidak pernah bilang bahwa instalasi kami tidak bisa memakainya, karena ia tidak memeriksa versi, jadi periksa sendiri versimu. Di tabel context, server itu muncul hanya sebagai nama tool-nya, dimuat sesuai kebutuhan sampai Claude meraih salah satunya.
Empat file, satu kartu pemilih
Setelah keempat tugas, git status menunjukkan tepat empat file, karena hook tidak butuh script sendiri:
.claude/skills/release/SKILL.md.claude/settings.json.claude/agents/conventions-auditor.md.mcp.json
Commit semuanya, dan sesi berikutnya di repo ini punya semuanya, begitu juga siapa pun yang meng-clone-nya.
Alasan tiap pilihan tepat adalah tabel yang disediakan docs, yang bisa kamu simpan sebagai kartu keputusan:
| Situasi | Ekstensi |
|---|---|
| Prosedur yang kamu tempel lagi dan lagi | Skill |
| Sesuatu yang harus terjadi setiap kali, tanpa bertanya | Hook |
| Tugas sampingan yang membanjiri percakapanmu dengan output yang tidak akan kamu baca lagi | Subagent |
| Data yang terus kamu salin dari tempat yang tidak terlihat Claude | Server MCP |
Jenis-jenis ini juga bisa digabung. Docs memasangkan skill dengan server MCP: server menyediakan koneksi, dan skill mengajari Claude cara memakainya dengan baik. Sebuah skill juga bisa jalan di dalam subagent yang di-fork, sehingga pembacaannya tetap di luar window-mu. Ketika repo lain butuh setup yang sama, plugin adalah kotak yang mengirim semuanya sekaligus.
Kartu ini menentukan jenis, bukan kualitas. Hook yang hanya mencatat log, subagent yang tidak pernah kamu sebut namanya, dan server untuk docs yang sudah diketahui model, semuanya berada di jenis yang tepat dan tetap gagal. Pilih jenis dari kartu, lalu buat file itu menjawab, bukan sekadar ada.
Putusan: kapan masing-masing, kapan tidak ada, satu aturan
Keempat tugas yang dulu kamu ketik ulang semuanya dicoba dengan cara salah dulu, gagal di layar, dan sekarang menjadi file di repo yang bekerja. Rilis adalah perintah yang kamu ketik. Aturan data adalah hook yang menolak edit dan membuat Claude bertanya. Audit kembali sebagai ringkasan. Pertanyaan docs mendapat setting dan versi yang tak bisa ditemukan Claude sendirian.
Hook yang kami buka dengannya, yang jalan dan membiarkan penulisan lolos, mengajarkan aturan di balik semua ini: hook hanya memutuskan lewat apa yang dikembalikan perintahnya, jadi hook yang hanya mencatat log adalah permintaan yang berkostum.
Beberapa kasus tidak memerlukan satu pun dari ini:
- Konvensi yang terus salah dilakukan Claude tetap di memory file, sebagai satu baris, bukan sebagai prosedur.
- Tugas yang perlu kamu arahkan bolak-balik, dengan riwayatmu terlihat, tetap di thread utama dan bukan di subagent.
- Server docs untuk library yang sudah diketahui model memakan context dan tidak mengubah apa pun. Hubungkan yang tidak bisa dimiliki model, bukan yang sudah ia punya.
Aturan yang perlu diingat: beri setiap tugas yang kamu ketik ulang filenya sendiri, pilih jenisnya dari kartu, dan ingat bahwa di antara semuanya, hanya hook yang tidak pernah bertanya.
AIDive