create-agdf 0.1.6 → 0.1.8
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/README.md +25 -2
- package/bin/create-agdf.js +310 -3
- package/generated/.agdf/control/README.md +20 -5
- package/generated/.github/skills/agdf-release-or/SKILL.md +3 -10
- package/generated/.github/skills/agdf-runtime-contract.md +2 -1
- package/generated/plugins/agdf/.codex-plugin/plugin.json +2 -1
- package/generated/plugins/agdf/control/README.md +20 -5
- package/generated/plugins/agdf/hooks/hooks.json +1 -1
- package/generated/plugins/agdf/meta/agdf-plugin.definition.json +1 -1
- package/generated/plugins/agdf/meta/agdf-runtime-contract.md +2 -1
- package/generated/plugins/agdf/meta/agdf-tenets.md +6 -1
- package/generated/plugins/agdf/skills/release-or/SKILL.md +3 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,6 +8,8 @@ Bootstrap AGDF repository instructions for one repository.
|
|
|
8
8
|
npm create agdf@latest codex
|
|
9
9
|
npm create agdf@latest copilot
|
|
10
10
|
npm create agdf@latest both
|
|
11
|
+
npm create agdf@latest init
|
|
12
|
+
npm create agdf@latest doctor
|
|
11
13
|
```
|
|
12
14
|
|
|
13
15
|
Optional flags:
|
|
@@ -29,7 +31,7 @@ After `npm create agdf@latest codex`, restart Codex in that repository, open `/p
|
|
|
29
31
|
|
|
30
32
|
## Control scaffold
|
|
31
33
|
|
|
32
|
-
The generated `.agdf/control/templates/` files are starting points for durable AGDF state:
|
|
34
|
+
The generated `.agdf/control/templates/` files are reusable starting points for durable AGDF state:
|
|
33
35
|
|
|
34
36
|
- `AGDF_RUN.md` for the current run dashboard
|
|
35
37
|
- `MASTER_BACKLOG.md` for active delivery pointers
|
|
@@ -37,7 +39,28 @@ The generated `.agdf/control/templates/` files are starting points for durable A
|
|
|
37
39
|
- `CONTEXT_GRAPH.md` for durable Brownfield findings, decisions, risks, evidence and exit criteria
|
|
38
40
|
- `AGENT_QUALITY_CONTRACTS.json` for reusable block, revise and warning conditions
|
|
39
41
|
|
|
40
|
-
|
|
42
|
+
Use `init` to promote those templates into live control files:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm create agdf@latest init
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
This writes:
|
|
49
|
+
|
|
50
|
+
- `.agdf/control/AGDF_RUN.md`
|
|
51
|
+
- `.agdf/control/MASTER_BACKLOG.md`
|
|
52
|
+
- `.agdf/control/SOT_REGISTRY.md`
|
|
53
|
+
- `.agdf/control/CONTEXT_GRAPH.md`
|
|
54
|
+
- `.agdf/control/AGENT_QUALITY_CONTRACTS.json`
|
|
55
|
+
|
|
56
|
+
Use `doctor` to check whether the live control state is actionable:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npm create agdf@latest doctor
|
|
60
|
+
npm create agdf@latest doctor --json
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The doctor reports missing live control files, missing current gate, missing next allowed action, empty evidence, empty backlog pointer, empty source-of-truth registry, duplicate active SoT rows and invalid quality contracts. It exits non-zero only for blocking control failures.
|
|
41
64
|
|
|
42
65
|
## Single source of truth
|
|
43
66
|
|
package/bin/create-agdf.js
CHANGED
|
@@ -11,7 +11,7 @@ const generatedRoot = join(packageRoot, "generated");
|
|
|
11
11
|
const pluginDefinitionPath = join(generatedRoot, "plugins", "agdf", "meta", "agdf-plugin.definition.json");
|
|
12
12
|
const pluginDefinition = JSON.parse(readFileSync(pluginDefinitionPath, "utf8"));
|
|
13
13
|
const pluginInstallCommand = "claude plugin add arndtgold/ai-native-governance-delivery-framework";
|
|
14
|
-
const allowedTargets = new Set(["codex", "copilot", "both"]);
|
|
14
|
+
const allowedTargets = new Set(["codex", "copilot", "both", "init", "doctor"]);
|
|
15
15
|
const agdfFragmentPath = "AGENTS.agdf.md";
|
|
16
16
|
const codexSkillNames = pluginDefinition.skillSet.map((skill) => `${pluginDefinition.codex.skillPrefix}${skill.slug}`);
|
|
17
17
|
const copilotSkillNames = pluginDefinition.skillSet.map((skill) => `${pluginDefinition.copilot.skillPrefix}${skill.slug}`);
|
|
@@ -41,6 +41,35 @@ const controlFiles = [
|
|
|
41
41
|
join(".agdf", "control", "templates", "CONTEXT_GRAPH.md"),
|
|
42
42
|
join(".agdf", "control", "templates", "AGENT_QUALITY_CONTRACTS.json"),
|
|
43
43
|
];
|
|
44
|
+
const liveControlFiles = [
|
|
45
|
+
{
|
|
46
|
+
path: join(".agdf", "control", "AGDF_RUN.md"),
|
|
47
|
+
source: join(".agdf", "control", "templates", "AGDF_RUN.md"),
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
path: join(".agdf", "control", "MASTER_BACKLOG.md"),
|
|
51
|
+
source: join(".agdf", "control", "templates", "MASTER_BACKLOG.md"),
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
path: join(".agdf", "control", "SOT_REGISTRY.md"),
|
|
55
|
+
source: join(".agdf", "control", "templates", "SOT_REGISTRY.md"),
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
path: join(".agdf", "control", "CONTEXT_GRAPH.md"),
|
|
59
|
+
source: join(".agdf", "control", "templates", "CONTEXT_GRAPH.md"),
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
path: join(".agdf", "control", "AGENT_QUALITY_CONTRACTS.json"),
|
|
63
|
+
source: join(".agdf", "control", "templates", "AGENT_QUALITY_CONTRACTS.json"),
|
|
64
|
+
},
|
|
65
|
+
];
|
|
66
|
+
const doctorRequiredFiles = [
|
|
67
|
+
join(".agdf", "control", "AGDF_RUN.md"),
|
|
68
|
+
join(".agdf", "control", "MASTER_BACKLOG.md"),
|
|
69
|
+
join(".agdf", "control", "SOT_REGISTRY.md"),
|
|
70
|
+
join(".agdf", "control", "CONTEXT_GRAPH.md"),
|
|
71
|
+
join(".agdf", "control", "AGENT_QUALITY_CONTRACTS.json"),
|
|
72
|
+
];
|
|
44
73
|
const copilotInstructionFiles = [
|
|
45
74
|
join(".github", "copilot-instructions.md"),
|
|
46
75
|
join(".github", "instructions", "agdf-governance.instructions.md"),
|
|
@@ -58,10 +87,13 @@ Usage:
|
|
|
58
87
|
npm create agdf@latest codex
|
|
59
88
|
npm create agdf@latest copilot
|
|
60
89
|
npm create agdf@latest both
|
|
90
|
+
npm create agdf@latest init
|
|
91
|
+
npm create agdf@latest doctor
|
|
61
92
|
|
|
62
93
|
Options:
|
|
63
94
|
--dir <path> Write files into a specific directory
|
|
64
95
|
--force Overwrite existing generated files
|
|
96
|
+
--json Print doctor output as JSON
|
|
65
97
|
--help Show this help
|
|
66
98
|
`);
|
|
67
99
|
}
|
|
@@ -71,6 +103,7 @@ function parseArgs(argv) {
|
|
|
71
103
|
let target;
|
|
72
104
|
let dir = ".";
|
|
73
105
|
let force = false;
|
|
106
|
+
let json = false;
|
|
74
107
|
|
|
75
108
|
for (let i = 0; i < args.length; i += 1) {
|
|
76
109
|
const arg = args[i];
|
|
@@ -86,6 +119,11 @@ function parseArgs(argv) {
|
|
|
86
119
|
continue;
|
|
87
120
|
}
|
|
88
121
|
|
|
122
|
+
if (arg === "--json") {
|
|
123
|
+
json = true;
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
|
|
89
127
|
if (arg === "--dir") {
|
|
90
128
|
const next = args[i + 1];
|
|
91
129
|
if (!next) {
|
|
@@ -118,7 +156,7 @@ function parseArgs(argv) {
|
|
|
118
156
|
}
|
|
119
157
|
|
|
120
158
|
if (!target || !allowedTargets.has(target)) {
|
|
121
|
-
console.error("Please choose one target: codex, copilot or
|
|
159
|
+
console.error("Please choose one target: codex, copilot, both, init or doctor.");
|
|
122
160
|
printUsage();
|
|
123
161
|
process.exit(1);
|
|
124
162
|
}
|
|
@@ -127,6 +165,7 @@ function parseArgs(argv) {
|
|
|
127
165
|
target,
|
|
128
166
|
dir: resolve(process.cwd(), dir),
|
|
129
167
|
force,
|
|
168
|
+
json,
|
|
130
169
|
};
|
|
131
170
|
}
|
|
132
171
|
|
|
@@ -148,6 +187,22 @@ function writeGeneratedFile(targetDir, relativePath, content, force) {
|
|
|
148
187
|
function generatedFilesForTarget(target, targetDir, force) {
|
|
149
188
|
const files = [];
|
|
150
189
|
|
|
190
|
+
if (target === "init") {
|
|
191
|
+
files.push({
|
|
192
|
+
path: join(".agdf", "control", "README.md"),
|
|
193
|
+
content: loadAsset(join(".agdf", "control", "README.md")),
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
for (const controlPath of liveControlFiles) {
|
|
197
|
+
files.push({
|
|
198
|
+
path: controlPath.path,
|
|
199
|
+
content: loadAsset(controlPath.source),
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return files;
|
|
204
|
+
}
|
|
205
|
+
|
|
151
206
|
if (target === "codex" || target === "both") {
|
|
152
207
|
for (const codexPath of codexPluginFiles) {
|
|
153
208
|
files.push({
|
|
@@ -200,6 +255,12 @@ function printNextSteps(target, destination, files, wroteAgentsFragment) {
|
|
|
200
255
|
|
|
201
256
|
console.log("");
|
|
202
257
|
console.log("Next steps:");
|
|
258
|
+
if (target === "init") {
|
|
259
|
+
console.log("- Fill .agdf/control/AGDF_RUN.md with the current gate, evidence and next allowed action.");
|
|
260
|
+
console.log("- Run npm create agdf@latest doctor to check the control state before the next agent run.");
|
|
261
|
+
console.log("- Commit the live control files once they represent the repository's current delivery state.");
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
203
264
|
if (wroteAgentsFragment) {
|
|
204
265
|
console.log(`- Existing AGENTS.md detected. Merge ${agdfFragmentPath} into your current AGENTS.md before using Copilot with AGDF.`);
|
|
205
266
|
}
|
|
@@ -212,13 +273,259 @@ function printNextSteps(target, destination, files, wroteAgentsFragment) {
|
|
|
212
273
|
}
|
|
213
274
|
if (target === "copilot" || target === "both") {
|
|
214
275
|
console.log("- In GitHub Copilot CLI, run /instructions after the AGENTS.md step is complete to confirm that AGDF instructions and the repository skills are visible.");
|
|
215
|
-
console.log("-
|
|
276
|
+
console.log("- Run npm create agdf@latest init when the repository needs live AGDF control files.");
|
|
216
277
|
}
|
|
217
278
|
console.log("- Commit the generated files so the repository becomes the source of truth.");
|
|
218
279
|
}
|
|
219
280
|
|
|
281
|
+
function readTargetFile(targetDir, relativePath) {
|
|
282
|
+
return readFileSync(join(targetDir, relativePath), "utf8");
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function addFinding(findings, severity, code, message, path, nextStep) {
|
|
286
|
+
findings.push({
|
|
287
|
+
severity,
|
|
288
|
+
code,
|
|
289
|
+
message,
|
|
290
|
+
path,
|
|
291
|
+
next_step: nextStep,
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function nonEmptyTableRows(content) {
|
|
296
|
+
return content
|
|
297
|
+
.split("\n")
|
|
298
|
+
.filter((line) => line.trim().startsWith("|"))
|
|
299
|
+
.filter((line) => !line.includes("---"))
|
|
300
|
+
.map((line) => line.split("|").map((cell) => cell.trim()).filter(Boolean))
|
|
301
|
+
.filter((cells) => cells.some((cell) => cell && !cell.startsWith("`")));
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function tableRows(content) {
|
|
305
|
+
return content
|
|
306
|
+
.split("\n")
|
|
307
|
+
.filter((line) => line.trim().startsWith("|"))
|
|
308
|
+
.filter((line) => !line.includes("---"))
|
|
309
|
+
.map((line) => {
|
|
310
|
+
const cells = line.split("|").map((cell) => cell.trim());
|
|
311
|
+
if (cells[0] === "") cells.shift();
|
|
312
|
+
if (cells.at(-1) === "") cells.pop();
|
|
313
|
+
return cells;
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function hasFilledTableRow(content, firstCellPattern) {
|
|
318
|
+
return tableRows(content)
|
|
319
|
+
.filter((cells) => firstCellPattern.test(cells[0] ?? ""))
|
|
320
|
+
.some((cells) => cells.slice(1).some((cell) => cell && !cell.startsWith("`")));
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function isPlaceholderValue(value) {
|
|
324
|
+
return !value || (value.startsWith("`") && value.includes("|"));
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function hasFilledEvidenceRow(content) {
|
|
328
|
+
const evidenceSection = content.match(/## Evidence([\s\S]*?)(?:\n## |\n# |$)/)?.[1] ?? "";
|
|
329
|
+
return tableRows(evidenceSection)
|
|
330
|
+
.filter((cells) => cells[0] !== "Evidence")
|
|
331
|
+
.some((cells) => {
|
|
332
|
+
const [evidence, source, covers] = cells;
|
|
333
|
+
return Boolean(evidence || source || covers);
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function parseQualityContracts(content) {
|
|
338
|
+
const parsed = JSON.parse(content);
|
|
339
|
+
if (!Array.isArray(parsed.contracts) || parsed.contracts.length === 0) {
|
|
340
|
+
throw new Error("contracts must be a non-empty array");
|
|
341
|
+
}
|
|
342
|
+
for (const contract of parsed.contracts) {
|
|
343
|
+
if (!contract.code || !contract.impact || !contract.required_evidence) {
|
|
344
|
+
throw new Error(`contract ${contract.code ?? "<unknown>"} is missing code, impact or required_evidence`);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return parsed;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function evaluateDoctor(targetDir) {
|
|
351
|
+
const findings = [];
|
|
352
|
+
const missing = doctorRequiredFiles.filter((relativePath) => !existsSync(join(targetDir, relativePath)));
|
|
353
|
+
|
|
354
|
+
for (const relativePath of missing) {
|
|
355
|
+
const templatePath = join(dirname(relativePath), "templates", relativePath.split("/").at(-1));
|
|
356
|
+
const hasTemplate = existsSync(join(targetDir, templatePath));
|
|
357
|
+
addFinding(
|
|
358
|
+
findings,
|
|
359
|
+
"block",
|
|
360
|
+
"AGDF_CONTROL_FILE_MISSING",
|
|
361
|
+
hasTemplate
|
|
362
|
+
? "Live control file is missing; only the template exists."
|
|
363
|
+
: "Required live control file is missing.",
|
|
364
|
+
relativePath,
|
|
365
|
+
"Run npm create agdf@latest init, then fill the live control files with the current repository state.",
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
if (missing.length === 0) {
|
|
370
|
+
const runPath = join(".agdf", "control", "AGDF_RUN.md");
|
|
371
|
+
const run = readTargetFile(targetDir, runPath);
|
|
372
|
+
const currentGateLine = run.match(/^- current_gate:[^\S\r\n]*(.*)$/m)?.[1]?.trim() ?? "";
|
|
373
|
+
const nextActionLine = run.match(/^- next_allowed_action:[^\S\r\n]*(.*)$/m)?.[1]?.trim() ?? "";
|
|
374
|
+
const hasEvidence = hasFilledEvidenceRow(run);
|
|
375
|
+
|
|
376
|
+
if (isPlaceholderValue(currentGateLine)) {
|
|
377
|
+
addFinding(
|
|
378
|
+
findings,
|
|
379
|
+
"revise",
|
|
380
|
+
"AGDF_CURRENT_GATE_MISSING",
|
|
381
|
+
"AGDF_RUN.md does not name the current gate.",
|
|
382
|
+
runPath,
|
|
383
|
+
"Set current_gate to the current delivery gate or none.",
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
if (isPlaceholderValue(nextActionLine)) {
|
|
388
|
+
addFinding(
|
|
389
|
+
findings,
|
|
390
|
+
"revise",
|
|
391
|
+
"AGDF_NEXT_ALLOWED_ACTION_MISSING",
|
|
392
|
+
"AGDF_RUN.md does not state the next allowed action.",
|
|
393
|
+
runPath,
|
|
394
|
+
"Fill the next allowed action before asking an agent to continue delivery work.",
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
if (!hasEvidence) {
|
|
399
|
+
addFinding(
|
|
400
|
+
findings,
|
|
401
|
+
"warn",
|
|
402
|
+
"AGDF_EVIDENCE_EMPTY",
|
|
403
|
+
"AGDF_RUN.md has no visible evidence row yet.",
|
|
404
|
+
runPath,
|
|
405
|
+
"Add at least one evidence row or explicitly document that no evidence exists yet.",
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const backlogPath = join(".agdf", "control", "MASTER_BACKLOG.md");
|
|
410
|
+
const backlog = readTargetFile(targetDir, backlogPath);
|
|
411
|
+
if (!hasFilledTableRow(backlog, /^P[0-9]/)) {
|
|
412
|
+
addFinding(
|
|
413
|
+
findings,
|
|
414
|
+
"warn",
|
|
415
|
+
"AGDF_BACKLOG_POINTER_EMPTY",
|
|
416
|
+
"MASTER_BACKLOG.md does not contain an active or planned work pointer.",
|
|
417
|
+
backlogPath,
|
|
418
|
+
"Add the active item or document that no governed delivery item is active.",
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const sotPath = join(".agdf", "control", "SOT_REGISTRY.md");
|
|
423
|
+
const sot = readTargetFile(targetDir, sotPath);
|
|
424
|
+
if (!hasFilledTableRow(sot, /Product intent|Architecture|Runtime contracts|UX \/ user flows|Operations \/ release/)) {
|
|
425
|
+
addFinding(
|
|
426
|
+
findings,
|
|
427
|
+
"warn",
|
|
428
|
+
"AGDF_SOT_REGISTRY_EMPTY",
|
|
429
|
+
"SOT_REGISTRY.md has no filled primary source-of-truth row.",
|
|
430
|
+
sotPath,
|
|
431
|
+
"Assign one primary source of truth for at least the domains relevant to the next run.",
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const activeDomains = new Map();
|
|
436
|
+
for (const cells of nonEmptyTableRows(sot)) {
|
|
437
|
+
const [domain, document, status] = cells;
|
|
438
|
+
if (!domain || !document || status !== "active") continue;
|
|
439
|
+
activeDomains.set(domain, (activeDomains.get(domain) ?? 0) + 1);
|
|
440
|
+
}
|
|
441
|
+
for (const [domain, count] of activeDomains.entries()) {
|
|
442
|
+
if (count > 1) {
|
|
443
|
+
addFinding(
|
|
444
|
+
findings,
|
|
445
|
+
"block",
|
|
446
|
+
"AGDF_PARALLEL_SOT",
|
|
447
|
+
`Domain has ${count} active source-of-truth rows: ${domain}.`,
|
|
448
|
+
sotPath,
|
|
449
|
+
"Keep exactly one active primary source of truth for this domain.",
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
const contextPath = join(".agdf", "control", "CONTEXT_GRAPH.md");
|
|
455
|
+
const contextGraph = readTargetFile(targetDir, contextPath);
|
|
456
|
+
if (contextGraph.includes("### CG-001 Example")) {
|
|
457
|
+
addFinding(
|
|
458
|
+
findings,
|
|
459
|
+
"warn",
|
|
460
|
+
"AGDF_CONTEXT_GRAPH_TEMPLATE_NODE",
|
|
461
|
+
"CONTEXT_GRAPH.md still contains the example node.",
|
|
462
|
+
contextPath,
|
|
463
|
+
"Remove the example or replace it with an evidenced node that has an exit criterion.",
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
const contractsPath = join(".agdf", "control", "AGENT_QUALITY_CONTRACTS.json");
|
|
468
|
+
try {
|
|
469
|
+
parseQualityContracts(readTargetFile(targetDir, contractsPath));
|
|
470
|
+
} catch (error) {
|
|
471
|
+
addFinding(
|
|
472
|
+
findings,
|
|
473
|
+
"block",
|
|
474
|
+
"AGDF_QUALITY_CONTRACTS_INVALID",
|
|
475
|
+
`AGENT_QUALITY_CONTRACTS.json is invalid: ${error.message}`,
|
|
476
|
+
contractsPath,
|
|
477
|
+
"Restore the generated contracts or fix the JSON contract schema.",
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
const severityRank = { block: 3, revise: 2, warn: 1 };
|
|
483
|
+
const maxSeverity = findings.reduce((max, finding) => Math.max(max, severityRank[finding.severity] ?? 0), 0);
|
|
484
|
+
const status = maxSeverity >= 3 ? "block" : maxSeverity === 2 ? "revise" : maxSeverity === 1 ? "warn" : "pass";
|
|
485
|
+
|
|
486
|
+
return {
|
|
487
|
+
schema_version: "1",
|
|
488
|
+
status,
|
|
489
|
+
checked_at: new Date().toISOString(),
|
|
490
|
+
target_dir: targetDir,
|
|
491
|
+
summary: {
|
|
492
|
+
findings: findings.length,
|
|
493
|
+
block: findings.filter((finding) => finding.severity === "block").length,
|
|
494
|
+
revise: findings.filter((finding) => finding.severity === "revise").length,
|
|
495
|
+
warn: findings.filter((finding) => finding.severity === "warn").length,
|
|
496
|
+
},
|
|
497
|
+
findings,
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function printDoctorReport(report, json) {
|
|
502
|
+
if (json) {
|
|
503
|
+
console.log(JSON.stringify(report, null, 2));
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
console.log(`AGDF doctor: ${report.status}`);
|
|
508
|
+
console.log(`Checked: ${report.target_dir}`);
|
|
509
|
+
console.log(`Findings: ${report.summary.findings} (${report.summary.block} block, ${report.summary.revise} revise, ${report.summary.warn} warn)`);
|
|
510
|
+
|
|
511
|
+
for (const finding of report.findings) {
|
|
512
|
+
console.log("");
|
|
513
|
+
console.log(`[${finding.severity}] ${finding.code}`);
|
|
514
|
+
console.log(`Path: ${finding.path}`);
|
|
515
|
+
console.log(finding.message);
|
|
516
|
+
console.log(`Next step: ${finding.next_step}`);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
220
520
|
function main() {
|
|
221
521
|
const options = parseArgs(process.argv.slice(2));
|
|
522
|
+
|
|
523
|
+
if (options.target === "doctor") {
|
|
524
|
+
const report = evaluateDoctor(options.dir);
|
|
525
|
+
printDoctorReport(report, options.json);
|
|
526
|
+
process.exit(report.status === "block" ? 2 : 0);
|
|
527
|
+
}
|
|
528
|
+
|
|
222
529
|
const files = generatedFilesForTarget(options.target, options.dir, options.force);
|
|
223
530
|
const wroteAgentsFragment = files.some(file => file.path === agdfFragmentPath);
|
|
224
531
|
|
|
@@ -8,11 +8,11 @@ Use this scaffold when a target repository should keep AGDF state outside chat h
|
|
|
8
8
|
|
|
9
9
|
| File | Purpose |
|
|
10
10
|
|---|---|
|
|
11
|
-
| `templates/AGDF_RUN.md` |
|
|
12
|
-
| `templates/MASTER_BACKLOG.md` |
|
|
13
|
-
| `templates/SOT_REGISTRY.md` |
|
|
14
|
-
| `templates/CONTEXT_GRAPH.md` |
|
|
15
|
-
| `templates/AGENT_QUALITY_CONTRACTS.json` |
|
|
11
|
+
| `templates/AGDF_RUN.md` | Template for current run state: mode, gate, approvals, evidence, risks, next allowed action |
|
|
12
|
+
| `templates/MASTER_BACKLOG.md` | Template for the living backlog pointer: active initiatives and current UR/PRD/SD/TP artefacts |
|
|
13
|
+
| `templates/SOT_REGISTRY.md` | Template for the source-of-truth registry: one primary owner per domain |
|
|
14
|
+
| `templates/CONTEXT_GRAPH.md` | Template for project memory: durable decisions, Brownfield findings, risks, evidence and exit criteria |
|
|
15
|
+
| `templates/AGENT_QUALITY_CONTRACTS.json` | Template for machine-readable warning, revise and block contracts for review and QA |
|
|
16
16
|
|
|
17
17
|
## Recommended Target Layout
|
|
18
18
|
|
|
@@ -28,6 +28,21 @@ Use this scaffold when a target repository should keep AGDF state outside chat h
|
|
|
28
28
|
|
|
29
29
|
Keep these files small and reviewable. They are control artefacts, not a second documentation site.
|
|
30
30
|
|
|
31
|
+
Create the live files with:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm create agdf@latest init
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Then check whether the live state is actionable:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm create agdf@latest doctor
|
|
41
|
+
npm create agdf@latest doctor --json
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`doctor` does not replace agent judgment. It catches basic control failures: missing live files, missing current gate, missing next allowed action, empty evidence, empty backlog pointer, empty source-of-truth registry, duplicate active SoT rows and invalid quality contracts.
|
|
45
|
+
|
|
31
46
|
## Operating Rules
|
|
32
47
|
|
|
33
48
|
- `AGDF_RUN.md` is the current run dashboard.
|
|
@@ -22,7 +22,7 @@ It reports:
|
|
|
22
22
|
- Context Graph impact
|
|
23
23
|
- open risks, blockers, retained fallbacks, and exit criteria
|
|
24
24
|
- next permissible step
|
|
25
|
-
- whether further quality follow-up is useful
|
|
25
|
+
- whether further quality follow-up or a separate delivery closeout is useful
|
|
26
26
|
|
|
27
27
|
## Runtime Contract
|
|
28
28
|
Use `../agdf-runtime-contract.md` for Quality Contract output, Context Graph fields, gate terms, and non-duplication rules.
|
|
@@ -85,7 +85,7 @@ If information is missing, state the gap instead of guessing.
|
|
|
85
85
|
8. Name retained fallbacks and exit criteria.
|
|
86
86
|
9. Set exactly one next permissible step.
|
|
87
87
|
10. Set exactly one quality outlook.
|
|
88
|
-
11.
|
|
88
|
+
11. State whether `agdf-delivery-closeout` is the next operational handoff step when code changes exist and the delivery state allows it.
|
|
89
89
|
|
|
90
90
|
## Output
|
|
91
91
|
Use a compact structure:
|
|
@@ -106,14 +106,6 @@ Use a compact structure:
|
|
|
106
106
|
|
|
107
107
|
When Context Graph impact is relevant, include the fields from `../agdf-runtime-contract.md`.
|
|
108
108
|
|
|
109
|
-
For code-changing closeouts that are commit-near, append:
|
|
110
|
-
|
|
111
|
-
```text
|
|
112
|
-
Commit title:
|
|
113
|
-
Commit body:
|
|
114
|
-
Migration/Rollout note:
|
|
115
|
-
```
|
|
116
|
-
|
|
117
109
|
## Forbidden
|
|
118
110
|
This skill must not:
|
|
119
111
|
|
|
@@ -121,4 +113,5 @@ This skill must not:
|
|
|
121
113
|
- call `CD+Tests` complete, QA-ready, or release-ready
|
|
122
114
|
- hide missing approvals
|
|
123
115
|
- provide later-gate content while an earlier gate blocks
|
|
116
|
+
- produce the operative commit/PR handoff owned by `agdf-delivery-closeout`
|
|
124
117
|
- execute commit, push, or PR actions
|
|
@@ -24,7 +24,8 @@ Structured Delivery must not bypass missing approvals.
|
|
|
24
24
|
- `CD+Tests` is implementation and test status only, not a delivery signal.
|
|
25
25
|
- `agdf-code-review` standardizes the mandatory `CR` step, but does not replace QA.
|
|
26
26
|
- `agdf-qa-gate` decides final `pass | revise | block`.
|
|
27
|
-
- `agdf-release-or` reports the run, but does not replace QA.
|
|
27
|
+
- `agdf-release-or` reports the run, but does not replace QA or produce the operative commit/PR handoff.
|
|
28
|
+
- `agdf-delivery-closeout` owns the operative Git handoff text when QA/OR/UAT state allows it.
|
|
28
29
|
|
|
29
30
|
## Quality Contract Output
|
|
30
31
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agdf",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "Codex-first workflow skills for gated, auditable AI-assisted software delivery.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "AI-native Governance & Delivery Framework",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"license": "Apache-2.0",
|
|
12
12
|
"keywords": ["agentic", "governance", "delivery", "ai-native", "brownfield"],
|
|
13
13
|
"skills": "./skills/",
|
|
14
|
+
"hooks": "./hooks/hooks.json",
|
|
14
15
|
"interface": {
|
|
15
16
|
"displayName": "AI Governance & Delivery Framework",
|
|
16
17
|
"shortDescription": "Codex-first workflow skills for gated, auditable AI-assisted delivery.",
|
|
@@ -8,11 +8,11 @@ Use this scaffold when a target repository should keep AGDF state outside chat h
|
|
|
8
8
|
|
|
9
9
|
| File | Purpose |
|
|
10
10
|
|---|---|
|
|
11
|
-
| `templates/AGDF_RUN.md` |
|
|
12
|
-
| `templates/MASTER_BACKLOG.md` |
|
|
13
|
-
| `templates/SOT_REGISTRY.md` |
|
|
14
|
-
| `templates/CONTEXT_GRAPH.md` |
|
|
15
|
-
| `templates/AGENT_QUALITY_CONTRACTS.json` |
|
|
11
|
+
| `templates/AGDF_RUN.md` | Template for current run state: mode, gate, approvals, evidence, risks, next allowed action |
|
|
12
|
+
| `templates/MASTER_BACKLOG.md` | Template for the living backlog pointer: active initiatives and current UR/PRD/SD/TP artefacts |
|
|
13
|
+
| `templates/SOT_REGISTRY.md` | Template for the source-of-truth registry: one primary owner per domain |
|
|
14
|
+
| `templates/CONTEXT_GRAPH.md` | Template for project memory: durable decisions, Brownfield findings, risks, evidence and exit criteria |
|
|
15
|
+
| `templates/AGENT_QUALITY_CONTRACTS.json` | Template for machine-readable warning, revise and block contracts for review and QA |
|
|
16
16
|
|
|
17
17
|
## Recommended Target Layout
|
|
18
18
|
|
|
@@ -28,6 +28,21 @@ Use this scaffold when a target repository should keep AGDF state outside chat h
|
|
|
28
28
|
|
|
29
29
|
Keep these files small and reviewable. They are control artefacts, not a second documentation site.
|
|
30
30
|
|
|
31
|
+
Create the live files with:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm create agdf@latest init
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Then check whether the live state is actionable:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm create agdf@latest doctor
|
|
41
|
+
npm create agdf@latest doctor --json
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`doctor` does not replace agent judgment. It catches basic control failures: missing live files, missing current gate, missing next allowed action, empty evidence, empty backlog pointer, empty source-of-truth registry, duplicate active SoT rows and invalid quality contracts.
|
|
45
|
+
|
|
31
46
|
## Operating Rules
|
|
32
47
|
|
|
33
48
|
- `AGDF_RUN.md` is the current run dashboard.
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"hooks": [
|
|
6
6
|
{
|
|
7
7
|
"type": "command",
|
|
8
|
-
"command": "bash -lc '
|
|
8
|
+
"command": "bash -lc 'hook=\"${PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT:-}}/hooks/session-start.sh\"; if [ -f \"$hook\" ]; then exec bash \"$hook\"; fi; hook=\"$PWD/plugins/agdf/hooks/session-start.sh\"; if [ -f \"$hook\" ]; then exec bash \"$hook\"; fi; exit 0'",
|
|
9
9
|
"statusMessage": "Loading AGDF..."
|
|
10
10
|
}
|
|
11
11
|
]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"id": "agdf",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.8",
|
|
5
5
|
"displayName": "AI Governance & Delivery Framework",
|
|
6
6
|
"developerName": "AI-native Governance & Delivery Framework",
|
|
7
7
|
"description": "Codex-first workflow skills for gated, auditable AI-assisted software delivery.",
|
|
@@ -24,7 +24,8 @@ Structured Delivery must not bypass missing approvals.
|
|
|
24
24
|
- `CD+Tests` is implementation and test status only, not a delivery signal.
|
|
25
25
|
- `code-review` standardizes the mandatory `CR` step, but does not replace QA.
|
|
26
26
|
- `qa-gate` decides final `pass | revise | block`.
|
|
27
|
-
- `release-or` reports the run, but does not replace QA.
|
|
27
|
+
- `release-or` reports the run, but does not replace QA or produce the operative commit/PR handoff.
|
|
28
|
+
- `delivery-closeout` owns the operative Git handoff text when QA/OR/UAT state allows it.
|
|
28
29
|
|
|
29
30
|
## Quality Contract Output
|
|
30
31
|
|
|
@@ -16,7 +16,12 @@ you *MUST* honor the following **GENERIC TENETS**:
|
|
|
16
16
|
Implementation should not be based on vague intent.
|
|
17
17
|
A stable product contract defines accepted scope, acceptance criteria,
|
|
18
18
|
non-goals, constraints and success measurement.
|
|
19
|
-
|
|
19
|
+
For Structured Delivery or product-semantically relevant implementation,
|
|
20
|
+
no implementation may begin without an approved PRD or an explicitly
|
|
21
|
+
equivalent product contract.
|
|
22
|
+
Quick Task Mode may still handle narrow local fixes, reviews, debugging
|
|
23
|
+
and tooling maintenance when no new product meaning, user capability,
|
|
24
|
+
architecture, policy or persistence decision is introduced.
|
|
20
25
|
|
|
21
26
|
- **Fail Closed**:
|
|
22
27
|
When a necessary approval, input, or quality statement is missing,
|
|
@@ -22,7 +22,7 @@ It reports:
|
|
|
22
22
|
- Context Graph impact
|
|
23
23
|
- open risks, blockers, retained fallbacks, and exit criteria
|
|
24
24
|
- next permissible step
|
|
25
|
-
- whether further quality follow-up is useful
|
|
25
|
+
- whether further quality follow-up or a separate delivery closeout is useful
|
|
26
26
|
|
|
27
27
|
## Runtime Contract
|
|
28
28
|
Use `../../meta/agdf-runtime-contract.md` for Quality Contract output, Context Graph fields, gate terms, and non-duplication rules.
|
|
@@ -85,7 +85,7 @@ If information is missing, state the gap instead of guessing.
|
|
|
85
85
|
8. Name retained fallbacks and exit criteria.
|
|
86
86
|
9. Set exactly one next permissible step.
|
|
87
87
|
10. Set exactly one quality outlook.
|
|
88
|
-
11.
|
|
88
|
+
11. State whether `delivery-closeout` is the next operational handoff step when code changes exist and the delivery state allows it.
|
|
89
89
|
|
|
90
90
|
## Output
|
|
91
91
|
Use a compact structure:
|
|
@@ -106,14 +106,6 @@ Use a compact structure:
|
|
|
106
106
|
|
|
107
107
|
When Context Graph impact is relevant, include the fields from `../../meta/agdf-runtime-contract.md`.
|
|
108
108
|
|
|
109
|
-
For code-changing closeouts that are commit-near, append:
|
|
110
|
-
|
|
111
|
-
```text
|
|
112
|
-
Commit title:
|
|
113
|
-
Commit body:
|
|
114
|
-
Migration/Rollout note:
|
|
115
|
-
```
|
|
116
|
-
|
|
117
109
|
## Forbidden
|
|
118
110
|
This skill must not:
|
|
119
111
|
|
|
@@ -121,4 +113,5 @@ This skill must not:
|
|
|
121
113
|
- call `CD+Tests` complete, QA-ready, or release-ready
|
|
122
114
|
- hide missing approvals
|
|
123
115
|
- provide later-gate content while an earlier gate blocks
|
|
116
|
+
- produce the operative commit/PR handoff owned by `delivery-closeout`
|
|
124
117
|
- execute commit, push, or PR actions
|