dev-loops 0.1.0
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/.pi/dev-loop/defaults.yaml +477 -0
- package/AGENTS.md +25 -0
- package/CHANGELOG.md +18 -0
- package/LICENSE +21 -0
- package/README.md +178 -0
- package/agents/dev-loop.agent.md +82 -0
- package/agents/developer.agent.md +37 -0
- package/agents/docs.agent.md +33 -0
- package/agents/fixer.agent.md +53 -0
- package/agents/quality.agent.md +28 -0
- package/agents/refiner.agent.md +87 -0
- package/agents/review.agent.md +64 -0
- package/cli/index.mjs +424 -0
- package/extension/README.md +233 -0
- package/extension/checks.ts +94 -0
- package/extension/index.ts +131 -0
- package/extension/post-merge-update.ts +512 -0
- package/extension/presentation.ts +107 -0
- package/lib/dev-loops-core.mjs +284 -0
- package/package.json +103 -0
- package/scripts/README.md +1007 -0
- package/scripts/_cli-primitives.mjs +10 -0
- package/scripts/_core-helpers.mjs +30 -0
- package/scripts/docs/validate-links.mjs +567 -0
- package/scripts/docs/validate-no-duplicate-rules.mjs +250 -0
- package/scripts/github/_review-thread-mutations.mjs +214 -0
- package/scripts/github/capture-review-threads.mjs +180 -0
- package/scripts/github/create-draft-pr.mjs +108 -0
- package/scripts/github/detect-checkpoint-evidence.mjs +393 -0
- package/scripts/github/detect-linked-issue-pr.mjs +331 -0
- package/scripts/github/manage-sub-issues.mjs +394 -0
- package/scripts/github/probe-copilot-review.mjs +323 -0
- package/scripts/github/ready-for-review.mjs +93 -0
- package/scripts/github/reconcile-draft-gate.mjs +328 -0
- package/scripts/github/reply-resolve-review-thread.mjs +42 -0
- package/scripts/github/reply-resolve-review-threads.mjs +329 -0
- package/scripts/github/request-copilot-review.mjs +551 -0
- package/scripts/github/resolve-tracker-local-spec.mjs +205 -0
- package/scripts/github/stage-reviewer-draft.mjs +191 -0
- package/scripts/github/upsert-checkpoint-verdict.mjs +694 -0
- package/scripts/github/verify-fresh-review-context.mjs +125 -0
- package/scripts/github/write-gate-findings-log.mjs +212 -0
- package/scripts/loop/_checkpoint-io.mjs +55 -0
- package/scripts/loop/_checkpoint-paths.mjs +28 -0
- package/scripts/loop/_handoff-contract.mjs +230 -0
- package/scripts/loop/_inspect-run-viewer-adapter.mjs +345 -0
- package/scripts/loop/_loop-evidence.mjs +32 -0
- package/scripts/loop/_pr-runner-coordination.mjs +611 -0
- package/scripts/loop/_stale-runner-detection.mjs +145 -0
- package/scripts/loop/_steering-state-file.mjs +134 -0
- package/scripts/loop/build-handoff-envelope.mjs +181 -0
- package/scripts/loop/checkpoint-contract.mjs +49 -0
- package/scripts/loop/conductor-monitor.mjs +1850 -0
- package/scripts/loop/conductor.mjs +214 -0
- package/scripts/loop/copilot-pr-handoff.mjs +493 -0
- package/scripts/loop/debt-remediate.mjs +304 -0
- package/scripts/loop/detect-change-scope.mjs +102 -0
- package/scripts/loop/detect-copilot-loop-state.mjs +454 -0
- package/scripts/loop/detect-copilot-session-activity.mjs +186 -0
- package/scripts/loop/detect-initial-copilot-pr-state.mjs +318 -0
- package/scripts/loop/detect-internal-only-pr.mjs +270 -0
- package/scripts/loop/detect-issue-refinement-artifact.mjs +163 -0
- package/scripts/loop/detect-pr-gate-coordination-state.mjs +509 -0
- package/scripts/loop/detect-reviewer-loop-state.mjs +231 -0
- package/scripts/loop/detect-stale-runner.mjs +250 -0
- package/scripts/loop/detect-tracker-first-loop-state.mjs +76 -0
- package/scripts/loop/detect-tracker-pr-state.mjs +102 -0
- package/scripts/loop/info.mjs +267 -0
- package/scripts/loop/inspect-run-viewer/cli.mjs +117 -0
- package/scripts/loop/inspect-run-viewer/constants.mjs +80 -0
- package/scripts/loop/inspect-run-viewer/graph.mjs +757 -0
- package/scripts/loop/inspect-run-viewer/handoff-envelope-renderer.mjs +398 -0
- package/scripts/loop/inspect-run-viewer/inbox.mjs +308 -0
- package/scripts/loop/inspect-run-viewer/managed-instance.mjs +750 -0
- package/scripts/loop/inspect-run-viewer/rendering.mjs +411 -0
- package/scripts/loop/inspect-run-viewer/server.mjs +638 -0
- package/scripts/loop/inspect-run-viewer/shared.mjs +103 -0
- package/scripts/loop/inspect-run-viewer/status.mjs +715 -0
- package/scripts/loop/inspect-run-viewer-ci-changes.mjs +77 -0
- package/scripts/loop/inspect-run-viewer.mjs +82 -0
- package/scripts/loop/inspect-run.mjs +382 -0
- package/scripts/loop/outer-loop.mjs +419 -0
- package/scripts/loop/pr-runner-coordination.mjs +143 -0
- package/scripts/loop/pre-commit-branch-guard.mjs +68 -0
- package/scripts/loop/pre-flight-gate.mjs +236 -0
- package/scripts/loop/pre-pr-ready-gate.mjs +183 -0
- package/scripts/loop/pre-push-main-guard.mjs +103 -0
- package/scripts/loop/pre-write-remote-freshness-guard.mjs +32 -0
- package/scripts/loop/print-gates.mjs +42 -0
- package/scripts/loop/resolve-dev-loop-startup.mjs +533 -0
- package/scripts/loop/run-conductor-cycle.mjs +322 -0
- package/scripts/loop/run-queue.mjs +124 -0
- package/scripts/loop/run-refinement-audit.mjs +513 -0
- package/scripts/loop/run-watch-cycle.mjs +358 -0
- package/scripts/loop/steer-loop.mjs +841 -0
- package/scripts/loop/ui-designer-review-contract.mjs +76 -0
- package/scripts/loop/watch-initial-copilot-pr.mjs +253 -0
- package/scripts/projects/add-queue-item.mjs +528 -0
- package/scripts/projects/ensure-queue-board.mjs +837 -0
- package/scripts/projects/list-queue-items.mjs +489 -0
- package/scripts/projects/move-queue-item.mjs +549 -0
- package/scripts/projects/reorder-queue-item.mjs +518 -0
- package/scripts/refine/_refine-helpers.mjs +258 -0
- package/scripts/refine/prose-linkage-detector.mjs +92 -0
- package/scripts/refine/refinement-completeness-checker.mjs +88 -0
- package/scripts/refine/scope-boundary-cross-checker.mjs +163 -0
- package/scripts/refine/tree-integrity-validator.mjs +211 -0
- package/scripts/refine/verify.mjs +178 -0
- package/scripts/repo-wiki-local.mjs +156 -0
- package/scripts/repo-wiki.mjs +119 -0
- package/skills/copilot-pr-followup/SKILL.md +380 -0
- package/skills/dev-loop/SKILL.md +141 -0
- package/skills/dev-loop/scripts/dev-mode-context.mjs +152 -0
- package/skills/dev-loop/scripts/dev-mode-context.test.mjs +80 -0
- package/skills/dev-loop/scripts/init-phase.mjs +71 -0
- package/skills/dev-loop/scripts/log-bash-exit-1.mjs +25 -0
- package/skills/dev-loop/scripts/phase-files.mjs +29 -0
- package/skills/dev-loop/scripts/post-gate-verdict-fallback.mjs +480 -0
- package/skills/dev-loop/scripts/post-gate-verdict-fallback.test.mjs +732 -0
- package/skills/dev-loop/scripts/render-template.mjs +82 -0
- package/skills/dev-loop/scripts/render-template.test.mjs +63 -0
- package/skills/dev-loop/templates/bootstrap-agents.md +26 -0
- package/skills/dev-loop/templates/bootstrap-implementation-state.md +31 -0
- package/skills/dev-loop/templates/bootstrap-implementation-workflow.md +17 -0
- package/skills/dev-loop/templates/dev-mode-retrospective.md +15 -0
- package/skills/dev-loop/templates/dev-mode-review.md +17 -0
- package/skills/dev-loop/templates/dev-mode-skill-changes.md +11 -0
- package/skills/dev-loop/templates/merged-phase-plan.md +19 -0
- package/skills/dev-loop/templates/phase-doc.md +27 -0
- package/skills/dev-loop/templates/phase-summary.md +13 -0
- package/skills/dev-loop/templates/phase-variant.md +15 -0
- package/skills/dev-loop/templates/retrospective.md +11 -0
- package/skills/dev-loop/templates/review.md +32 -0
- package/skills/dev-loop/templates/ui-vision-review.md +55 -0
- package/skills/docs/acceptance-criteria-verification.md +21 -0
- package/skills/docs/anti-patterns.md +21 -0
- package/skills/docs/artifact-authority-contract.md +119 -0
- package/skills/docs/confirmation-rules.md +28 -0
- package/skills/docs/copilot-ci-status-contract.md +52 -0
- package/skills/docs/copilot-loop-operations.md +233 -0
- package/skills/docs/debt-remediation-contract.md +107 -0
- package/skills/docs/entrypoint-strategies.md +115 -0
- package/skills/docs/epic-tree-refinement-procedure.md +234 -0
- package/skills/docs/issue-intake-procedure.md +235 -0
- package/skills/docs/main-agent-contract.md +72 -0
- package/skills/docs/merge-preconditions.md +29 -0
- package/skills/docs/pr-lifecycle-contract.md +209 -0
- package/skills/docs/public-dev-loop-contract.md +497 -0
- package/skills/docs/retrospective-checkpoint-contract.md +159 -0
- package/skills/docs/stop-conditions.md +29 -0
- package/skills/docs/structural-quality.md +42 -0
- package/skills/docs/tracker-first-loop-state.md +281 -0
- package/skills/docs/validation-policy.md +27 -0
- package/skills/docs/workflow-handoff-contract.md +135 -0
- package/skills/final-approval/SKILL.md +19 -0
- package/skills/local-implementation/SKILL.md +640 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
|
|
5
|
+
export function renderTemplate(template, variables) {
|
|
6
|
+
if (typeof template !== "string") {
|
|
7
|
+
throw new Error("template must be a string");
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return template.replace(/{{\s*([a-zA-Z0-9_-]+)\s*}}/g, (match, key) => {
|
|
11
|
+
if (!(key in variables)) {
|
|
12
|
+
throw new Error(`Missing template variable: ${key}`);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return String(variables[key]);
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function materializeTemplate(templatePath, outputPath, variables) {
|
|
20
|
+
const template = await readFile(templatePath, "utf8");
|
|
21
|
+
const content = renderTemplate(template, variables);
|
|
22
|
+
await mkdir(path.dirname(outputPath), { recursive: true });
|
|
23
|
+
await writeFile(outputPath, content, "utf8");
|
|
24
|
+
return { templatePath, outputPath, content };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function parseCliArgs(argv) {
|
|
28
|
+
const args = [...argv];
|
|
29
|
+
let templatePath;
|
|
30
|
+
let outputPath;
|
|
31
|
+
let variables = {};
|
|
32
|
+
|
|
33
|
+
while (args.length > 0) {
|
|
34
|
+
const token = args.shift();
|
|
35
|
+
|
|
36
|
+
if (token === "--template") {
|
|
37
|
+
templatePath = args.shift();
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (token === "--output") {
|
|
42
|
+
outputPath = args.shift();
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (token === "--vars") {
|
|
47
|
+
variables = JSON.parse(args.shift() ?? "{}");
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
throw new Error(`Unknown argument: ${token}`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (!templatePath) {
|
|
55
|
+
throw new Error("Missing required --template <path> argument");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!outputPath) {
|
|
59
|
+
throw new Error("Missing required --output <path> argument");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return { templatePath, outputPath, variables };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export async function runCli(argv = process.argv.slice(2)) {
|
|
66
|
+
const options = parseCliArgs(argv);
|
|
67
|
+
const result = await materializeTemplate(options.templatePath, options.outputPath, options.variables);
|
|
68
|
+
process.stdout.write(
|
|
69
|
+
`${JSON.stringify({ ok: true, templatePath: result.templatePath, outputPath: result.outputPath })}\n`,
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const invokedAsScript = process.argv[1]
|
|
74
|
+
? import.meta.url === pathToFileURL(process.argv[1]).href
|
|
75
|
+
: false;
|
|
76
|
+
|
|
77
|
+
if (invokedAsScript) {
|
|
78
|
+
runCli().catch((error) => {
|
|
79
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
80
|
+
process.exitCode = 1;
|
|
81
|
+
});
|
|
82
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
|
|
7
|
+
import { materializeTemplate, parseCliArgs, renderTemplate } from "./render-template.mjs";
|
|
8
|
+
|
|
9
|
+
test("render-template renders placeholders deterministically", () => {
|
|
10
|
+
assert.equal(
|
|
11
|
+
renderTemplate("# Phase {{phase}} variant {{variant}}\n", {
|
|
12
|
+
phase: "phase-0",
|
|
13
|
+
variant: "a",
|
|
14
|
+
}),
|
|
15
|
+
"# Phase phase-0 variant a\n",
|
|
16
|
+
);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test("render-template throws on missing variables", () => {
|
|
20
|
+
assert.throws(() => renderTemplate("Hello {{name}}", {}), /missing template variable: name/i);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test("render-template materializes a template file", async () => {
|
|
24
|
+
const tempDir = await mkdtemp(path.join(os.tmpdir(), "dev-loop-render-template-"));
|
|
25
|
+
const templatePath = path.join(tempDir, "template.md");
|
|
26
|
+
const outputPath = path.join(tempDir, "out", "variant-a.md");
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
await writeFile(templatePath, "# {{phase}}\n{{body}}\n", "utf8");
|
|
30
|
+
await materializeTemplate(templatePath, outputPath, {
|
|
31
|
+
phase: "phase-0",
|
|
32
|
+
body: "hello",
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const output = await readFile(outputPath, "utf8");
|
|
36
|
+
assert.equal(output, "# phase-0\nhello\n");
|
|
37
|
+
} finally {
|
|
38
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("render-template parses cli args", () => {
|
|
43
|
+
assert.deepEqual(
|
|
44
|
+
parseCliArgs([
|
|
45
|
+
"--template",
|
|
46
|
+
"templates/x.md",
|
|
47
|
+
"--output",
|
|
48
|
+
"tmp/x.md",
|
|
49
|
+
"--vars",
|
|
50
|
+
'{"phase":"phase-0"}',
|
|
51
|
+
]),
|
|
52
|
+
{
|
|
53
|
+
templatePath: "templates/x.md",
|
|
54
|
+
outputPath: "tmp/x.md",
|
|
55
|
+
variables: { phase: "phase-0" },
|
|
56
|
+
},
|
|
57
|
+
);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("render-template requires template and output args", () => {
|
|
61
|
+
assert.throws(() => parseCliArgs(["--output", "tmp/x.md"]), /missing required --template/i);
|
|
62
|
+
assert.throws(() => parseCliArgs(["--template", "templates/x.md"]), /missing required --output/i);
|
|
63
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
## Project contract
|
|
4
|
+
|
|
5
|
+
This repository uses the `dev-loop` skill as the primary implementation workflow.
|
|
6
|
+
|
|
7
|
+
The skill may be provided repo-locally or globally; this contract does not assume a local skill path.
|
|
8
|
+
|
|
9
|
+
## Working agreement
|
|
10
|
+
|
|
11
|
+
- Work test-first for all non-trivial logic.
|
|
12
|
+
- Maintain at least 90% coverage for lines, statements, functions, and branches.
|
|
13
|
+
- Implement one phase at a time.
|
|
14
|
+
- Use fan-out / fan-in / review / merge before implementing each phase.
|
|
15
|
+
- Keep logs under `tmp/` in deterministic phase-scoped paths.
|
|
16
|
+
- Use local branches and small commits only after local verification.
|
|
17
|
+
- Do not assume GitHub PR or issue workflows.
|
|
18
|
+
|
|
19
|
+
## Core guard rails
|
|
20
|
+
|
|
21
|
+
- KISS
|
|
22
|
+
- SRP
|
|
23
|
+
- YAGNI
|
|
24
|
+
- strict TypeScript
|
|
25
|
+
- thin runtime glue
|
|
26
|
+
- no production reliance on Pi private internals
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Implementation state
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
|
|
5
|
+
Preparation is in place. Implementation has not started.
|
|
6
|
+
|
|
7
|
+
## Current source of truth
|
|
8
|
+
|
|
9
|
+
- Product plan: [Project Plan](../../../PLAN.md)
|
|
10
|
+
- Durable phase plans: [Phase Plan](../../../docs/phases/)
|
|
11
|
+
- Execution skill: `dev-loop`
|
|
12
|
+
- Repo contract: [Agent Instructions](../../../AGENTS.md)
|
|
13
|
+
- Workflow explainer: [Implementation Workflow](../../../docs/IMPLEMENTATION_WORKFLOW.md)
|
|
14
|
+
- tmp index for fresh-context inspection if present locally: `tmp/phases/index.json`
|
|
15
|
+
|
|
16
|
+
## Next action for a fresh session
|
|
17
|
+
|
|
18
|
+
If the user says **"start implementation"**:
|
|
19
|
+
|
|
20
|
+
1. read [Project Plan](../../../PLAN.md)
|
|
21
|
+
2. load the `dev-loop` skill
|
|
22
|
+
3. read [Agent Instructions](../../../AGENTS.md) if it exists
|
|
23
|
+
4. read [Implementation Workflow](../../../docs/IMPLEMENTATION_WORKFLOW.md)
|
|
24
|
+
5. read the current durable phase plan under `docs/phases/` if it exists
|
|
25
|
+
6. inspect `tmp/phases/` only if it exists locally and is relevant
|
|
26
|
+
7. read this file
|
|
27
|
+
8. start with the next unfinished phase only
|
|
28
|
+
|
|
29
|
+
## Next unfinished phase
|
|
30
|
+
|
|
31
|
+
Phase 0 — define the workflow convention, durable phase-plan format, and initial package boundary.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Implementation workflow
|
|
2
|
+
|
|
3
|
+
This file is optional. The primary execution entrypoint is the `dev-loop` skill.
|
|
4
|
+
|
|
5
|
+
Use this file for repo-specific workflow notes that complement the skill.
|
|
6
|
+
|
|
7
|
+
## Defaults
|
|
8
|
+
|
|
9
|
+
- one phase at a time
|
|
10
|
+
- [Project Plan](../../../PLAN.md) holds roadmap/product truth
|
|
11
|
+
- `docs/phases/phase-<n>.md` holds the durable plan for the active phase
|
|
12
|
+
- `tmp/phases/phase-<n>/` holds temporary local execution artifacts, reviews, and logs
|
|
13
|
+
- fan-out / fan-in / review / merge before coding
|
|
14
|
+
- test-first
|
|
15
|
+
- deterministic tmp logging
|
|
16
|
+
- local validation before phase completion
|
|
17
|
+
- local branches and small commits only after verification
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Phase {{phase}} dev-mode retrospective
|
|
2
|
+
|
|
3
|
+
## Iteration reviewed
|
|
4
|
+
|
|
5
|
+
## What the loop did well
|
|
6
|
+
|
|
7
|
+
## What created friction or waste
|
|
8
|
+
|
|
9
|
+
## Prompt follow-ups required
|
|
10
|
+
|
|
11
|
+
## Prompt and workflow changes applied
|
|
12
|
+
|
|
13
|
+
## Validation of the follow-up changes
|
|
14
|
+
|
|
15
|
+
## Next dev-mode watchpoints
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Phase {{phase}} dev-mode review
|
|
2
|
+
|
|
3
|
+
Optional analytical notes that support the required [Dev Mode Retrospective](./dev-mode-retrospective.md).
|
|
4
|
+
|
|
5
|
+
## Iteration reviewed
|
|
6
|
+
|
|
7
|
+
## Artifact inputs reviewed
|
|
8
|
+
|
|
9
|
+
## What the skill did well
|
|
10
|
+
|
|
11
|
+
## Friction and failure patterns
|
|
12
|
+
|
|
13
|
+
## Deterministic tooling gaps
|
|
14
|
+
|
|
15
|
+
## Recommended skill or workflow changes
|
|
16
|
+
|
|
17
|
+
## Decision
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Phase {{phase}} merged plan
|
|
2
|
+
|
|
3
|
+
## Selected direction
|
|
4
|
+
|
|
5
|
+
## Exact scope
|
|
6
|
+
|
|
7
|
+
## Explicit non-goals
|
|
8
|
+
|
|
9
|
+
## Tests to write first
|
|
10
|
+
|
|
11
|
+
## Implementation order
|
|
12
|
+
|
|
13
|
+
## Validation steps
|
|
14
|
+
|
|
15
|
+
## Acceptance criteria
|
|
16
|
+
|
|
17
|
+
## Definition of done
|
|
18
|
+
|
|
19
|
+
## Risks / watchpoints
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# {{phase}} durable plan
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
|
|
5
|
+
Planning
|
|
6
|
+
|
|
7
|
+
## Objective
|
|
8
|
+
|
|
9
|
+
## Why this phase exists now
|
|
10
|
+
|
|
11
|
+
## In scope
|
|
12
|
+
|
|
13
|
+
## Explicit non-goals
|
|
14
|
+
|
|
15
|
+
## Acceptance criteria
|
|
16
|
+
|
|
17
|
+
## Definition of done
|
|
18
|
+
|
|
19
|
+
## Validation approach
|
|
20
|
+
|
|
21
|
+
## Durable decisions
|
|
22
|
+
|
|
23
|
+
## Open questions
|
|
24
|
+
|
|
25
|
+
## Links to execution artifacts
|
|
26
|
+
|
|
27
|
+
- local execution artifacts may exist under `tmp/phases/{{phase}}/`
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Phase {{phase}} retrospective
|
|
2
|
+
|
|
3
|
+
## What worked well
|
|
4
|
+
|
|
5
|
+
## What caused friction or waste
|
|
6
|
+
|
|
7
|
+
## Fan-out / fan-in / review loop effectiveness
|
|
8
|
+
|
|
9
|
+
## What to change in the skill or workflow next time
|
|
10
|
+
|
|
11
|
+
## What a fresh session should know before the next phase
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Phase {{phase}} merged-plan review
|
|
2
|
+
|
|
3
|
+
## Review verdict
|
|
4
|
+
|
|
5
|
+
## Scope overreach check
|
|
6
|
+
|
|
7
|
+
## Default pre-approval gate
|
|
8
|
+
<!-- Resolve angles from config: resolveGateAngles(config, "preApproval") -->
|
|
9
|
+
- configured angle checks: add one bullet per configured pre-approval angle (for example `dry`, `kiss`, `yagni`, `srp`, `soc` when defaults apply)
|
|
10
|
+
- fallback note: if parallel execution of the configured review angles is impractical, record why and confirm all configured angles were still covered
|
|
11
|
+
|
|
12
|
+
## Additional design-principle check (SRP, etc.)
|
|
13
|
+
|
|
14
|
+
## Test and validation check
|
|
15
|
+
|
|
16
|
+
## Module boundary check
|
|
17
|
+
|
|
18
|
+
## Pi API / runtime coupling check
|
|
19
|
+
|
|
20
|
+
## Acceptance criteria clarity check
|
|
21
|
+
|
|
22
|
+
## Definition-of-done clarity check
|
|
23
|
+
|
|
24
|
+
## Review-surface completeness check
|
|
25
|
+
- review-surface completeness: confirm the merged plan and durable phase doc both carry stable definition-of-done output
|
|
26
|
+
- confirm the review surface checks the planned definition of done instead of only acceptance criteria
|
|
27
|
+
|
|
28
|
+
## RFC-escalation sanity check
|
|
29
|
+
- confirm RFC-worthy technical decisions are escalated to the parent session / human operator
|
|
30
|
+
- confirm the parent-session receiving boundary and decision ownership remain explicit
|
|
31
|
+
|
|
32
|
+
## Required revisions
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Vision-model UI review prompt template
|
|
2
|
+
|
|
3
|
+
Use this template when `uiReviewMode` is `vision`.
|
|
4
|
+
|
|
5
|
+
You are a vision-capable UI reviewer (model: `gpt-5.4`) reviewing deterministic named-state artifacts produced by `captureNamedUiState()`.
|
|
6
|
+
|
|
7
|
+
## Inputs
|
|
8
|
+
|
|
9
|
+
- `acceptanceCriteria`: required list of UI acceptance criteria
|
|
10
|
+
- `reviewBrief`: required short focus brief
|
|
11
|
+
- `artifactBundle.sliceId`: required UI slice id
|
|
12
|
+
- `artifactBundle.namedStates[]`: required list of named states
|
|
13
|
+
- `stateName`
|
|
14
|
+
- `screenshotPath` (must point to `screenshot.png`)
|
|
15
|
+
- `statePath` (must point to `state.json`)
|
|
16
|
+
|
|
17
|
+
## Review policy
|
|
18
|
+
|
|
19
|
+
1. Fail closed when required inputs are missing, ambiguous, or unreadable.
|
|
20
|
+
2. Ground every finding in one or more `screenshotPath` and `statePath` references.
|
|
21
|
+
3. Evaluate layout, hierarchy, spacing, clipping, overlap, contrast, callouts/highlighting, and state-transition clarity against the acceptance criteria and review brief.
|
|
22
|
+
4. Return only deterministic findings; do not invent evidence that is not visible in artifacts.
|
|
23
|
+
|
|
24
|
+
## Required output format
|
|
25
|
+
|
|
26
|
+
Allowed enum values:
|
|
27
|
+
- `outcome`: `"continue_ui_fix_loop"` | `"ui_review_satisfied"` | `"blocked_needs_human_decision"`
|
|
28
|
+
- `severity`: `"high"` | `"medium"` | `"low"`
|
|
29
|
+
|
|
30
|
+
`blockedReason` must always be present in the output. Set it to `null` unless `outcome` is `"blocked_needs_human_decision"`, in which case provide a non-empty string explaining the block reason.
|
|
31
|
+
|
|
32
|
+
Return strict JSON with this shape (example uses concrete values):
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"outcome": "ui_review_satisfied",
|
|
37
|
+
"summary": "short overall verdict",
|
|
38
|
+
"findings": [
|
|
39
|
+
{
|
|
40
|
+
"severity": "medium",
|
|
41
|
+
"stateName": "named state label",
|
|
42
|
+
"evidence": {
|
|
43
|
+
"screenshotPath": "test-results/ui-smoke/<sliceId>/named-states/<state-slug>/screenshot.png",
|
|
44
|
+
"statePath": "test-results/ui-smoke/<sliceId>/named-states/<state-slug>/state.json"
|
|
45
|
+
},
|
|
46
|
+
"problem": "what is visually wrong or unclear",
|
|
47
|
+
"suggestedFix": "specific corrective action"
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
"nextIterationFocus": [
|
|
51
|
+
"small, actionable UI fix target"
|
|
52
|
+
],
|
|
53
|
+
"blockedReason": null
|
|
54
|
+
}
|
|
55
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Acceptance Criteria Verification
|
|
2
|
+
|
|
3
|
+
Extracted procedure for verifying issue acceptance criteria during the `pre_approval_gate`. Referenced from [Copilot PR Follow-up Skill](../copilot-pr-followup/SKILL.md#pre-approval-gate-contract).
|
|
4
|
+
|
|
5
|
+
## Procedure
|
|
6
|
+
|
|
7
|
+
Before posting the `pre_approval_gate` comment, verify every acceptance criteria checklist item in the issue linked to this PR:
|
|
8
|
+
|
|
9
|
+
1. **Resolve the linked issue number deterministically:** use `gh pr view <pr-number> --repo <owner/name> --json closingIssuesReferences,body` and apply this decision tree: if there is exactly one closing issue reference, use it; else if there is exactly one PR-body `Closes #N` / `Fixes #N` pattern, use it; otherwise (zero or multiple candidates), post the gate comment with verdict `blocked` (gate cannot complete deterministically) rather than guessing.
|
|
10
|
+
|
|
11
|
+
2. **Read the issue body:** `gh issue view <issue-number> --repo <owner/name> --json body`
|
|
12
|
+
|
|
13
|
+
3. **Extract checklist items** from the **Acceptance criteria** section of the issue body (both `- [ ]` unchecked and `- [x]` already-checked items). Ignore checklist items from other sections (DoD, tasks, non-goals) that are not acceptance criteria.
|
|
14
|
+
|
|
15
|
+
4. **Verify each AC item** against the proposed changes on the current PR head.
|
|
16
|
+
|
|
17
|
+
5. **Update the issue body once:** compute the fully-updated issue body by replacing each verified item's `- [ ]` with `- [x]`, write it to a temporary file, and perform a single `gh issue edit <issue-number> --body-file <tmp-file> --repo <owner/name>`. Do not issue one edit per item; prefer `--body-file` over inline `--body` to avoid shell quoting/escaping hazards.
|
|
18
|
+
|
|
19
|
+
6. **Post the gate comment:** always post a `pre_approval_gate` comment (the checkpoint verdict comment contract requires a visible comment even for non-`clean` verdicts). Use verdict `clean` only when all AC items are verified; use verdict `findings_present` when any AC item is not satisfied and requires follow-up fixes; use verdict `blocked` when the gate cannot complete deterministically (for example no linked issue, ambiguous issue linkage, or the issue body is unavailable). In all cases include a note on AC verification status.
|
|
20
|
+
|
|
21
|
+
When the issue body has no AC checklist items, post the gate comment with verdict `findings_present` and note that fact explicitly rather than assuming satisfaction.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Anti-patterns
|
|
2
|
+
|
|
3
|
+
Canonical owner for anti-pattern guidance across all workflow families.
|
|
4
|
+
|
|
5
|
+
## Core anti-patterns
|
|
6
|
+
|
|
7
|
+
1. **Skipping fan-out/fan-in for non-trivial changes**: Do not implement directly without refinement when scope exceeds light-mode thresholds.
|
|
8
|
+
2. **Routing review-only work through local_implementation**: Review-only comparison, synthesis, or consolidation must use `refiner` agent, not `dev-loop` + `local_implementation`.
|
|
9
|
+
3. **Thin placeholder PR descriptions**: Always include change summary, scope/context, acceptance criteria, definition of done, non-goals, and `Closes #N`.
|
|
10
|
+
4. **Merging directly to main without PR**: Use PR-based remote loop when practical.
|
|
11
|
+
5. **Duplicate worktree paths**: Check `git worktree list` before creating new worktrees; reuse existing matching worktrees.
|
|
12
|
+
6. **Main-checkout mutation**: Reserve main checkout for inspection/control; use `tmp/worktrees/` paths for mutation work.
|
|
13
|
+
|
|
14
|
+
## Light mode exception
|
|
15
|
+
|
|
16
|
+
Small scoped changes (≤3 files, ≤200 lines) may skip fan-out/fan-in but must still run validation and a single review pass. See [Local Implementation](../local-implementation/SKILL.md) for details.
|
|
17
|
+
|
|
18
|
+
## Cross-references
|
|
19
|
+
|
|
20
|
+
- [Structural quality](structural-quality.md)
|
|
21
|
+
- [Validation policy](validation-policy.md)
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Artifact authority contract
|
|
2
|
+
|
|
3
|
+
This document is the canonical authority for the artifact-selection model: when work originates from a GitHub issue (tracker-first) vs a persisted markdown plan file (local-planning).
|
|
4
|
+
|
|
5
|
+
This canonical owner lives in the shipped `skills/docs/` surface because installed skill/runtime consumers reliably own the skills subtree. In installed layouts, read the same contract via [Artifact Authority Contract](../docs/artifact-authority-contract.md) from the installed skill directory.
|
|
6
|
+
|
|
7
|
+
Other repo docs may summarize or link this contract, but they should not redefine it.
|
|
8
|
+
|
|
9
|
+
## Two-tier model
|
|
10
|
+
|
|
11
|
+
dev-loops supports two mutually exclusive artifact authority modes. Every work item must originate from exactly one authoritative artifact — a GitHub issue or a persisted markdown plan file. No work may originate from a PR or direct local change unless explicitly requested.
|
|
12
|
+
|
|
13
|
+
### Tracker-first (default)
|
|
14
|
+
|
|
15
|
+
**GitHub issues are the authoritative artifact store.** Work originates from a GitHub issue. A linked PR is the execution artifact. GitHub is the canonical source of truth for issue identity, acceptance criteria, scope, and lifecycle state.
|
|
16
|
+
|
|
17
|
+
Artifacts:
|
|
18
|
+
- **Planning artifact:** GitHub issue (title, body, labels, assignees, acceptance criteria)
|
|
19
|
+
- **Execution artifact:** GitHub PR (linked to issue; created during implementation)
|
|
20
|
+
- **No local duplicate:** Do not create `docs/phases/phase-<n>.md` for the same session when a GitHub issue is the canonical spec
|
|
21
|
+
|
|
22
|
+
Key contract:
|
|
23
|
+
- GitHub issue state is authoritative — not local notes or chat context
|
|
24
|
+
- A linked PR is the single canonical follow-up artifact for the issue
|
|
25
|
+
- When an open linked PR exists, reuse it rather than opening another
|
|
26
|
+
- Implementation may proceed through either the GitHub-first routed path or the local implementation strategy (see [Public Dev Loop Contract](public-dev-loop-contract.md) `targetPreference`)
|
|
27
|
+
|
|
28
|
+
### Local-planning (opt-out)
|
|
29
|
+
|
|
30
|
+
**Persisted markdown plan files are the authoritative artifact store.** Work originates from a markdown plan file committed to the repository. No GitHub issue is required. GitHub PRs are still used for review and merge, but the plan file is the canonical spec.
|
|
31
|
+
|
|
32
|
+
Artifacts:
|
|
33
|
+
- **Planning artifact:** Persisted markdown plan file (e.g., `docs/phases/phase-<n>.md`)
|
|
34
|
+
- **Execution artifact:** Local branch and associated GitHub PR (created during implementation)
|
|
35
|
+
- **No GitHub issue:** The plan file replaces the issue as the canonical spec
|
|
36
|
+
|
|
37
|
+
Key contract:
|
|
38
|
+
- The markdown plan file is the canonical spec — not a duplicate of a tracker issue
|
|
39
|
+
- GitHub issues may still be used for tracking or linking, but the plan file is authoritative for scope and acceptance criteria
|
|
40
|
+
- A tracker-backed local implementation session (GitHub issue as canonical spec) must not also maintain a duplicate `docs/phases/phase-<n>.md` — see [Public Dev Loop Contract](public-dev-loop-contract.md) "Tracker-backed local implementation input-source contract"
|
|
41
|
+
|
|
42
|
+
### Mode selection table
|
|
43
|
+
|
|
44
|
+
| Mode | Canonical artifact | GitHub issue required | Settings values |
|
|
45
|
+
|---|---|---|---|
|
|
46
|
+
| Tracker-first (default) | GitHub issue | Yes | `strategy.default: github-first` |
|
|
47
|
+
| Local-planning (opt-out) | Markdown plan file | No | `strategy.default: local-first` |
|
|
48
|
+
|
|
49
|
+
`inputSource.default` further disambiguates local-first startup:
|
|
50
|
+
| inputSource | Meaning |
|
|
51
|
+
|---|---|
|
|
52
|
+
| `tracker` (default) | Local agent implements from the GitHub issue body; no phase doc created |
|
|
53
|
+
| `phase-docs` | Local agent implements from persisted phase docs (e.g., `docs/phases/phase-<n>.md`) |
|
|
54
|
+
|
|
55
|
+
## Settings mechanism
|
|
56
|
+
|
|
57
|
+
Artifact authority mode is controlled by `.devloops` at repo root:
|
|
58
|
+
|
|
59
|
+
```yaml
|
|
60
|
+
# .devloops
|
|
61
|
+
strategy:
|
|
62
|
+
default: github-first # tracker-first (GitHub issue required)
|
|
63
|
+
# default: local-first # local-planning (markdown plan file)
|
|
64
|
+
inputSource:
|
|
65
|
+
default: tracker # spec source for local-first: tracker (issue body) or phase-docs
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The `strategy.default` key serves dual purpose:
|
|
69
|
+
1. It selects the artifact authority mode (tracker-first vs local-planning)
|
|
70
|
+
2. It sets the default routing preference for `targetPreference` in dev-loop startup
|
|
71
|
+
|
|
72
|
+
The `inputSource.default` key disambiguates local-first startup:
|
|
73
|
+
- `tracker` (default): local agent implements from the GitHub issue body; the issue is canonical spec
|
|
74
|
+
- `phase-docs`: local agent implements from persisted phase docs; no tracker issue required
|
|
75
|
+
|
|
76
|
+
These keys are already defined in `.pi/dev-loop/defaults.yaml` (shipped with dev-loops) and may be overridden in `.devloops` (per-repo).
|
|
77
|
+
|
|
78
|
+
### Defaults resolution
|
|
79
|
+
|
|
80
|
+
1. `.pi/dev-loop/defaults.yaml` — shipped default (`github-first`)
|
|
81
|
+
2. `.devloops` — per-repo override (takes precedence)
|
|
82
|
+
|
|
83
|
+
### Explicit non-knobs
|
|
84
|
+
|
|
85
|
+
These are not valid artifact authority mode selectors:
|
|
86
|
+
- `strategy.default: copilot` — not a valid mode; must be `github-first` or `local-first`
|
|
87
|
+
- Free-form string values — fail closed
|
|
88
|
+
- Omitting `strategy.default` entirely — defaults to `github-first` from the shipped defaults
|
|
89
|
+
|
|
90
|
+
## dev-loops own mode
|
|
91
|
+
|
|
92
|
+
dev-loops is **tracker-first (opted in, GitHub backend).**
|
|
93
|
+
|
|
94
|
+
- **Mode:** Tracker-first
|
|
95
|
+
- **Settings:** `.pi/dev-loop/defaults.yaml` sets `strategy.default: github-first`
|
|
96
|
+
- **Artifact authority:** GitHub issues are the canonical spec for all work in this repository
|
|
97
|
+
- **No local-planning override:** This repo does not opt out to local-planning mode
|
|
98
|
+
- **Why tracker-first:** All work in this repo originates from GitHub issues. The public dev-loop contract, Copilot follow-up state machines, and gate pipeline all assume issues are the primary artifact. Self-improvement work on dev-loops itself follows the same tracker-first contract.
|
|
99
|
+
|
|
100
|
+
## Relationship to other docs
|
|
101
|
+
|
|
102
|
+
| Doc | Relationship |
|
|
103
|
+
|---|---|
|
|
104
|
+
| [Public Dev Loop Contract](public-dev-loop-contract.md) | This contract is the canonical entrypoint; artifact authority contract defines the artifact model it assumes |
|
|
105
|
+
| [Tracker-First Loop State](tracker-first-loop-state.md) | That doc defines the PR-level state machine for tracker-first PR workflows — it is about execution state, not artifact authority |
|
|
106
|
+
| [Main Agent Contract](main-agent-contract.md) | Defines the delegation boundary; artifact authority defines which artifacts govern work |
|
|
107
|
+
| AGENTS.md | Repo constitution; cites the work-origin rule and points to this contract |
|
|
108
|
+
| [Dev Loop Skill](../dev-loop/SKILL.md) | Public entrypoint skill; cites the work-origin rule and points to this contract |
|
|
109
|
+
|
|
110
|
+
### Distinction: artifact authority vs tracker-first PR workflow
|
|
111
|
+
|
|
112
|
+
`tracker-first-loop-state.md` defines a state machine for PR lifecycle management when a tracker item (e.g., Shortcut story) drives a GitHub PR. That is a **PR-level workflow contract**, not the artifact authority model. The term "tracker-first" in that doc refers to tracker-driven PR state transitions — it does not redefine the artifact authority contract defined here.
|
|
113
|
+
|
|
114
|
+
## Non-goals
|
|
115
|
+
|
|
116
|
+
- Defining tracker adapters or multi-tracker support
|
|
117
|
+
- Specifying how PRs map to issues in detail (that is the [Public Dev Loop Contract](public-dev-loop-contract.md))
|
|
118
|
+
- Changing the dev-loop startup resolver behavior
|
|
119
|
+
- Adding tracker-specific settings beyond `inputSource` — further tracker adapters or multi-tracker support remain out of scope
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Confirmation rules
|
|
2
|
+
|
|
3
|
+
Canonical owner for agent confirmation / authorization rules across all workflow families.
|
|
4
|
+
|
|
5
|
+
## Core rule
|
|
6
|
+
|
|
7
|
+
Before any state-changing action, get explicit confirmation unless the latest user message already clearly authorizes that exact action.
|
|
8
|
+
|
|
9
|
+
## What counts as confirmation
|
|
10
|
+
|
|
11
|
+
- ✅ Explicit authorization in the current conversation
|
|
12
|
+
- ✅ Pre-authorized merge or mutation scope (e.g. "Merge authorized if gates green")
|
|
13
|
+
- ❌ Questions, preferences, future-tense statements
|
|
14
|
+
- ❌ Implied approval from prior turns
|
|
15
|
+
- ❌ Bare response `ok`
|
|
16
|
+
|
|
17
|
+
## Where this rule applies
|
|
18
|
+
|
|
19
|
+
- All routed strategies (`local_implementation`, `copilot_pr_followup`, `issue_intake`, `reviewer_fixer`, `final_approval`)
|
|
20
|
+
- All gate entries (`draft_gate`, `pre_approval_gate`)
|
|
21
|
+
- All merge operations
|
|
22
|
+
- All force-push / history-rewriting operations
|
|
23
|
+
|
|
24
|
+
## Cross-references
|
|
25
|
+
|
|
26
|
+
- [Stop conditions](stop-conditions.md)
|
|
27
|
+
- [Merge preconditions](merge-preconditions.md)
|
|
28
|
+
- [Public Dev Loop Contract](public-dev-loop-contract.md)
|