Apa itu harness engineering? Panduan teruji untuk Codex dan Claude Code
Pelajari harness engineering lewat kasus Codex, batas peran manusia-AI, pengaman file, dan pengujian Node.js.
Sebuah tim meminta agen AI merapikan repository. Agen itu kemudian mengubah konfigurasi yang tidak berkaitan dengan tugas dan menutup pekerjaannya dengan kalimat “semua tes berhasil”. Tanpa catatan command, exit code, dan batas file yang boleh disentuh, tim tidak punya bukti bahwa hasilnya aman.
Masalahnya bukan sekadar prompt yang kurang rinci. Kita juga perlu menentukan informasi yang dapat dilihat agen, alat yang boleh digunakan, kondisi untuk berhenti, serta bukti yang diterima sebagai tanda selesai. Perancangan sistem di sekeliling agen inilah yang disebut harness engineering. Untuk pemula, bayangkan harness sebagai pijakan kerja: agen tetap bisa melakukan pekerjaan berguna tanpa diberi hak untuk mengambil semua keputusan.
Panduan ini memakai studi kasus Codex yang diterbitkan OpenAI sebagai dasar, lalu membangun harness kecil yang dapat diterapkan pada Claude Code atau agen lain. Contohnya membatasi akses file, menolak penimpaan file, dan menyediakan tes yang bisa dijalankan tanpa biaya API.
Poin utama
- Harness bukan satu wrapper script. Ia menggabungkan pengetahuan repository, tools, permissions, tests, logs, recovery, dan persetujuan manusia.
- Dalam studi kasus Codex, OpenAI membuat struktur repository, perilaku aplikasi, dan aturan kualitas dapat dibaca serta diuji oleh agen.
- Agen dapat menangani riset, draft, dan pekerjaan berulang. Penghapusan, perubahan production, komunikasi eksternal, dan pengeluaran tetap memerlukan keputusan manusia.
- Pengecekan awalan teks pada path bukan sandbox lengkap. Symbolic link, overwrite, process privilege, dan isolasi sistem operasi juga perlu diperhitungkan.
- Istilah “sudah diuji” harus menyebutkan command, hasil, dan scope. Pesan sukses dari model bukan bukti.
Arti harness engineering dalam pekerjaan sehari-hari
Prompt menjelaskan apa yang diminta pada satu pekerjaan. Harness menentukan lingkungan tempat instruksi itu dijalankan.
| Lapisan | Pertanyaan yang dijawab | Contoh minimal |
|---|---|---|
| Context | Apa yang boleh dipelajari agen? | AGENTS.md, folder terfokus, spesifikasi berversi |
| Tools | Apa yang boleh dilakukan? | Membaca, menguji, dan membuat draft |
| Permissions | Kapan agen harus berhenti? | Persetujuan manusia untuk menghapus atau mengirim |
| Verification | Apa arti “selesai”? | npm test keluar dengan status 0 |
| Observability | Bagaimana kegagalan ditelusuri? | Command, diff, dan bagian error yang relevan |
| Recovery | Bagaimana pekerjaan buruk dibatalkan? | Commit kecil, dry-run, dan langkah rollback |
Mengganti model tidak akan mengungkap aturan bisnis yang hanya tersimpan di ingatan seseorang. Sebaliknya, agen lebih dapat diandalkan ketika informasi penting mudah ditemukan di repository dan acceptance criteria dapat dijalankan sebagai pemeriksaan otomatis.
Mengapa istilah ini ramai pada 2026: studi kasus Codex
Salah satu sumber utama pembahasan saat ini adalah artikel OpenAI yang diterbitkan pada 11 Februari 2026, Harness engineering: leveraging Codex in an agent-first world.
OpenAI melaporkan bahwa tiga engineer menggunakan Codex untuk menghasilkan sekitar 1.500 pull requests dalam kurang lebih lima bulan. Angka tersebut menarik, tetapi bukan pelajaran utamanya. Tim merancang ulang lingkungan kerja dengan asumsi bahwa agen akan mengerjakan implementasi, bukan manusia yang mengetik setiap baris kode.
Pendekatan yang dijelaskan mencakup:
- menyimpan rencana dan keputusan desain sebagai artefak berversi di repository;
- membuat UI, logs, metrics, dan traces dapat diperiksa langsung oleh agen;
- menegakkan arah dependency dan aturan lain dengan structural tests serta custom linters;
- memperlakukan run yang gagal sebagai tanda kurangnya tool, rule, atau abstraction, bukan sekadar meminta model “mencoba lebih keras”;
- menjalankan pembersihan rutin untuk menemukan dokumentasi lama dan drift yang menumpuk.
Ini bukan ajakan membuat system prompt yang sangat panjang. Pengetahuan yang hanya ada di chat, dokumen eksternal, atau kepala seseorang tidak terlihat saat agen bekerja. Targetnya adalah entry point kecil dan stabil yang mengarah ke sumber terfokus, ditambah checks yang membuat aturan penting tidak dapat dilewati.
Claude Code mendukung pola yang sama. Dokumentasi resmi hooks Claude Agent SDK menjelaskan cara memeriksa permintaan tool, menolaknya, mengubah input, atau mencatatnya untuk audit. Setiap produk memiliki kontrol berbeda, tetapi harness tetap bertanggung jawab atas batas dan feedback loop.
Bagian untuk AI dan keputusan untuk manusia
Jangan memulai dengan otonomi penuh. Otomatiskan pekerjaan yang mudah dikembalikan terlebih dahulu, lalu minta persetujuan untuk tindakan yang memengaruhi pelanggan, uang, atau production.
| Otomatisasi awal yang aman | Delegasikan dengan syarat | Keputusan manusia |
|---|---|---|
| Mencari file | Mengedit file yang ada | Menghapus data production |
| Menjalankan tes | Menambah dependency | Mengirim e-mail pelanggan |
| Merangkum diff | Deploy ke staging | Mengubah billing atau kontrak |
| Membuat draft | Push branch | Memproses data pribadi sensitif |
Ajukan dua pertanyaan untuk setiap tindakan: apakah kesalahan bisa dibatalkan dengan biaya rendah, dan apakah tindakan ini berdampak pada pihak di luar tim? Mulailah dari akses baca dan output sementara. Jadikan sebuah operasi otomatis hanya setelah kondisi berhasil dan gagalnya dapat diamati.
Membangun harness minimal
Contoh berikut hanya memberi model dua kemampuan:
- membaca teks di dalam
sandbox; - membuat file teks baru di dalam
sandbox.
Tidak ada tool untuk menghapus, menimpa, menjalankan shell, atau mengakses jaringan. Contoh diperiksa dengan Node.js 22, dan versi SDK dikunci pada versi yang digunakan saat verifikasi.
mkdir harness-demo
cd harness-demo
npm init -y
npm install @anthropic-ai/[email protected]
mkdir sandbox
echo "# meeting notes" > sandbox/note.md
Buat policy.json:
{
"workspace": "./sandbox",
"maxSteps": 6,
"maxToolResultChars": 4000
}
1. Terapkan batas file di dalam kode
Buat safe-files.mjs. Pemeriksaan seperti candidate.startsWith(root) saja tidak cukup: folder dengan nama mirip dapat cocok, dan symbolic link di dalam workspace dapat mengarah ke luar. Jalur baca di bawah memeriksa target yang sebenarnya, sedangkan penulisan dibatasi hanya untuk file baru.
import { open, readFile, realpath } from "node:fs/promises";
import path from "node:path";
function assertInside(root, candidate) {
if (candidate !== root && !candidate.startsWith(root + path.sep)) {
throw new Error(`outside workspace: ${candidate}`);
}
}
export async function createFileGate(workspace) {
const root = await realpath(path.resolve(workspace));
async function readText(relativePath) {
const requested = path.resolve(root, relativePath);
assertInside(root, requested);
const actual = await realpath(requested);
assertInside(root, actual);
return readFile(actual, "utf8");
}
async function createText(relativePath, content) {
const requested = path.resolve(root, relativePath);
assertInside(root, requested);
const actualParent = await realpath(path.dirname(requested));
assertInside(root, actualParent);
let handle;
try {
handle = await open(requested, "wx", 0o600);
await handle.writeFile(content, "utf8");
} catch (error) {
if (error.code === "EEXIST") {
throw new Error(`refusing to overwrite: ${relativePath}`);
}
throw error;
} finally {
await handle?.close();
}
return "created";
}
return { readText, createText };
}
Ini adalah pengaman pada tingkat aplikasi, bukan batas keamanan lengkap. Untuk isolasi yang lebih kuat, gunakan container, virtual machine, permission sistem operasi, atau sandbox dari produk. Pemeriksaan aplikasi tidak dapat menetralkan proses dengan hak administrator.
2. Berikan hanya dua tools kepada model
Buat agent.mjs. Nama model diambil dari ANTHROPIC_MODEL, bukan dikunci di artikel, karena akses akun dan ketersediaan model dapat berubah.
import Anthropic from "@anthropic-ai/sdk";
import { readFile } from "node:fs/promises";
import { createFileGate } from "./safe-files.mjs";
const model = process.env.ANTHROPIC_MODEL;
if (!model) throw new Error("Set ANTHROPIC_MODEL to a model available to your account.");
const policy = JSON.parse(await readFile("./policy.json", "utf8"));
const gate = await createFileGate(policy.workspace);
const client = new Anthropic();
const tools = [
{
name: "read_file",
description: "Read a UTF-8 text file inside the workspace",
input_schema: {
type: "object",
properties: { path: { type: "string" } },
required: ["path"],
additionalProperties: false
}
},
{
name: "create_file",
description: "Create a new UTF-8 file; existing files cannot be overwritten",
input_schema: {
type: "object",
properties: {
path: { type: "string" },
content: { type: "string" }
},
required: ["path", "content"],
additionalProperties: false
}
}
];
async function runTool(name, input) {
if (name === "read_file") return gate.readText(input.path);
if (name === "create_file") return gate.createText(input.path, input.content);
throw new Error(`unknown tool: ${name}`);
}
const prompt = process.argv.slice(2).join(" ") ||
"Read note.md and create summary.md with a three-line summary.";
const messages = [{ role: "user", content: prompt }];
for (let step = 0; step < policy.maxSteps; step += 1) {
const response = await client.messages.create({
model,
max_tokens: 1200,
system: "Use only the supplied tools. Never claim a file was created unless the tool succeeded.",
tools,
messages
});
messages.push({ role: "assistant", content: response.content });
const calls = response.content.filter((block) => block.type === "tool_use");
if (calls.length === 0) {
console.log(response.content.find((block) => block.type === "text")?.text ?? "done");
process.exit(0);
}
const results = [];
for (const call of calls) {
try {
const value = await runTool(call.name, call.input);
results.push({
type: "tool_result",
tool_use_id: call.id,
content: String(value).slice(0, policy.maxToolResultChars)
});
} catch (error) {
results.push({
type: "tool_result",
tool_use_id: call.id,
is_error: true,
content: error.message
});
}
}
messages.push({ role: "user", content: results });
}
throw new Error(`step limit exceeded: ${policy.maxSteps}`);
3. Uji pengaman sebelum memanggil model
Batas yang paling penting dapat diuji secara lokal tanpa memakai kredit API. Buat safe-files.test.mjs:
import assert from "node:assert/strict";
import test from "node:test";
import { mkdtemp, mkdir, rm, symlink, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import path from "node:path";
import { createFileGate } from "./safe-files.mjs";
test("file gate blocks traversal, overwrite, and outside symlinks", async () => {
const base = await mkdtemp(path.join(tmpdir(), "harness-test-"));
const root = path.join(base, "sandbox");
const outside = path.join(base, "outside.txt");
try {
await mkdir(root);
await writeFile(path.join(root, "note.md"), "hello", "utf8");
await writeFile(outside, "secret", "utf8");
const gate = await createFileGate(root);
assert.equal(await gate.readText("note.md"), "hello");
await assert.rejects(() => gate.readText("../outside.txt"), /outside workspace/);
await assert.rejects(() => gate.createText("note.md", "replace"), /refusing to overwrite/);
try {
await symlink(outside, path.join(root, "outside-link.txt"), "file");
await assert.rejects(() => gate.readText("outside-link.txt"), /outside workspace/);
} catch (error) {
if (error.code !== "EPERM") throw error;
}
assert.equal(await gate.createText("summary.md", "safe"), "created");
} finally {
await rm(base, { recursive: true, force: true });
}
});
Jalankan pemeriksaan offline:
node --test safe-files.test.mjs
node --check agent.mjs
Setelah itu barulah atur ANTHROPIC_API_KEY dan ANTHROPIC_MODEL, kemudian jalankan node agent.mjs. Jangan simpan kredensial di source control atau policy.json.
Tiga use case praktis
1. Tim software: mengerjakan dan memverifikasi pull request
Berikan issue yang terfokus, directory yang relevan, serta command pengujian. “Kode sudah ditulis” bukan acceptance condition. Minta reproduksi yang gagal sebelum perbaikan, tes yang berhasil sesudahnya, dan diff yang mudah dibaca. Production deploy dan migration tetap menunggu persetujuan manusia.
2. Operasi media: menyaring artikel sebelum terbit
Pisahkan pembuatan artikel dari pemeriksaan topik ganda, kedalaman, sintaks kode, link, dan tampilan mobile. Kegagalan satu check harus menghentikan publikasi dan mengembalikan pesan perbaikan yang spesifik. Dengan begitu, kalimat “artikel sudah siap” dari agen tidak menggantikan bukti.
3. Layanan pelanggan: mengelompokkan pertanyaan dan membuat draft
Agen dapat mengelompokkan pesan dan membuat draft jawaban beserta alasannya. Manusia menyetujui perubahan data pelanggan dan pengiriman yang sebenarnya. Berikan hanya data pribadi yang diperlukan dan hindari menyalin seluruh isi pesan ke log jangka panjang.
Menghitung ROI secara sederhana
Ukur waktu review manusia dan rework yang berkurang, bukan jumlah token yang dibuat. Misalnya, 15 tugas per minggu masing-masing memerlukan review 20 menit: totalnya lima jam. Jika harness membutuhkan enam jam untuk dibuat dan maintenance turun menjadi satu jam per minggu, waktu pembangunan awal dapat kembali dalam sekitar satu setengah minggu.
Ini ilustrasi, bukan jaminan. Ukur selama dua minggu sebelum dan sesudah penerapan:
- menit kerja manusia per tugas;
- tingkat rework;
- defect yang ditemukan sebelum production;
- jumlah eskalasi untuk persetujuan manusia.
Terlalu banyak permintaan approval dapat berarti operasi berisiko rendah yang sudah terbukti bisa diotomatisasi dalam batas lebih sempit. Jika defect atau rework naik, tambahkan pemeriksaan atau context yang lebih jelas, bukan otonomi yang lebih luas.
Pitfall dan cara memperbaikinya
Menganggap pemeriksaan nama folder sebagai sandbox
Sebuah path bisa terlihat berada di workspace padahal symbolic link mengarah ke luar. Periksa target sebenarnya, tolak overwrite, dan gunakan permission sistem operasi sebagai batas kedua.
Hanya menulis “jangan lakukan hal berbahaya” di prompt
Teks adalah panduan, bukan pemaksaan. Jangan berikan tool berbahaya atau tolak lewat pre-tool hook. Lihat panduan permissions Claude Code untuk contoh konfigurasi.
Menerima pesan “semua tes lolos” dari model
Catat command, exit status, dan verification scope. Perubahan UI juga memerlukan interaksi langsung atau bukti screenshot. Alur verification receipt menjelaskan cara menyimpan bukti tersebut.
Mengirim semua dokumen pada setiap run
Context panjang dapat menenggelamkan batas yang paling penting. Berikan entry point kecil yang mengarah ke sumber terfokus dan berversi. Catat freshness dan verification status agar dokumentasi lama mudah ditemukan.
Langkah berikutnya
Pilih satu alur yang mudah dikembalikan, lalu tulis empat baris: input, tindakan yang diizinkan, acceptance command, dan tindakan yang perlu approval manusia. Untuk menerapkan permissions, verification, dan review gates pada repository nyata, gunakan pelatihan dan konsultasi implementasi Claude Code.
Hasil pengujian yang sebenarnya
Pada 21 Juli 2026, blok safe-files.mjs dan safe-files.test.mjs dari artikel ini diekstrak ke directory sementara lalu dijalankan dengan Node.js. Fixture menguji pembacaan normal, pembuatan file baru, penolakan traversal ../, dan penolakan overwrite. Pada sistem yang mengizinkan proses tes membuat symbolic link, fixture juga memastikan link ke luar ditolak. agent.mjs melewati pemeriksaan sintaks.
Panggilan langsung ke Anthropic API tidak termasuk dalam verification scope karena akses model dan biaya berbeda antar akun. “Kode diterbitkan”, “sintaks diperiksa”, “tes offline dijalankan”, dan “API eksternal berbayar dipanggil” adalah empat klaim berbeda. Harness yang dapat dipercaya mencatat klaim mana yang benar.
Artikel terkait
Claude Agent SDK: masukkan Claude Code ke app dengan aman
Setup terbaru Claude Agent SDK, permission, MCP, contoh runnable, dan pitfall production.
Claude Code vs Codex, akhirnya pilih yang mana? Solusi nyata "memakai keduanya" tanpa kecelakaan
Codex dan Claude Code, mana jago di mana dan tugas mana dioper ke mana? Cara memakai keduanya dengan aman plus cerita kegagalan saya.
Prompt Engineering Lanjutan untuk Claude Code dan Codex: Task Brief yang Bisa Diverifikasi
Rancang prompt Claude Code/Codex dengan task brief, acceptance criteria, verifikasi, dan iterasi aman.
PDF gratis: cheatsheet Claude Code
Masukkan email dan unduh satu halaman berisi command, kebiasaan review, dan workflow aman.
Kami menjaga datamu dan tidak mengirim spam.
Tentang penulis
Masa
Engineer yang berfokus pada workflow Claude Code praktis dan adopsi tim.