T13 — Tool description .txt pattern
.txt riêng với template variable injection — description đóng vai trò như 'mini system prompt' cho từng tool.Tổng quan Tool Design
opencode giải quyết bằng cách tách description ra file .txt bên cạnh file .ts.
Bun (runtime của opencode) hỗ trợ import text file trực tiếp. Description hỗ trợ template variable như
{PLATFORM}, {SHELL}, {MAX_LINES} — được inject lúc tool khởi tạo.
Phân tích code chi tiết Anatomy
Cặp .ts + .txt cho mỗi tool
Mỗi tool trong opencode có cặp file:
tool/bash.ts — import và inject template
{`
import DESCRIPTION from "./bash.txt"
import { Tool } from "./tool"
export const BashTool = Tool.define("bash", Effect.gen(function* () => {
const agent = yield* Agent
return {
description: renderTemplate(DESCRIPTION, {
PLATFORM: process.platform,
SHELL: process.env.SHELL ?? "bash",
MAX_LINES: 2000,
}),
parameters: z.object({
command: z.string(),
timeout: z.number().optional(),
}),
// execute: ...
}
}))
`}tool/bash.txt — excerpt
{`
Execute shell commands in a persistent {SHELL} session on {PLATFORM}.
<important-rules>
- DO NOT use `find` or `grep` — use the dedicated Grep/Glob tools instead.
- Quote paths with spaces: cd "path with spaces"
- Output is truncated to {MAX_LINES} lines. Full output saved to disk.
- Prefer absolute paths to avoid cwd ambiguity.
</important-rules>
<when-to-use>
Use when you need to run build commands, install packages, execute tests,
or any shell operation not covered by specialized tools.
</when-to-use>
<when-not-to-use>
- Reading files: use Read tool instead (structured output)
- Searching code: use Grep/Glob tools instead (faster, scoped)
- Editing files: use Edit tool instead (fuzzy matching + validation)
</when-not-to-use>
`}Template variable injection
Hàm renderTemplate đơn giản — thay thế {KEY} trong text bằng giá trị tương ứng.
Điểm mạnh: description có thể tự điều chỉnh theo môi trường (Windows vs macOS vs Linux, bash vs zsh vs fish).
renderTemplate — generic implementation
{`
function renderTemplate(
template: string,
vars: Record<string, string | number>
): string {
return template.replace(/\{(\w+)\}/g, (_, key) => {
const val = vars[key]
if (val === undefined) throw new Error(`Template var {${key}} not provided`)
return String(val)
})
}
// A/B test: swap file nội dung mà không đổi code
const descriptionV2 = renderTemplate(await readFile("bash-v2.txt", "utf8"), vars)
`}Tương tác với kỹ thuật khác Interaction
T13 kết hợp chặt với các kỹ thuật sau:
- T14 (Effect lazy tool init): Template rendering xảy ra bên trong Effect.gen block — chỉ chạy 1 lần lúc define tool, không phải mỗi lần execute.
- T16 (Zod validation): Description và schema đi cùng nhau — description dạy model format args, Zod validate args nhận được.
- T27 (Model-specific system prompt): System prompt cũng dùng pattern .txt file (anthropic.txt, gpt.txt...) — T13 là ứng dụng của pattern đó cho tool-level.
Failure modes Failure
1. Template variable typo
Nếu .txt file dùng {PLATFROM} (typo) thay vì {PLATFORM}, hàm renderTemplate sẽ:
— Nếu strict: throw lúc tool init (tốt, fail fast). — Nếu không strict: để nguyên literal {PLATFROM} trong description → model thấy text rác.
{...} nào trong output.
2. Bundler không bundle .txt
Bun hỗ trợ text import native. Node.js không — cần loader hoặc đọc file thủ công lúc runtime. Nếu quên config, import sẽ trả undefined hoặc throw.
3. Description drift
Engineer sửa behavior của tool (code) nhưng quên update .txt → description mô tả sai hành vi thực → model dùng tool sai cách. Cần test đảm bảo description sync với behavior.
So sánh với các harness khác Compare
| Harness | Cách quản lý tool description | Nhận xét |
|---|---|---|
| opencode | File .txt riêng, template vars, import static | Sạch nhất, dễ A/B test |
| Claude Code | TypeScript template literal trong file source | Dài nhưng type-safe, khó version control riêng |
| Aider | Python docstring trong class | Gắn chặt với code, không template |
| Cline | Hardcoded string trong register() call | Đơn giản, không tách được |
| OpenHarness | Python string constant + f-string | Tương tự Aider nhưng hỗ trợ interpolation |
Implementation recipe Recipe
Áp dụng pattern này vào dự án của bạn
Nếu dùng Bun:
{`
// tsconfig.json — thêm để TypeScript hiểu text import
{
"compilerOptions": {
"moduleResolution": "bundler"
}
}
// my-tool.ts
import DESCRIPTION from "./my-tool.txt"
export const MyTool = defineTool({
name: "my_tool",
description: renderTemplate(DESCRIPTION, {
MAX_OUTPUT: 5000,
PLATFORM: process.platform,
}),
// ...
})
`}Nếu dùng Node.js (không có Bun text import):
{`
import { readFileSync } from "node:fs"
import { join, dirname } from "node:path"
import { fileURLToPath } from "node:url"
const __dirname = dirname(fileURLToPath(import.meta.url))
const DESCRIPTION = readFileSync(join(__dirname, "my-tool.txt"), "utf8")
`}