greprag 5.84.0 → 5.85.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/agent-doctrine-file.js +5 -128
- package/dist/commands/agents.js +125 -846
- package/dist/commands/init.js +17 -29
- package/dist/commands/load.js +14 -36
- package/dist/commands/parity.js +1 -1
- package/dist/commands/skill-mirror-reminder.js +1 -18
- package/dist/commands/skill.js +137 -566
- package/dist/hook.js +30 -54
- package/dist/index.js +571 -573
- package/dist/native-adapter-refresh.js +15 -18
- package/dist/native-skill-mirror.js +11 -92
- package/dist/opencode-plugin.bundle.js +81 -283
- package/dist/skill-activation-manifest.js +14 -37
- package/dist/skill-git-ingest.js +300 -0
- package/dist/skill-landing.js +7 -173
- package/dist/skill-mirror-client.js +4 -280
- package/dist/skill-staleness.js +3 -6
- package/package.json +1 -1
- package/skill/mechanic/docs/skill-fix-conventions.md +1 -1
- package/skill/templates/os.md +1 -1
- package/skill/templates/prompt-audit.md +26 -49
- package/skill/templates/skill-change.md +15 -13
|
@@ -1,15 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/** Skill
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* shadows "last used state." Best-effort end to end: a mirror failure never
|
|
7
|
-
* touches the turn.
|
|
8
|
-
*
|
|
9
|
-
* Local freshness state (`~/.greprag/state/skill-mirror.json`) remembers the
|
|
10
|
-
* last-mirrored hash per skill so an unchanged skill costs one hash pass and
|
|
11
|
-
* ZERO network. Markdown only, v1 — SKILL.md + docs/**\/*.md; script-bearing
|
|
12
|
-
* assets stay file-bound (see the spec's named gaps). */
|
|
2
|
+
/** Skill package reader: the markdown a mirrored skill carries (SKILL.md +
|
|
3
|
+
* docs/**\/*.md) and its content hash. Used to verify an export and to send a
|
|
4
|
+
* loadout. The mirror itself is written only by git ingestion
|
|
5
|
+
* (skill-git-ingest.ts, adr/skill-ownership-git.md). */
|
|
13
6
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
7
|
if (k2 === undefined) k2 = k;
|
|
15
8
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -44,44 +37,11 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
44
37
|
};
|
|
45
38
|
})();
|
|
46
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
47
|
-
exports.skillRevisionAuthor = skillRevisionAuthor;
|
|
48
40
|
exports.collectSkillFiles = collectSkillFiles;
|
|
49
41
|
exports.computeMirrorHash = computeMirrorHash;
|
|
50
|
-
exports.dryRunNativeSkillAdoption = dryRunNativeSkillAdoption;
|
|
51
|
-
exports.syncNativeSkillAdoptions = syncNativeSkillAdoptions;
|
|
52
|
-
exports.readMirrorState = readMirrorState;
|
|
53
|
-
exports.writeMirrorState = writeMirrorState;
|
|
54
|
-
exports.maybeMirrorSkill = maybeMirrorSkill;
|
|
55
42
|
const fs = __importStar(require("fs"));
|
|
56
43
|
const path = __importStar(require("path"));
|
|
57
|
-
const skill_landing_1 = require("./skill-landing");
|
|
58
|
-
const native_skill_adoption_1 = require("./native-skill-adoption");
|
|
59
|
-
const native_skill_mirror_1 = require("./native-skill-mirror");
|
|
60
44
|
const skill_mirror_files_1 = require("./skill-mirror-files");
|
|
61
|
-
const proc_1 = require("./proc");
|
|
62
|
-
/** Who is writing skill canon, for the revision row every write records:
|
|
63
|
-
* the writer (`via`), the harness session, and the chip branch when the
|
|
64
|
-
* write runs inside one. adr: adr/skill-revision-history.md */
|
|
65
|
-
function skillRevisionAuthor(via, opts = {}) {
|
|
66
|
-
const env = process.env;
|
|
67
|
-
const harness = opts.harness
|
|
68
|
-
|| (env.CLAUDE_CODE_SESSION_ID || env.CLAUDECODE ? 'claude-code'
|
|
69
|
-
: env.CODEX_THREAD_ID || env.CODEX_CI || env.CODEX_SHELL ? 'codex'
|
|
70
|
-
: env.OPENCODE_SESSION_ID ? 'opencode' : 'cli');
|
|
71
|
-
const sessionId = opts.sessionId || env.CLAUDE_CODE_SESSION_ID || env.CODEX_THREAD_ID
|
|
72
|
-
|| env.OPENCODE_SESSION_ID || env.GREPRAG_SESSION_ID || '';
|
|
73
|
-
let chip = '';
|
|
74
|
-
try {
|
|
75
|
-
const branch = (0, proc_1.safeSpawnSync)('git', ['branch', '--show-current'], {
|
|
76
|
-
cwd: opts.cwd || process.cwd(), encoding: 'utf8', timeout: 3000,
|
|
77
|
-
});
|
|
78
|
-
const name = String(branch.stdout || '').trim();
|
|
79
|
-
if (branch.status === 0 && name.startsWith('chip/'))
|
|
80
|
-
chip = name;
|
|
81
|
-
}
|
|
82
|
-
catch { /* not a git checkout */ }
|
|
83
|
-
return { via, harness, ...(sessionId ? { sessionId } : {}), ...(chip ? { chip } : {}) };
|
|
84
|
-
}
|
|
85
45
|
/** Mirrors the server's caps (SKILL_MIRROR_* in @greprag/core — the CLI is
|
|
86
46
|
* core-free, so the numbers are restated; the server re-validates anyway). */
|
|
87
47
|
const MAX_FILES = 20;
|
|
@@ -141,239 +101,3 @@ function collectSkillFiles(skillDir) {
|
|
|
141
101
|
function computeMirrorHash(files) {
|
|
142
102
|
return (0, skill_mirror_files_1.computeSkillFileHash)(files);
|
|
143
103
|
}
|
|
144
|
-
function dryRunNativeSkillAdoption(params) {
|
|
145
|
-
return (0, native_skill_adoption_1.planNativeSkillAdoption)({ ...params, collectFiles: collectSkillFiles });
|
|
146
|
-
}
|
|
147
|
-
function adoptedSkillId(candidate) {
|
|
148
|
-
return candidate.scope === 'project'
|
|
149
|
-
? `project:${candidate.projectId}:${candidate.skillName}`
|
|
150
|
-
: `global:${candidate.skillName}`;
|
|
151
|
-
}
|
|
152
|
-
async function responseJson(response) {
|
|
153
|
-
try {
|
|
154
|
-
return await response.json();
|
|
155
|
-
}
|
|
156
|
-
catch {
|
|
157
|
-
return {};
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
async function ensureNativeAdoptionOriginalSnapshot(params) {
|
|
161
|
-
const skillId = adoptedSkillId(params.candidate);
|
|
162
|
-
const snapshotPath = `/v1/skillmirror/${encodeURIComponent(params.candidate.skillName)}/snapshots/original`;
|
|
163
|
-
const body = {
|
|
164
|
-
scope: params.candidate.scope,
|
|
165
|
-
projectId: params.candidate.projectId,
|
|
166
|
-
skillId,
|
|
167
|
-
source: 'disk',
|
|
168
|
-
sourceRef: path.join(params.candidate.root, params.candidate.skillName),
|
|
169
|
-
reason: 'captured native skill package before GrepRAG adapter adoption',
|
|
170
|
-
};
|
|
171
|
-
const created = await fetch(`${params.apiUrl}${snapshotPath}`, {
|
|
172
|
-
method: 'POST',
|
|
173
|
-
headers: { 'Authorization': `Bearer ${params.apiKey}`, 'Content-Type': 'application/json' },
|
|
174
|
-
body: JSON.stringify(body),
|
|
175
|
-
});
|
|
176
|
-
if (created.ok)
|
|
177
|
-
return true;
|
|
178
|
-
if (created.status !== 409)
|
|
179
|
-
return false;
|
|
180
|
-
const query = new URLSearchParams({
|
|
181
|
-
scope: params.candidate.scope,
|
|
182
|
-
skillId,
|
|
183
|
-
...(params.candidate.projectId ? { projectId: params.candidate.projectId } : {}),
|
|
184
|
-
});
|
|
185
|
-
const existing = await fetch(`${params.apiUrl}${snapshotPath}?${query.toString()}`, {
|
|
186
|
-
method: 'GET',
|
|
187
|
-
headers: { 'Authorization': `Bearer ${params.apiKey}` },
|
|
188
|
-
});
|
|
189
|
-
if (!existing.ok)
|
|
190
|
-
return false;
|
|
191
|
-
const data = await responseJson(existing);
|
|
192
|
-
const snapshot = data.snapshot;
|
|
193
|
-
return snapshot?.contentHash === params.candidate.sourceHash;
|
|
194
|
-
}
|
|
195
|
-
async function syncNativeSkillAdoptions(params) {
|
|
196
|
-
const plan = dryRunNativeSkillAdoption(params);
|
|
197
|
-
const result = {
|
|
198
|
-
plan,
|
|
199
|
-
adopted: 0,
|
|
200
|
-
blocked: plan.blocked.length,
|
|
201
|
-
skipped: plan.skipped.length,
|
|
202
|
-
};
|
|
203
|
-
if (params.dryRun)
|
|
204
|
-
return result;
|
|
205
|
-
for (const candidate of plan.candidates) {
|
|
206
|
-
const body = {
|
|
207
|
-
files: candidate.files,
|
|
208
|
-
contentHash: candidate.sourceHash,
|
|
209
|
-
scope: candidate.scope,
|
|
210
|
-
projectId: candidate.projectId,
|
|
211
|
-
projectName: candidate.projectName,
|
|
212
|
-
reason: `adoption of native ${params.platform} skill from ${path.join(candidate.root, candidate.skillName)}`,
|
|
213
|
-
author: skillRevisionAuthor('adoption', { cwd: params.projectDir }),
|
|
214
|
-
};
|
|
215
|
-
const response = await fetch(`${params.apiUrl}/v1/skillmirror/${encodeURIComponent(candidate.skillName)}`, {
|
|
216
|
-
method: 'POST',
|
|
217
|
-
headers: { 'Authorization': `Bearer ${params.apiKey}`, 'Content-Type': 'application/json' },
|
|
218
|
-
body: JSON.stringify(body),
|
|
219
|
-
});
|
|
220
|
-
if (!response.ok) {
|
|
221
|
-
result.blocked++;
|
|
222
|
-
continue;
|
|
223
|
-
}
|
|
224
|
-
const snapshotted = await ensureNativeAdoptionOriginalSnapshot({
|
|
225
|
-
apiUrl: params.apiUrl,
|
|
226
|
-
apiKey: params.apiKey,
|
|
227
|
-
candidate,
|
|
228
|
-
});
|
|
229
|
-
if (!snapshotted) {
|
|
230
|
-
result.blocked++;
|
|
231
|
-
continue;
|
|
232
|
-
}
|
|
233
|
-
const installed = (0, native_skill_adoption_1.installAdoptedNativeSkill)({
|
|
234
|
-
platform: params.platform,
|
|
235
|
-
root: candidate.root,
|
|
236
|
-
expectedSourceHash: candidate.sourceHash,
|
|
237
|
-
collectFiles: collectSkillFiles,
|
|
238
|
-
skill: {
|
|
239
|
-
skillName: candidate.skillName,
|
|
240
|
-
skillId: adoptedSkillId(candidate),
|
|
241
|
-
scope: candidate.scope,
|
|
242
|
-
projectId: candidate.projectId,
|
|
243
|
-
projectName: candidate.projectName,
|
|
244
|
-
files: candidate.files,
|
|
245
|
-
},
|
|
246
|
-
});
|
|
247
|
-
if (installed === 'installed')
|
|
248
|
-
result.adopted++;
|
|
249
|
-
else if (installed === 'blocked')
|
|
250
|
-
result.blocked++;
|
|
251
|
-
else
|
|
252
|
-
result.skipped++;
|
|
253
|
-
}
|
|
254
|
-
return result;
|
|
255
|
-
}
|
|
256
|
-
function materializeLocally(skillName, files, cwd) {
|
|
257
|
-
for (const platform of native_skill_mirror_1.NATIVE_SKILL_ADAPTER_PLATFORMS) {
|
|
258
|
-
try {
|
|
259
|
-
(0, native_skill_mirror_1.applyNativeSkillMirror)({
|
|
260
|
-
platform,
|
|
261
|
-
skills: [{
|
|
262
|
-
skillName,
|
|
263
|
-
skillId: `global:${skillName}`,
|
|
264
|
-
scope: 'global',
|
|
265
|
-
contentHash: computeMirrorHash(files),
|
|
266
|
-
files,
|
|
267
|
-
}],
|
|
268
|
-
projectDir: cwd,
|
|
269
|
-
prune: false,
|
|
270
|
-
});
|
|
271
|
-
}
|
|
272
|
-
catch { /* local adapter failure never breaks turn capture */ }
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
function statePath() {
|
|
276
|
-
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
277
|
-
return path.join(home, '.greprag', 'state', 'skill-mirror.json');
|
|
278
|
-
}
|
|
279
|
-
function readMirrorState() {
|
|
280
|
-
try {
|
|
281
|
-
const parsed = JSON.parse(fs.readFileSync(statePath(), 'utf-8'));
|
|
282
|
-
if (parsed && typeof parsed.skills === 'object' && parsed.skills) {
|
|
283
|
-
return { skills: parsed.skills };
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
catch { /* missing/unreadable → empty */ }
|
|
287
|
-
return { skills: {} };
|
|
288
|
-
}
|
|
289
|
-
function writeMirrorState(state) {
|
|
290
|
-
try {
|
|
291
|
-
const file = statePath();
|
|
292
|
-
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
293
|
-
fs.writeFileSync(file, JSON.stringify(state, null, 2) + '\n');
|
|
294
|
-
}
|
|
295
|
-
catch { /* best-effort — worst case is one redundant upload next use */ }
|
|
296
|
-
}
|
|
297
|
-
async function fetchRemoteSkillHash(params) {
|
|
298
|
-
try {
|
|
299
|
-
const res = await fetch(`${params.apiUrl}/v1/skillmirror/${encodeURIComponent(params.skill)}?scope=global`, {
|
|
300
|
-
headers: { 'Authorization': `Bearer ${params.apiKey}` },
|
|
301
|
-
});
|
|
302
|
-
if (res.status === 404)
|
|
303
|
-
return null;
|
|
304
|
-
if (!res.ok)
|
|
305
|
-
return null;
|
|
306
|
-
const data = await responseJson(res);
|
|
307
|
-
return typeof data.contentHash === 'string' ? data.contentHash : null;
|
|
308
|
-
}
|
|
309
|
-
catch {
|
|
310
|
-
return null;
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
/** Mirror one skill if its content changed since the last mirror. Never throws. */
|
|
314
|
-
async function maybeMirrorSkill(params) {
|
|
315
|
-
try {
|
|
316
|
-
if (!/^[A-Za-z0-9._-]{1,64}$/.test(params.skill))
|
|
317
|
-
return 'skipped';
|
|
318
|
-
const homeDir = process.env.HOME || process.env.USERPROFILE || '';
|
|
319
|
-
const dir = (0, skill_landing_1.resolveSkillDir)(params.skill, params.cwd, homeDir);
|
|
320
|
-
if (!dir)
|
|
321
|
-
return 'skipped';
|
|
322
|
-
const files = collectSkillFiles(dir);
|
|
323
|
-
if (!files)
|
|
324
|
-
return 'skipped';
|
|
325
|
-
// The disk copy of an already-mirrored skill is the generated ADAPTER that
|
|
326
|
-
// `materializeLocally` wrote below — a launcher whose whole body says "run
|
|
327
|
-
// `greprag load <name>`". Uploading it makes it canon, and `greprag load`
|
|
328
|
-
// then serves the launcher back to the agent that was told to run it: the
|
|
329
|
-
// skill's real instructions are gone and nothing errors. That loop closed
|
|
330
|
-
// here, one turn after every first mirror, and had already eaten the
|
|
331
|
-
// canonical body of skills including anti-ai, chrome, gmail and root-cause.
|
|
332
|
-
//
|
|
333
|
-
// An adapter is never a mirror source. Canon changes through the guarded
|
|
334
|
-
// edit path (`greprag skill edit` / `skill mirror apply`), never by
|
|
335
|
-
// shadowing a file greprag itself generated. adr: adr/skill-adapter-never-canon.md
|
|
336
|
-
const main = files.find(file => file.path === 'SKILL.md');
|
|
337
|
-
if (main && (0, skill_mirror_files_1.isGeneratedSkillAdapter)(main.content))
|
|
338
|
-
return 'skipped';
|
|
339
|
-
const hash = computeMirrorHash(files);
|
|
340
|
-
const state = readMirrorState();
|
|
341
|
-
const localLease = state.skills[params.skill]?.hash;
|
|
342
|
-
if (localLease === hash) {
|
|
343
|
-
materializeLocally(params.skill, files, params.cwd);
|
|
344
|
-
return 'fresh';
|
|
345
|
-
}
|
|
346
|
-
if (!localLease) {
|
|
347
|
-
const remoteHash = await fetchRemoteSkillHash(params);
|
|
348
|
-
if (remoteHash === hash) {
|
|
349
|
-
state.skills[params.skill] = { hash, mirroredAt: new Date().toISOString() };
|
|
350
|
-
writeMirrorState(state);
|
|
351
|
-
materializeLocally(params.skill, files, params.cwd);
|
|
352
|
-
return 'fresh';
|
|
353
|
-
}
|
|
354
|
-
if (remoteHash)
|
|
355
|
-
return 'skipped';
|
|
356
|
-
}
|
|
357
|
-
const res = await fetch(`${params.apiUrl}/v1/skillmirror/${encodeURIComponent(params.skill)}`, {
|
|
358
|
-
method: 'POST',
|
|
359
|
-
headers: { 'Authorization': `Bearer ${params.apiKey}`, 'Content-Type': 'application/json' },
|
|
360
|
-
body: JSON.stringify({
|
|
361
|
-
files,
|
|
362
|
-
contentHash: hash,
|
|
363
|
-
scope: 'global',
|
|
364
|
-
expectedHash: localLease,
|
|
365
|
-
reason: params.reason || `shadow upload of local edit from ${dir}`,
|
|
366
|
-
author: skillRevisionAuthor('shadow-upload', { cwd: params.cwd, sessionId: params.sessionId }),
|
|
367
|
-
}),
|
|
368
|
-
});
|
|
369
|
-
if (!res.ok)
|
|
370
|
-
return 'skipped';
|
|
371
|
-
state.skills[params.skill] = { hash, mirroredAt: new Date().toISOString() };
|
|
372
|
-
writeMirrorState(state);
|
|
373
|
-
materializeLocally(params.skill, files, params.cwd);
|
|
374
|
-
return 'mirrored';
|
|
375
|
-
}
|
|
376
|
-
catch {
|
|
377
|
-
return 'skipped';
|
|
378
|
-
}
|
|
379
|
-
}
|
package/dist/skill-staleness.js
CHANGED
|
@@ -358,7 +358,7 @@ function formatSkillStaleness(report, options = {}) {
|
|
|
358
358
|
lines.push('1. Pause trusting this skill; read the changed watched source files/diffs first.');
|
|
359
359
|
lines.push('2. Classify relevance: low relevance or small delta -> use repo source as truth; no chip.');
|
|
360
360
|
lines.push('3. If this task depends on the stale area and the delta is material, spawn a skill-refresh chip.');
|
|
361
|
-
lines.push('4. The refresh chip
|
|
361
|
+
lines.push('4. The refresh chip edits the skill\'s git folder (~/.claude/skills/<name>/ in dotclaude, or <repo>/.claude/skills/<name>/) and commits; the mirror follows.');
|
|
362
362
|
}
|
|
363
363
|
if (report.projects.some(p => p.dirtyPaths.length > 0)) {
|
|
364
364
|
lines.push('Baseline rule: do not stamp a new baseline while watched local edits are dirty.');
|
|
@@ -372,11 +372,8 @@ function formatSkillNoSourceBinding(skillName) {
|
|
|
372
372
|
return [
|
|
373
373
|
'[greprag skill-staleness - no source binding]',
|
|
374
374
|
`/${skillName} has no source bindings.`,
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
`Agent-safe edit path: \`greprag skill mirror export ${skillName} --to <dir>\`, patch the exported Markdown files non-interactively, then \`greprag skill mirror apply <dir> --skill ${skillName} --expected-hash <exported-hash> --reason "<why>"\`.`,
|
|
378
|
-
`Human editor shortcut: \`greprag skill edit ${skillName} --reason "<why>"\`; Codex auto-skips the editor, and agents may pass \`--no-open\` explicitly.`,
|
|
379
|
-
`After binding a real source repo, stamp it with \`greprag skill source stamp ${skillName} --project <p> --path <rel>\`.`,
|
|
375
|
+
`Authority: git. Edit ~/.claude/skills/${skillName}/ (dotclaude) or <repo>/.claude/skills/${skillName}/ and commit; GrepRAG mirrors the committed files read only. Codex/OpenCode SKILL.md files are generated launchers, never content.`,
|
|
376
|
+
`To watch a source repo, stamp a binding into the git SKILL.md with \`greprag skill source stamp ${skillName} --project <p> --path <rel>\`, then commit.`,
|
|
380
377
|
].join('\n') + '\n';
|
|
381
378
|
}
|
|
382
379
|
function stampSourceBinding(params) {
|
package/package.json
CHANGED
|
@@ -53,6 +53,6 @@ Each: **signature** (how it shows up in the run) · **location** (where it lives
|
|
|
53
53
|
|
|
54
54
|
- **One friction, one edit.** If a run surfaced two defects, make two separate edits, each shown for its own accept/revert. Never batch.
|
|
55
55
|
- **Apply + show diff.** Make the edit, then show the unified diff and stop for one accept/revert. (This is the operator-chosen gate; the Mechanic "always confirm" rule still holds.)
|
|
56
|
-
- **Edit the
|
|
56
|
+
- **Edit the git source and commit.** Global skills: `~/.claude/skills/<name>/` (dotclaude repo); project skills: `<repo>/.claude/skills/<name>/`; greprag-bundled skills: `packages/cli/skill/<name>/`. The commit message names the friction this fixes. Never edit a generated Codex/OpenCode launcher or the installed copy of a bundled skill.
|
|
57
57
|
- **Line budget:** a fix must not grow SKILL.md without adding a real proactive-fire rule or per-task step. Converting wallpaper → Convention B is net-neutral or smaller; mis-route adds at most one line.
|
|
58
58
|
- **Out of taxonomy → spawn, don't improvise.** Anything not matching the six becomes one `greprag fix spawn --type doctrine "<unit>"` chip. `greprag fix log` is only for deliberate audit/design notes.
|
package/skill/templates/os.md
CHANGED
|
@@ -31,7 +31,7 @@ conversation. The registration is part of the work, not an extra:
|
|
|
31
31
|
|
|
32
32
|
- **Docs** mirror through `greprag doc mirror sync` and can still auto-register
|
|
33
33
|
pointers when edited in a live session. Search/read them through the CLI.
|
|
34
|
-
- **Skills**
|
|
34
|
+
- **Skills** live in git (`~/.claude/skills/<name>/` or `<repo>/.claude/skills/<name>/`); commit them and the mirror follows (`greprag load` serves them cross-machine).
|
|
35
35
|
- **Decisions** get a dated entry in the owning ADR / decision log, in the
|
|
36
36
|
same commit as the code.
|
|
37
37
|
- **Everything else** (state files, artifacts, conventions) gets its path
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Prompt Audit — dated-model cruft in
|
|
1
|
+
# Prompt Audit — dated-model cruft in agent instructions
|
|
2
2
|
|
|
3
3
|
<!-- adr: adr/prompt-audit-canon.md -->
|
|
4
4
|
|
|
@@ -14,56 +14,35 @@ local skill adapters may not override it.
|
|
|
14
14
|
|
|
15
15
|
## The one invariant
|
|
16
16
|
|
|
17
|
-
**AUDIT FINDINGS LAND IN
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
`
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
That single command advances canon (optimistic concurrency, `expectedRevision`)
|
|
26
|
-
and materializes every follower for the scope. Nothing else writes a follower.
|
|
17
|
+
**AUDIT FINDINGS LAND IN THE GIT SOURCE, NEVER IN A RENDERED FILE.**
|
|
18
|
+
`~/.claude/CLAUDE.md` in the dotclaude repo is the global source; a repo's
|
|
19
|
+
`CLAUDE.md` and `AGENTS.md` are ordinary files in that repo.
|
|
20
|
+
`~/.codex/AGENTS.md` and `~/.config/opencode/AGENTS.md` are rendered from
|
|
21
|
+
`~/.claude/CLAUDE.md` plus `~/.claude/instructions/<codex|opencode>.md` by
|
|
22
|
+
`greprag instructions render` (session start runs it), so an edit there is
|
|
23
|
+
overwritten. GrepRAG's copy (`greprag load instructions`) is read only and
|
|
24
|
+
follows the last commit.
|
|
27
25
|
|
|
28
26
|
## Procedure
|
|
29
27
|
|
|
30
|
-
1. **Scope and target model.**
|
|
31
|
-
|
|
28
|
+
1. **Scope and target model.** Global audits `~/.claude/CLAUDE.md`; repo
|
|
29
|
+
audits the current repo's `CLAUDE.md`/`AGENTS.md`. Target
|
|
32
30
|
model is the one Claude Code sessions run today (Claude Fable 5.1 as of
|
|
33
31
|
2026-09). State both at the top of the report; do not ask.
|
|
34
|
-
2. **
|
|
35
|
-
`
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
auditing, or the audit will grade a stale canon.
|
|
40
|
-
Overlays: `instructions` canon is `shared` + per-harness raw suffixes. When
|
|
41
|
-
a suffix is non-empty, audit each harness render separately and land
|
|
42
|
-
suffix edits with `instructions overlay set|derive`, never by pulling a
|
|
43
|
-
rendered file as `shared`. When all suffixes are empty (check the document
|
|
44
|
-
via the API or `overlay` history), the Claude render **is** `shared` and
|
|
45
|
-
`pull` of the revised Claude render is exact.
|
|
46
|
-
3. **Provenance.** The Claude follower is usually Git-tracked
|
|
47
|
-
(`~/.claude` dotclaude repo; repo files in the repo). `git log`/`git blame`
|
|
32
|
+
2. **Read the source.** Global: `~/.claude/CLAUDE.md` plus any
|
|
33
|
+
`~/.claude/instructions/<harness>.md` addition; audit each addition
|
|
34
|
+
separately. Repo: that repo's `CLAUDE.md` and `AGENTS.md`. Confirm the
|
|
35
|
+
rendered files are current with `greprag instructions status`.
|
|
36
|
+
3. **Provenance.** Every source file is in git. `git log`/`git blame`
|
|
48
37
|
each emphatic or prohibitive line: which failure, on which model, did it
|
|
49
38
|
prevent, and does it still reproduce on the target model?
|
|
50
39
|
4. **Classify every line** with the rubric below. Produce the report and the
|
|
51
40
|
proposed diff, both, always.
|
|
52
|
-
5. **Land.**
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
greprag instructions status --scope <scope> # every follower fresh
|
|
58
|
-
```
|
|
59
|
-
Medium findings and flags stay in the report for the operator; they are
|
|
60
|
-
applied by a later `pull` of an operator-approved revision, the same way.
|
|
61
|
-
If the follower lives in a Git repo, the push dirties it; the operator
|
|
62
|
-
commits that repo (the audit never runs git there).
|
|
63
|
-
6. **Write the report** to `tasks/prompt-audit-<scope>-<date>.md` in the
|
|
64
|
-
repo you are working in (or scratch if the repo has no `tasks/`), in the
|
|
65
|
-
shape under "Report shape". Persona (`greprag persona show`) is a separate
|
|
66
|
-
system: note Persona findings in the report; never edit it from here.
|
|
41
|
+
5. **Land.** Apply ONLY high-confidence hunks to the source file, show the
|
|
42
|
+
diff, and leave the commit to the operator (the audit never runs git in
|
|
43
|
+
their repos). After the commit, `greprag instructions render` rewrites the
|
|
44
|
+
AGENTS.md files and refreshes GrepRAG's copy. Medium findings and flags
|
|
45
|
+
stay in the report for the operator.
|
|
67
46
|
|
|
68
47
|
## Rubric (shipped copy — Anthropic prompt-audit, condensed, binding)
|
|
69
48
|
|
|
@@ -166,12 +145,12 @@ returns 400; prefill is replaced by structured outputs.
|
|
|
166
145
|
## Report shape
|
|
167
146
|
|
|
168
147
|
Top: Assumptions (scope, target model), Inventory (what was audited and its
|
|
169
|
-
|
|
148
|
+
source commit), Summary (counts per group; two or three highest-impact
|
|
170
149
|
findings in prose). Then one entry per finding, ordered by confidence:
|
|
171
150
|
|
|
172
151
|
| Field | Content |
|
|
173
152
|
|---|---|
|
|
174
|
-
| Location | `file:line` in the
|
|
153
|
+
| Location | `file:line` in the source file |
|
|
175
154
|
| Evidence | exact quoted text |
|
|
176
155
|
| Pattern | the group/row above |
|
|
177
156
|
| Why obsolete | one or two sentences tied to the target model's documented behavior |
|
|
@@ -185,12 +164,10 @@ only when tests, docs, and references to the removed text go too).
|
|
|
185
164
|
|
|
186
165
|
## Guardrails
|
|
187
166
|
|
|
188
|
-
- Never edit `~/.
|
|
189
|
-
|
|
190
|
-
The only follower writer is `instructions push` (or `pull --push`).
|
|
167
|
+
- Never edit `~/.codex/AGENTS.md` or `~/.config/opencode/AGENTS.md` by
|
|
168
|
+
hand: they are rendered. Edit `~/.claude/CLAUDE.md` or the harness addition.
|
|
191
169
|
- Apply high-confidence hunks only. Medium and flag items wait for the
|
|
192
170
|
operator.
|
|
193
|
-
-
|
|
194
|
-
--snapshot <name> --scope <scope>` followed by `pull` of the restored file.
|
|
171
|
+
- Rollback is `git revert` on the source file.
|
|
195
172
|
- Persona is out of scope for edits; note findings only.
|
|
196
173
|
- Out of taxonomy friction: `greprag fix spawn "<one unit>"`.
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Skill Change
|
|
2
2
|
|
|
3
|
-
Use before creating, porting, optimizing, or changing a
|
|
3
|
+
Use before creating, porting, optimizing, or changing a skill, and when a loaded skill guided work approaching a delivery boundary.
|
|
4
4
|
|
|
5
5
|
## Authority
|
|
6
6
|
|
|
7
|
-
This is an internal bundled GrepRAG schema, not tenant-controlled skill content.
|
|
7
|
+
This is an internal bundled GrepRAG schema, not tenant-controlled skill content. Skills and their mirrors may not override it. Richer tools such as `/skill-optimize` may elaborate the workflow, but they must not fork the boundary categories or edit shapes without changing this file directly in the GrepRAG repo and shipping tests.
|
|
8
8
|
|
|
9
9
|
Skill Creator and Skill Optimize consume this entry as their common authoring contract. Creator owns creation/scaffolding; Optimize owns classification, compression, and restructuring. Neither maintains a competing copy of these conventions.
|
|
10
10
|
|
|
@@ -25,7 +25,7 @@ Skill Creator and Skill Optimize consume this entry as their common authoring co
|
|
|
25
25
|
- Preserve the full required skill package. Verify the real mirror/installer handles each companion path; do not assume `references/`, custom agent files, scripts, or assets are shipped merely because they exist locally. Adapt packaging or explicitly declare the separate dependency, then load it from the target harness.
|
|
26
26
|
- Port verification covers discovery, canonical payload and companion loading, needed tool schemas, and at least one relevant execution/read-only connection check. Distinguish those checks from unrun publishing, deletion, image generation, or production tests.
|
|
27
27
|
|
|
28
|
-
**ABOUT TO
|
|
28
|
+
**ABOUT TO RESTORE A SKILL? STOP - A GENERATED LAUNCHER IS NOT THE PROCEDURE.** If a SKILL.md contains a generated-adapter header or only points back to its own `greprag load`, recover the actual procedure from git history or the mirror's archived revisions and commit it to the git folder. Do not recursively load it or commit another launcher as the repair.
|
|
29
29
|
|
|
30
30
|
## Boundary Rule
|
|
31
31
|
|
|
@@ -37,22 +37,24 @@ Explicitly requested creation, porting, or redesign is authorized work. The prop
|
|
|
37
37
|
|
|
38
38
|
## Where To Edit
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
-
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
40
|
+
Git owns every skill; GrepRAG only mirrors the committed files and refuses every write to the mirror.
|
|
41
|
+
|
|
42
|
+
- Global skill: edit `~/.claude/skills/<name>/` (the dotclaude git repo) and commit.
|
|
43
|
+
- Project skill: edit `<repo>/.claude/skills/<name>/` and commit in that repo.
|
|
44
|
+
- Bundled GrepRAG skill: edit `packages/cli/skill/<name>/` in the greprag repo, never the installed artifact.
|
|
45
|
+
- Codex/OpenCode `SKILL.md` files are generated launchers: never edit them. Edit the git folder they name.
|
|
46
|
+
- Unknown source: stop and identify the git folder before editing.
|
|
47
|
+
- **ABOUT TO CALL A SKILL CHANGE DONE? STOP - COMMIT IT.** Uncommitted edits are never mirrored; the commit message carries the learning the edit captures, not "update skill". The next session start (or `greprag skill mirror sync`) copies the commit into the mirror for every harness.
|
|
48
|
+
- History and rollback: `git log`, `git diff` and `git revert` on the skill folder. `greprag skill history <skill>` and `greprag skill diff <skill> <revA> [<revB>]` still read the mirror's archived revisions.
|
|
46
49
|
|
|
47
50
|
## Skill-Refresh Chips
|
|
48
51
|
|
|
49
52
|
A `skill-refresh` chip must:
|
|
50
53
|
|
|
51
|
-
- load the
|
|
54
|
+
- load the skill with `greprag load <skill>`
|
|
52
55
|
- read the changed watched source files/diffs before trusting stale skill claims
|
|
53
|
-
- decide whether the right result is a
|
|
54
|
-
-
|
|
55
|
-
- regenerate or mirror adapters only through GrepRAG commands when needed
|
|
56
|
+
- decide whether the right result is a skill edit or only a new source stamp (`greprag skill source stamp`, which writes the git SKILL.md)
|
|
57
|
+
- edit the skill's git folder and commit, never a generated launcher
|
|
56
58
|
- report checks and whether release/deploy is needed
|
|
57
59
|
|
|
58
60
|
## Edit Shapes
|