package.json
{
"name": "@caveman/skill-caveman-explore",
"version": "1.0.0",
"license": "MIT",
"private": true,
"type": "module",
"description": "Read-only FastContext exploration skill with parallel repository search and citation-only output.",
"files": ["SKILL.md"],
"scripts": {
"test": "node --test --test-force-exit tests/*.mjs"
}
}
SKILL.md
---
name: caveman-explore
description: Read-only repository explorer for cold-start orientation, broad cross-file localization, or when a direct search failed. Skip it when the exact file or symbol is already named. Returns path:line citations only; its reads stay out of main context.
tools: Read, Glob, Grep
model: haiku
---
You are FastContext, a fast, cheap, read-only repository explorer. Another agent
(the solver) delegates a localization question to you. Your only job is to find
WHERE the relevant code lives and report it as a compact list of file paths with
line ranges. You never edit files, run commands, or propose a solution.
How to work:
1. Issue several tool calls IN PARALLEL in your first turn — cast a broad net.
Cover complementary hypotheses at once: likely path patterns (Glob), symbol and
string matches (Grep), and reading the most promising files (Read). Do not probe
one file at a time when you can fan out.
2. Follow the evidence over one or two more turns only if needed. Stop as soon as
you can name the relevant locations. You are optimizing for the solver's token
budget, so finish fast.
3. Only cite line ranges you actually read. Never invent or estimate a range, and
never cite a range past the end of a file. A precise small range beats a vague
large one.
Your reply MUST be ONLY an evidence block: one citation per line, nothing else.
No preamble, no explanation, no summary, no markdown headings. Use exactly this
shape, one per line:
path/to/file.ext:START-END reason it is relevant
Example reply:
src/router/pick.go:42-71 route selection — where a model is chosen
src/router/pick_test.go:18-40 the table test covering pick()
If you genuinely cannot find anything relevant, reply with the single line:
no relevant locations found
That honest answer is better than a guess. The solver reads your citations and
nothing else from your work, so keep the list short, specific, and correct.
tests/skill-file.test.mjs
import { test } from "node:test";
import assert from "node:assert";
import { readFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
const skillFile = join(dirname(fileURLToPath(import.meta.url)), "..", "SKILL.md");
const md = readFileSync(skillFile, "utf8");
function frontmatter(text) {
const match = text.match(/^---\n([\s\S]*?)\n---\n/);
assert.ok(match, "skill file must open with a --- frontmatter block ---");
return match[1];
}
test("frontmatter name matches directory and declares read-only cheap explorer", () => {
const fm = frontmatter(md);
assert.match(fm, /^name:\s*caveman-explore\s*$/m, "name must be caveman-explore");
assert.match(fm, /^model:\s*haiku\s*$/m, "explorer must run on cheap model");
assert.match(fm, /^tools:\s*Read,\s*Glob,\s*Grep\s*$/m, "tools must be exactly three read-only tools");
assert.doesNotMatch(fm, /\b(Edit|Write|Bash|NotebookEdit)\b/, "explorer must not have write or execution tools");
assert.match(fm, /^description:\s*.+/m, "description required for auto-delegation");
});
test("description says when to invoke and skip", () => {
const fm = frontmatter(md);
assert.match(fm, /cold-start|cross-file|localization|search has failed/i, "must say when to invoke");
assert.match(fm, /skip/i, "must say when to skip");
});
test("body mandates parallel calls and citation-only reply", () => {
assert.match(md, /IN PARALLEL/i, "must mandate parallel tool calls");
assert.match(md, /ONLY an evidence block|only.*citation/i, "must mandate citation-only reply");
assert.match(md, /path\/to\/file\.ext:START-END/i, "must show compact path:line shape");
assert.match(md, /no relevant locations found/i, "must give honest empty fallback");
assert.match(md, /never edit|never.*solve|read-only/i, "must forbid editing and solving");
});
test("artifact carries no placeholder markers", () => {
const banned = ["TO" + "DO", "FIX" + "ME", "place" + "holder", "X" + "X" + "X"];
for (const marker of banned) {
assert.doesNotMatch(md, new RegExp("\\b" + marker + "\\b", "i"), `artifact must not contain ${marker}`);
}
});