@vegastack/skills 0.9.1 → 0.11.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.
Files changed (85) hide show
  1. package/README.md +8 -3
  2. package/dist/index.js +5 -5
  3. package/package.json +1 -1
  4. package/skill/dev-architect/SKILL.md +96 -0
  5. package/skill/dev-architect/agents/openai.yaml +4 -0
  6. package/skill/dev-architect/references/ai-agents.md +89 -0
  7. package/skill/dev-architect/references/conventions.md +93 -0
  8. package/skill/{architect → dev-architect}/references/data.md +43 -44
  9. package/skill/dev-architect/references/infra.md +98 -0
  10. package/skill/dev-architect/references/mobile.md +75 -0
  11. package/skill/{architect → dev-architect}/references/pinned-facts.md +17 -16
  12. package/skill/dev-architect/references/principles.md +117 -0
  13. package/skill/{architect → dev-architect}/references/security.md +37 -44
  14. package/skill/dev-architect/references/stack.md +38 -0
  15. package/skill/dev-architect/references/web.md +102 -0
  16. package/skill/{architect → dev-architect}/refresh/REFRESH.md +8 -6
  17. package/skill/{architect → dev-architect}/refresh/sources.json +5 -10
  18. package/skill/dev-chronicle/SKILL.md +45 -0
  19. package/skill/dev-chronicle/agents/openai.yaml +4 -0
  20. package/skill/dev-chronicle/references/conventions.md +93 -0
  21. package/skill/dev-chronicle/refresh/REFRESH.md +3 -0
  22. package/skill/dev-chronicle/refresh/sources.json +6 -0
  23. package/skill/dev-debug/SKILL.md +43 -0
  24. package/skill/dev-debug/agents/openai.yaml +4 -0
  25. package/skill/dev-debug/references/conventions.md +93 -0
  26. package/skill/dev-debug/references/loop-ladder.md +20 -0
  27. package/skill/dev-debug/refresh/REFRESH.md +3 -0
  28. package/skill/dev-debug/refresh/sources.json +6 -0
  29. package/skill/dev-implement/SKILL.md +41 -36
  30. package/skill/dev-implement/references/conventions.md +93 -0
  31. package/skill/dev-implement/references/ledger-and-resume.md +27 -0
  32. package/skill/dev-implement/scripts/evidence-check.mjs +57 -0
  33. package/skill/dev-implement/scripts/lib/gh.mjs +93 -0
  34. package/skill/dev-implement/scripts/preflight.mjs +101 -0
  35. package/skill/dev-intake/SKILL.md +39 -33
  36. package/skill/dev-intake/references/brief-template.md +27 -12
  37. package/skill/dev-intake/references/conventions.md +93 -0
  38. package/skill/dev-intake/scripts/brief-lint.mjs +87 -0
  39. package/skill/dev-plan/SKILL.md +53 -0
  40. package/skill/dev-plan/agents/openai.yaml +4 -0
  41. package/skill/dev-plan/references/conventions.md +93 -0
  42. package/skill/dev-plan/references/plan-format.md +54 -0
  43. package/skill/dev-plan/refresh/REFRESH.md +3 -0
  44. package/skill/dev-plan/refresh/sources.json +6 -0
  45. package/skill/dev-plan/scripts/plan-lint.mjs +86 -0
  46. package/skill/dev-review/SKILL.md +69 -0
  47. package/skill/dev-review/agents/openai.yaml +4 -0
  48. package/skill/dev-review/assets/review-known-patterns.md.template +30 -0
  49. package/skill/dev-review/references/conventions.md +93 -0
  50. package/skill/dev-review/references/cross-agent.md +39 -0
  51. package/skill/dev-review/references/dispatch-prompts.md +104 -0
  52. package/skill/dev-review/references/security-axis.md +33 -0
  53. package/skill/dev-review/refresh/REFRESH.md +3 -0
  54. package/skill/dev-review/refresh/sources.json +6 -0
  55. package/skill/dev-setup/SKILL.md +14 -9
  56. package/skill/dev-setup/assets/agents-section.md.template +2 -2
  57. package/skill/dev-setup/assets/dev-profile.md.template +23 -5
  58. package/skill/dev-setup/references/conventions.md +93 -0
  59. package/skill/dev-setup/references/stack-playbooks.md +1 -1
  60. package/skill/dev-ship/SKILL.md +14 -7
  61. package/skill/dev-ship/references/conventions.md +93 -0
  62. package/skill/dev-ship/references/runbook.md +1 -1
  63. package/skill/dev-ship/scripts/ship-gate.mjs +213 -0
  64. package/skill/dev-status/SKILL.md +45 -0
  65. package/skill/dev-status/agents/openai.yaml +4 -0
  66. package/skill/dev-status/references/conventions.md +93 -0
  67. package/skill/dev-status/refresh/REFRESH.md +3 -0
  68. package/skill/dev-status/refresh/sources.json +6 -0
  69. package/skill/dev-status/scripts/status.mjs +152 -0
  70. package/skill/skill-maintainer/references/release-ops.md +3 -3
  71. package/skill/skillify/SKILL.md +1 -1
  72. package/skill/skillify/references/eval-playbook.md +6 -0
  73. package/skill-integrity.json +93 -33
  74. package/skill/architect/SKILL.md +0 -68
  75. package/skill/architect/agents/openai.yaml +0 -4
  76. package/skill/architect/assets/adr-template.md +0 -21
  77. package/skill/architect/assets/arch-template.md +0 -20
  78. package/skill/architect/references/advisory.md +0 -102
  79. package/skill/architect/references/ai-agents.md +0 -95
  80. package/skill/architect/references/infra.md +0 -128
  81. package/skill/architect/references/mobile.md +0 -78
  82. package/skill/architect/references/principles.md +0 -91
  83. package/skill/architect/references/project-profile.md +0 -37
  84. package/skill/architect/references/stack.md +0 -38
  85. package/skill/architect/references/web.md +0 -152
@@ -0,0 +1,27 @@
1
+ # Using the ledger
2
+
3
+ The ledger comment's format, line vocabulary, and the resume read-order (brief → plan → ledger → `git log`, nothing else) live in the `dev-setup` skill's `references/conventions.md` — this file owns only how dev-implement **uses** them. The ledger is the build's recovery map and the operator's live progress view.
4
+
5
+ ## When to checkpoint
6
+
7
+ Create the ledger comment as the session's **first write after claiming** — before any code — with just the marker and heading. Then checkpoint, editing in place:
8
+
9
+ - **After each plan task completes** — and tick the matching checkbox in the plan comment in the same pass. Record the task's base sha *before* starting it, so the `complete` line's commit range is exact.
10
+ - **After each review fix round**, with the addressed/open counts.
11
+ - **At every dark-mode judgment call.** A ruling is any decision the brief/plan didn't make for you that a reviewer or the operator could reasonably question. Rulings are cheap; unrecorded decisions are debt.
12
+ - **On findings deferred or parked at review**, per dev-review's adjudication lines.
13
+
14
+ Never batch checkpoints "for later" — the ledger's value is exactly that a crash between checkpoints loses one task, not the map. Under concurrent edits, last-writer-wins on one comment is accepted (single-operator workflow); note a clobber if you ever see one.
15
+
16
+ ## Resuming — dev-implement's additions to the protocol
17
+
18
+ - The takeover of a `working` issue requires the operator's explicit handover word; the protocol never makes claiming automatic.
19
+ - Corroborate, don't re-verify: the commits the ledger names should exist in `git log` — reconcile the ranges; a mismatch is a `handback`, not a guess.
20
+ - A task whose last line is a fix round is mid-loop — resume at the next round with the open findings; a later `complete` line supersedes earlier rounds.
21
+ - Recorded rulings bind the resumed session: build on them, and surface disagreement in the evidence comment instead of re-litigating.
22
+ - The "nothing else" is literal: not the full issue thread, not review round history, not any transcript of the dead session — that is context spent re-reading what the ledger already distills.
23
+ - Re-executing work the ledger marks complete is the single most expensive failure this protocol exists to prevent — after compaction, trust the ledger and `git log` over recollection.
24
+
25
+ ## Surfacing — rulings never die in the dark
26
+
27
+ Every `Ruling:` line lands on the evidence comment's `**Review:**` line at hand-back, in the order made. The operator reads that list and reverses anything wrong — a ruling that only ever lived in the ledger was a decision made in secret.
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env node
2
+ // dev-implement guard: the evidence comment's required shape. Structure blocks;
3
+ // nothing here warns.
4
+ //
5
+ // Exit codes: 0 pass · 2 blocked (this guard has no warn class).
6
+ // Usage: node evidence-check.mjs --file <evidence.md> --json
7
+ import { readFileSync } from 'node:fs';
8
+ import { resolve } from 'node:path';
9
+ import { fileURLToPath } from 'node:url';
10
+ import { parseFlags, parseMarker, renderResult } from './lib/gh.mjs';
11
+
12
+ const REQUIRED_SECTIONS = [
13
+ [/\*\*Done:\*\*/, '**Done:** section'],
14
+ [/\*\*Tests:\*\*/, '**Tests:** section (command → fresh result)'],
15
+ [/\*\*Review:\*\*/, '**Review:** section (mode + verdict/adjudications)'],
16
+ [/\*\*Changelog:\*\*/, '**Changelog:** section (entry, or none with a holding reason)'],
17
+ [/\*\*Docs:\*\*/, '**Docs:** section (brief/plan revisions in sync, or unchanged)'],
18
+ [/\*\*Not done/, '**Not done / limits:** section (the honest list)'],
19
+ ];
20
+
21
+ export function checkEvidence(text) {
22
+ const blocks = [];
23
+
24
+ const marker = parseMarker(text);
25
+ if (!marker || marker.keys.type !== 'evidence') {
26
+ blocks.push('missing evidence marker (<!-- vsk:v1 type=evidence rev=n branch=... sha=... -->)');
27
+ } else {
28
+ if (!marker.keys.branch) blocks.push('evidence marker missing branch=');
29
+ if (!/^[0-9a-f]{7,}$/.test(marker.keys.sha ?? '')) blocks.push('evidence marker missing a real sha=');
30
+ }
31
+
32
+ for (const [pattern, label] of REQUIRED_SECTIONS) {
33
+ if (!pattern.test(text)) blocks.push(`missing ${label}`);
34
+ }
35
+
36
+ if (!/Branch:\s*\S+\s*@\s*[0-9a-f]{7,}/.test(text)) blocks.push('missing "Branch: <name> @ <sha7>" tail line');
37
+
38
+ return { blocks, warns: [] };
39
+ }
40
+
41
+ const invokedDirectly = process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url);
42
+ if (invokedDirectly) {
43
+ const flags = parseFlags(process.argv.slice(2));
44
+ let outcome;
45
+ if (!flags.file) {
46
+ outcome = { blocks: ['usage: evidence-check.mjs --file <evidence.md> [--json]'], warns: [] };
47
+ } else {
48
+ try {
49
+ outcome = checkEvidence(readFileSync(flags.file, 'utf8'));
50
+ } catch (error) {
51
+ outcome = { blocks: [`cannot read evidence: ${error.message}`], warns: [] };
52
+ }
53
+ }
54
+ const { exitCode, text } = renderResult('evidence-check', outcome, { json: Boolean(flags.json) });
55
+ console.log(text);
56
+ process.exit(exitCode);
57
+ }
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env node
2
+ // Shared plumbing for the workflow guard scripts: gh invocation, vsk:v1 comment
3
+ // marker parsing, and the block/warn result contract (facts block, heuristics
4
+ // warn — exit 0 pass · 1 warn-only · 2 block; unverifiable state fails closed).
5
+ import { execFileSync } from 'node:child_process';
6
+
7
+ export class GhUnavailable extends Error {
8
+ constructor(message, httpStatus = null) {
9
+ super(message);
10
+ this.httpStatus = httpStatus; // parsed from gh's "HTTP <code>" stderr, when present
11
+ }
12
+ }
13
+
14
+ // Run gh with explicit args (never a shell) and parse JSON output. Any failure
15
+ // to reach GitHub is a GhUnavailable — callers treat it as "cannot verify",
16
+ // which blocks (fail closed), never as a pass. VSK_GH is a TEST SEAM only
17
+ // (points unit tests at a stub binary); guards are enforcement infrastructure,
18
+ // so never set it in real runs.
19
+ export function ghJson(args, { gh = process.env.VSK_GH || 'gh' } = {}) {
20
+ let out;
21
+ try {
22
+ out = execFileSync(gh, args, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] });
23
+ } catch (error) {
24
+ const stderr = error.stderr?.toString().trim() || '';
25
+ const status = /HTTP (\d{3})/.exec(stderr)?.[1];
26
+ throw new GhUnavailable(`gh ${args.join(' ')} failed: ${stderr || error.message}`, status ? Number(status) : null);
27
+ }
28
+ try {
29
+ return JSON.parse(out);
30
+ } catch {
31
+ throw new GhUnavailable(`gh ${args.join(' ')} returned unparseable JSON`);
32
+ }
33
+ }
34
+
35
+ // Parse a `<!-- vsk:v1 key=value ... -->` marker from a comment/body's first
36
+ // marker line. Returns { keys } or null when no marker exists — and per
37
+ // conventions, no marker means the artifact does not exist (no fallback).
38
+ export function parseMarker(body) {
39
+ const match = /<!--\s*vsk:v1\s+([^>]*?)\s*-->/.exec(body ?? '');
40
+ if (!match) return null;
41
+ const keys = {};
42
+ for (const pair of match[1].split(/\s+/)) {
43
+ const eq = pair.indexOf('=');
44
+ if (eq > 0) keys[pair.slice(0, eq)] = pair.slice(eq + 1);
45
+ }
46
+ return { keys };
47
+ }
48
+
49
+ // Find the last comment carrying a marker of the given type (last wins: for
50
+ // edited-in-place singletons there is one; for repeated types the newest is
51
+ // the operative one).
52
+ export function findMarkerComment(comments, type) {
53
+ let found = null;
54
+ for (const comment of comments ?? []) {
55
+ const marker = parseMarker(comment.body);
56
+ if (marker && marker.keys.type === type) found = { comment, keys: marker.keys };
57
+ }
58
+ return found;
59
+ }
60
+
61
+ // Render the guard result and compute the exit code. blocks/warns are arrays of
62
+ // human sentences; the caller passes process.argv-derived json flag.
63
+ export function renderResult(name, { blocks = [], warns = [] }, { json = false } = {}) {
64
+ const ok = blocks.length === 0;
65
+ const exitCode = blocks.length > 0 ? 2 : warns.length > 0 ? 1 : 0;
66
+ let text;
67
+ if (json) {
68
+ text = JSON.stringify({ guard: name, ok, blocks, warns }, null, 2);
69
+ } else {
70
+ const lines = [`${name}: ${ok ? (warns.length ? 'pass with warnings' : 'pass') : 'BLOCKED'}`];
71
+ for (const b of blocks) lines.push(` block: ${b}`);
72
+ for (const w of warns) lines.push(` warn: ${w}`);
73
+ text = lines.join('\n');
74
+ }
75
+ return { exitCode, text };
76
+ }
77
+
78
+ // Minimal flag parser shared by the guards: --key value and boolean --flags.
79
+ export function parseFlags(argv, booleans = ['json']) {
80
+ const flags = {};
81
+ for (let i = 0; i < argv.length; i += 1) {
82
+ const arg = argv[i];
83
+ if (!arg.startsWith('--')) continue;
84
+ const key = arg.slice(2);
85
+ if (booleans.includes(key)) {
86
+ flags[key] = true;
87
+ } else {
88
+ flags[key] = argv[i + 1];
89
+ i += 1;
90
+ }
91
+ }
92
+ return flags;
93
+ }
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/env node
2
+ // dev-implement preflight guard: the deterministic facts that must hold before
3
+ // an agent may claim an issue. Facts block (exit 2 with reasons); nothing here
4
+ // warns — judgment checks stay in the skill prose.
5
+ //
6
+ // Exit codes: 0 pass · 1 pass-with-warnings · 2 blocked (reasons printed).
7
+ // Usage: node preflight.mjs --issue <n> [--repo owner/name] [--me <login>] [--dev-md <path>] --json
8
+ import { readFileSync } from 'node:fs';
9
+ import { resolve } from 'node:path';
10
+ import { fileURLToPath } from 'node:url';
11
+ import { GhUnavailable, findMarkerComment, ghJson, parseFlags, renderResult } from './lib/gh.mjs';
12
+
13
+ export function evaluatePreflight({ issue, comments, devMd, me, expect = 'ready' }) {
14
+ const blocks = [];
15
+ const warns = [];
16
+ const labels = (issue.labels ?? []).map((l) => l.name);
17
+
18
+ if (issue.state && issue.state !== 'open') blocks.push(`issue is ${issue.state} — only open issues are workable`);
19
+ const STATE_LABELS = ['needs-operator', 'needs-plan', 'ready', 'working', 'for-operator'];
20
+ const state = STATE_LABELS.filter((s) => labels.includes(s));
21
+ if (!state.includes(expect)) {
22
+ blocks.push(`issue state label is [${state.join(', ') || 'none'}], expected ${expect} (fresh start: ready · resume: working with the operator's handover · corrections: for-operator)`);
23
+ }
24
+
25
+ const approval = findMarkerComment(comments, 'approval');
26
+ if (!approval) blocks.push('no recorded approval comment (marker type=approval) on the issue');
27
+
28
+ const scope = ['research', 'quick-build', 'full-plan'].filter((s) => labels.includes(s));
29
+ if (scope.length !== 1) blocks.push(`issue needs exactly one scope label (research | quick-build | full-plan), found: ${scope.join(', ') || 'none'}`);
30
+
31
+ if (scope[0] === 'full-plan') {
32
+ const planApproved = (comments ?? []).some((c) => {
33
+ const m = findMarkerComment([c], 'approval');
34
+ return m && ['plan', 'brief+plan'].includes(m.keys.scope);
35
+ });
36
+ if (!planApproved) blocks.push('full-plan issue without a recorded plan approval (marker type=approval scope=plan or brief+plan)');
37
+ }
38
+
39
+ // The brief-template rule: a resolved Assumptions section is deleted, so the
40
+ // heading's presence at all means unresolved entries remain.
41
+ if (/^##\s+Assumptions\b/m.test(issue.body ?? '')) {
42
+ blocks.push('the brief still carries a "## Assumptions" section — resolve every entry (the section is deleted once resolved) before starting');
43
+ }
44
+
45
+ const openBlockers = issue.blockedBy ?? [];
46
+ if (openBlockers.length > 0) blocks.push(`open blockers: ${openBlockers.map((b) => `#${b.number}`).join(', ')}`);
47
+
48
+ const others = (issue.assignees ?? []).map((a) => a.login).filter((l) => l !== me);
49
+ if (others.length > 0) blocks.push(`already assigned to ${others.join(', ')} — a working issue belongs to its claimant`);
50
+
51
+ const repoLine = /^repo:\s*(\S+)/m.exec(devMd ?? '');
52
+ if (!repoLine) {
53
+ warns.push('dev.md has no repo: line — the issue-repo match could not be verified');
54
+ } else if (issue.repo && repoLine[1] !== issue.repo) {
55
+ blocks.push(`issue repo ${issue.repo} does not match dev.md repo ${repoLine[1]}`);
56
+ }
57
+
58
+ return { blocks, warns };
59
+ }
60
+
61
+ export function gatherAndEvaluate(flags) {
62
+ const repo = flags.repo || ghJson(['repo', 'view', '--json', 'nameWithOwner']).nameWithOwner;
63
+ const issueNumber = flags.issue;
64
+ const raw = ghJson(['api', `repos/${repo}/issues/${issueNumber}`]);
65
+ const comments = ghJson(['api', `repos/${repo}/issues/${issueNumber}/comments`, '--paginate']);
66
+ let blockedBy = [];
67
+ try {
68
+ blockedBy = ghJson(['api', `repos/${repo}/issues/${issueNumber}/dependencies/blocked_by`])
69
+ .filter((b) => b.state === 'open');
70
+ } catch (error) {
71
+ // Only an HTTP 404 (host without the dependencies API) means "none
72
+ // recorded" — matched on the parsed status, never the message text, so a
73
+ // path containing "404" can't masquerade. Every other failure — auth,
74
+ // network, rate limit — is unverifiable state and fails closed.
75
+ if (error.httpStatus !== 404) throw error;
76
+ blockedBy = [];
77
+ }
78
+ const devMd = readFileSync(flags['dev-md'] || '.vegastack/dev.md', 'utf8');
79
+ const me = flags.me || ghJson(['api', 'user']).login;
80
+ return evaluatePreflight({
81
+ issue: { body: raw.body, state: raw.state, labels: raw.labels, assignees: raw.assignees, repo, blockedBy },
82
+ comments,
83
+ devMd,
84
+ me,
85
+ expect: flags.expect || 'ready',
86
+ });
87
+ }
88
+
89
+ const invokedDirectly = process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url);
90
+ if (invokedDirectly) {
91
+ const flags = parseFlags(process.argv.slice(2));
92
+ let outcome;
93
+ try {
94
+ outcome = gatherAndEvaluate(flags);
95
+ } catch (error) {
96
+ outcome = { blocks: [error instanceof GhUnavailable ? `cannot verify: ${error.message}` : `preflight error: ${error.message}`], warns: [] };
97
+ }
98
+ const { exitCode, text } = renderResult('preflight', outcome, { json: Boolean(flags.json) });
99
+ console.log(text);
100
+ process.exit(exitCode);
101
+ }
@@ -1,62 +1,68 @@
1
1
  ---
2
2
  name: dev-intake
3
- description: Turn ideas, brainstorms, feature requests, or SOW documents into GitHub issues an agent can implement without further questions. Use when asked to "turn this into issues", "create tasks from this SOW", "write up an issue for" a feature or bug, "plan this as issues", "slice this epic", or when the user gives approval on a drafted issue and it needs recording. Produces complete inline build briefs with labels, milestones, and blocker links. Not for implementing issues (dev-implement), creating PRs or merging (dev-ship), or project bootstrap (dev-setup).
3
+ description: Turn ideas, brainstorms, feature requests, bug reports, or SOW documents into GitHub issues an agent can act on without further questions. Use when asked to "turn this into issues", "create tasks from this SOW", "write up an issue for" a feature or bug, "users report X — make an issue", "plan this as issues", "slice this epic", or when the user gives approval on a drafted issue and it needs recording. Not for writing the implementation plan of an approved issue (dev-plan), implementing issues (dev-implement), creating PRs or merging (dev-ship), or project bootstrap (dev-setup).
4
4
  ---
5
5
 
6
6
  # dev-intake
7
7
 
8
- Requirements come in as the user's brainstorm, feature thought, or SOW; issues go out complete enough that a fresh agent needs nothing but the URL. Every question gets asked **here** — once implementation starts, dark mode means no questions, so an under-specified issue becomes either an interruption or a guess. This skill exists to make both impossible.
8
+ Requirements come in as the operator's brainstorm, feature thought, bug report, or SOW; issues go out complete enough that a fresh agent needs nothing but the URL. Every question gets asked **here** — once implementation starts, dark mode means no questions, so an under-specified issue becomes either an interruption or a guess. Artifact formats (markers, operator identity, labels, revisions) follow the `dev-setup` skill's `references/conventions.md`.
9
9
 
10
- Nearest neighbor: `dev-implement` consumes what this produces — intake writes and gets approval, implement builds. If `.vegastack/dev.md` is missing, run `dev-setup` first, then continue here.
10
+ Nearest neighbors: `dev-plan` owns the how once a brief is approved — intake owns the what/why and the approval mechanics; `dev-implement` builds. If `.vegastack/dev.md` is missing run `dev-setup` first, then continue.
11
11
 
12
12
  ## Ground before you ask
13
13
 
14
- Finding facts is your job, never the user's — and a brief built on unverified facts is a confident mistake waiting for dark mode. The source can be one sentence in chat; thinner material just means the grounding and interview carry more weight. Before the first question:
14
+ Finding facts is your job, never the operator's — a brief built on unverified facts is a confident mistake waiting for dark mode. Before the first question:
15
15
 
16
- - **Read the touched code.** Open the actual paths the feature would change: current behavior, existing patterns to reuse, where the new work plugs in. The brief cites these real paths later — a brief naming no files is a sign this step was skipped.
17
- - **Verify dependencies.** Any library, service, or API capability the approach leans on gets checked against current official docs (docs tools or web search), noted with the date. Consult `architect`'s pinned facts for stack questions before re-researching; re-verify a pinned fact older than 60 days; skip lookups for long-stable basics — judgment, not ritual.
18
- - **Cross-check the request** against product docs and current behavior. A contradiction is pushback, never a silent resolution: "you asked for X; the code/docs currently do Y — which wins?" Push back on cost the same way: when a simpler version covers most of the need, name it.
19
- - **Triage every unknown** into exactly three bins: *findable* → find it now, yourself; *only-the-user-knows* → ask, with a recommendation; *only-running-code-can-tell* → flag it as a spike that becomes the issue's first step. Guessing is not a bin.
16
+ - **Read the touched code.** Open the actual paths the work would change: current behavior, patterns to reuse, where it plugs in. The brief cites these real paths later — a brief naming no files is a sign this step was skipped.
17
+ - **Verify dependencies.** Any library, service, or API capability the approach leans on gets checked against current official docs, noted with the date. Stack, schema, auth, and infra choices route through `dev-architect` its verify protocol governs the check.
18
+ - **Cross-check the request** against product docs and current behavior. A contradiction is pushback, never a silent resolution: "you asked for X; the code currently does Y — which wins?" Push back on cost the same way: when a simpler version covers most of the need, name it.
19
+ - **Triage every unknown** into exactly three bins: *findable* → find it now, yourself; *only-the-operator-knows* → ask, with a recommendation; *only-running-code-can-tell* → a `research` issue or the issue's first spike step. Guessing is not a bin.
20
20
 
21
- ## The interview
21
+ ## Scope the work — say it out loud
22
+
23
+ Every issue gets exactly one scope call, announced with its reason, applied as a label, and recorded in the brief's `**Scope:**` line so the reasoning survives the conversation. The operator can override it:
22
24
 
23
- Ask in rounds using your harness's question tool (AskUserQuestion in Claude Code, `request_user_input` in Codex where the mode allows; no tool available → draft with recommended answers marked `TODO confirm` and say so). Each round covers the current frontier: every open decision that does not depend on another answer.
25
+ - **`research`** a question to answer, not code to keep. The brief is the question plus what "answered" looks like.
26
+ - **`quick-build`** — the objective test (conventions' wording): *a small change AND the flow being changed already exists in the repo to read*. Missing either half — no existing flow, or not actually small — means it is not quick-build; familiarity with the kind of app doesn't count.
27
+ - **`full-plan`** — big or new ground: a new subsystem, a restructuring, a brand-new flow.
24
28
 
25
- - Number the questions. Give each a **recommended answer with a one-line reason**, so the user can reply "all recommended" or override by number.
26
- - Stop asking when the bar is met: *a fresh agent could implement each issue without asking anything.* Test every brief against that sentence before calling it done.
27
- - Do not re-ask what the material or an earlier round already settled.
29
+ In doubt between two classes, take the heavier one. Re-classification after this point belongs to `dev-plan`'s one-way ratchet never silently downgrade.
28
30
 
29
- ## The angles, in order
31
+ ## The interview
30
32
 
31
- Work the design the way a joint product-and-tech review would; each round's answers feed the next:
33
+ Ask in rounds with your harness's question tool (no tool available → documented defaults marked `TODO confirm`, and say so). Each round covers the current frontier: every open decision that doesn't depend on another answer. Number the questions; give each a **recommended answer with a one-line reason** so the operator can reply "all recommended"; never re-ask what the material or an earlier round already settled. A vague or self-contradicting answer gets pushback with concrete options — simple words, a mermaid or ASCII sketch when a picture beats prose — never silent absorption. Stop when the bar is met: *a fresh agent could act on each issue without asking anything.*
32
34
 
33
- 1. **Product** — who this is for, the observable outcome, what's in and out of scope now, how it splits into slices or phases, priority.
34
- 2. **Behavior** — primary and alternate flows, rules, permissions, validations, edge and failure cases; for UI, the states, components, and copy.
35
- 3. **Technical** — only the choices that are genuinely the user's: approach trade-offs, data and interface implications, integrations, migration; recommend one and say why. When the project versions releases (dev.md `changelog:` knob), settle the intended version impact (patch/minor/major) here — the brief records it and dev-implement's changelog entry starts from it. Routine implementation stays the implementer's.
36
- 4. **Quality and risk** — what proves it works (test cases, acceptance), what earns the `risky` label, what should stop a dark run beyond the standing stop-list.
35
+ The angles, in order product (who, observable outcome, in/out of scope, slices, priority) → behavior (flows, rules, permissions, edge and failure cases; UI states and copy) → technical (only choices genuinely the operator's, each with a recommendation, checked against `dev-architect`; settle the version impact where the project versions releases) → quality and risk (what proves it works, what earns `risky`, what stops a dark run). Deep approach trade-offs beyond the operator's choices belong to `dev-plan`, not this interview.
37
36
 
38
- These are the brief template's sections in interview form — a question exists only where reading the material, the codebase, and sensible defaults cannot fill a section.
37
+ **Bug variant** (`fix:` issues): reproduction steps — or the artifacts needed to obtain them (logs, HAR, recording) are a required brief section, and the brief names `dev-debug` as the implement path. A bug that can't be reproduced yet becomes a `research` issue first.
39
38
 
40
- ## Slicing
39
+ ## Slicing and hierarchy
41
40
 
42
- - One issue = one outcome that fits one agent session, sliced vertically (a thin working path through the stack beats a layer at a time).
43
- - Blockers use native issue dependencies (blocked-by); phases use milestones; hierarchy uses parent/sub-issues. Labels never duplicate these.
44
- - A large feature gets a parent issue holding the map and child issues holding the work. **Only child issues ever get `ready`**a parent brief is context, not an executable task, and an agent must never pick it up whole.
45
- - Deliberately deferred work ("someday, not now") lives in the parent's out-of-scope section, not as its own issue icebox issues clutter the tracker. Create a tracking issue for it only when the user asks.
41
+ - One issue = one outcome that fits one agent session, sliced vertically. Blockers use native dependencies; phases use milestones; parents use native sub-issues.
42
+ - Deliberately deferred work ("someday, not now") lives in the parent's out-of-scope section, never as its own issue — icebox issues clutter the tracker; a tracking issue exists only on the operator's ask.
43
+ - **Epics:** a multi-deliverable feature gets a parent whose body is a map, never a task `Destination` (one or two lines every session orients to) · `Decisions so far` (one-line gists linking closed children) · `Not clear yet` (in-scope questions you cannot yet state precisely the test is whether the question can be phrased sharply now, not answered now; don't pre-slice fog) · `Out of scope` (the tempting adjacent work, named). A mermaid overview when it helps. Each child is classified independently. **Only children ever get `ready`.**
44
+ - Titles carry the type prefix (dev.md `branch:` type list + `research:`) and the native issue type where the org has them issue, branch, and PR always agree.
46
45
 
47
46
  ## The brief
48
47
 
49
- Every issue body follows [brief-template](references/brief-template.md): Outcome · Out of scope · Rules and edge cases · UI states (when there is UI) · Approach and touch points · Tests and acceptance · Risks and stop conditions · Assumptions. Write the sections that apply and delete the ones that don't — an empty "N/A" section is noise, not diligence. Details live inline in the issue; links to docs are supporting material, never a substitute for the brief. Evidence over confidence: touch points name real paths, dependency claims carry their check date, and anything material the grounding could not verify goes in **Assumptions — confirm or correct**, never asserted as fact.
48
+ The issue body follows [brief-template](references/brief-template.md), marker line included. Inline over linked; concrete over abstract; evidence over confidence touch points name real paths, dependency claims carry their check date, and anything unverifiable goes to **Assumptions — confirm or correct**, never asserted. Tests-and-acceptance names the **seams** — the public boundaries tests will live at — because dark mode can't ask later.
49
+
50
+ **Quick-build issues get their plan now:** after the brief has consensus, invoke `dev-plan`'s inline mode in this same conversation and post brief (description) + plan (comment) together — the operator's single approval covers both.
51
+
52
+ Before posting any brief, run `node <path-to-this-skill>/scripts/brief-lint.mjs --file <draft> --scope <class> --json` (add `--fix` for fix:-type briefs — it requires the Reproduction section) — structure gaps block (exit 2), quality smells only warn; fix blocks before the operator ever sees the draft. Inline plans additionally pass `dev-plan`'s plan-lint.
50
53
 
51
54
  ## Labels and approval
52
55
 
53
- - A new issue starts at `needs-operator`. Add `risky` when it touches security, money, user data, or production. (Label names come from dev.md's `labels:` knob; the defaults are used throughout this skill family's prose.)
54
- - Approval is only the user's explicit words — "approved", "go ahead", clearly tied to this issue, in chat or on the issue. Labels, silence, or the passage of time never create approval.
55
- - Record it once: comment `Approved by <user> on <date>: "<their words>"`, then swap `needs-operator` `ready`. That comment is what dev-implement's preflight looks for.
56
- - An issue with an unconfirmed entry in its Assumptions section cannot go `ready` — the recorded approval covers the ledger the user saw, so resolve every entry (confirmed, corrected, or moved to a spike) first.
57
- - An issue that settles a directional decision one that passes the Decisions test in `.vegastack/dev.md` — records it as one comment starting `Decision:`, in the register's line format; dev-ship appends it at merge after naming it in the merge confirmation. A decision that stands regardless of the issue's fate may go into the register immediately on the user's explicit yes in the same conversation — note "recorded" on the comment so dev-ship doesn't append it twice. Choices that fail the test are brief content, never register lines.
58
- - The user edits or corrects a draft apply, and summarize what changed since they last read it.
56
+ - A new issue starts at `needs-operator`, plus its scope label; add `risky` when it touches security, money, user data, or production. (Names come from dev.md's `labels:` knob.)
57
+ - Approval is only the operator's explicit words, clearly tied to the issue. Labels, silence, or time never create approval.
58
+ - Record it as one approval marker comment per conventions — `scope=brief`, or `scope=brief+plan` when the inline plan was posted with it — quoting the operator's words in the operator (username) format. That comment is what preflight verifies.
59
+ - Then flip the state: `research` and `quick-build` `ready`; `full-plan` `needs-plan` (dev-plan takes it from there).
60
+ - An issue with an unresolved Assumptions entry cannot leave `needs-operator`resolve every entry (confirmed, corrected, or moved to a spike) first; the section is deleted once resolved.
61
+ - A directional decision this work settles one passing the Decisions test in dev.md is proposed as one register line on the operator's yes; `dev-ship` records at merge.
62
+ - The operator edits a draft → apply, and summarize what changed since they last read it.
59
63
 
60
64
  ## After approval
61
65
 
62
- An approved issue that later needs a material change flips back to `needs-operator` with one comment naming what changed; the new approval is recorded the same way. Small wording fixes that change no behavior don't reopen anything.
66
+ An approved issue that later needs a material change flips back to `needs-operator` with one comment naming what changed; the new approval is recorded the same way, and the brief's revision marker bumps. Small wording fixes that change no behavior don't reopen anything.
67
+
68
+ End every run with the plain-language summary: what was created or changed, the scope calls made and why, and exactly what awaits the operator's word.
@@ -1,13 +1,21 @@
1
1
  # Issue brief template
2
2
 
3
- The issue body a `ready` issue must have. Write the sections that apply, delete the rest. The test for every section: would a fresh agent have to guess or ask without it?
3
+ The issue body a workable issue must have. Write the sections that apply, delete the rest. The test for every section: would a fresh agent have to guess or ask without it?
4
4
 
5
5
  ```markdown
6
+ <!-- vsk:v1 type=brief rev=1 scope=research|quick-build|full-plan -->
7
+ **Scope:** research | quick-build | full-plan — the announced reason for the call, one line.
8
+
6
9
  ## Outcome
7
10
 
8
11
  What exists when this is done, in observable terms — what the user can do, what the
9
12
  system produces. One paragraph.
10
13
 
14
+ Research issues replace Outcome and the build sections with two headings brief-lint
15
+ expects verbatim in spirit: `## The question` (what this issue resolves) and
16
+ `## What answered looks like` (the evidence that closes it). Risks/stop conditions
17
+ and Assumptions still apply.
18
+
11
19
  ## Out of scope
12
20
 
13
21
  The nearby things this issue deliberately does NOT do. This is what stops scope creep
@@ -18,6 +26,12 @@ in dark mode — name the tempting adjacent work.
18
26
  The behavior that isn't obvious: validations, permissions, limits, empty/error/concurrent
19
27
  cases, what happens on failure. Bullet list, one behavior per line.
20
28
 
29
+ ## Reproduction <!-- fix: issues only -->
30
+
31
+ The exact steps (or attached artifacts — logs, HAR, recording) that demonstrate the
32
+ bug today, and the observed vs expected behavior. A bug without this is a `research`
33
+ issue, not a fix. The implement path is dev-debug.
34
+
21
35
  ## UI states <!-- only when there is UI -->
22
36
 
23
37
  Loading, empty, error, success, disabled. Which design-system components. Copy for
@@ -26,19 +40,18 @@ user-facing text. Responsive and keyboard behavior when it matters.
26
40
  ## Approach and touch points
27
41
 
28
42
  The chosen technical approach in a few lines: which parts of the codebase change,
29
- new/changed interfaces or schemas, data migrations. Routine choices (file names,
30
- helpers, fixtures) stay the implementer's — don't specify them.
31
- Name the docs and changelog surfaces this change must update (README section, user
32
- docs, the changelog entry's gist).
43
+ new/changed interfaces or schemas, data migrations. Routine choices stay the
44
+ implementer's — don't specify them. Name the docs and changelog surfaces this change
45
+ must update. Task-level detail belongs to the plan (dev-plan), not here.
33
46
  **Version impact:** patch | minor | major, one-line reason — only when the project
34
- versions releases (dev.md `changelog:` knob); dev-implement's changelog entry or
35
- changeset starts from this line.
47
+ versions releases (dev.md `changelog:` knob).
36
48
 
37
49
  ## Tests and acceptance
38
50
 
39
51
  What proves it works: the cases tests must cover (success, boundary, failure,
40
- authorization where relevant) and the commands to run. Acceptance = the Outcome plus
41
- these passing.
52
+ authorization where relevant), the commands to run, and the **seams** — the public
53
+ boundaries tests live at (dark mode can't negotiate seams later; they're settled
54
+ here). Acceptance = the Outcome plus these passing.
42
55
 
43
56
  ## Risks and stop conditions
44
57
 
@@ -48,9 +61,10 @@ through — beyond the standing stop-list in .vegastack/dev.md.
48
61
  ## Assumptions — confirm or correct
49
62
 
50
63
  Anything material the grounding investigation could not verify, one per line, each
51
- awaiting the user's confirm/correct. The issue cannot go `ready` while one is
52
- unconfirmed. Verified facts never appear here — they live in their section with
53
- their evidence. Delete the section once every entry is resolved.
64
+ awaiting the operator's confirm/correct. The issue cannot leave needs-operator while
65
+ one is unconfirmed. Verified facts never appear here — they live in their section
66
+ with their evidence. Delete the whole section once every entry is resolved (its
67
+ presence alone blocks preflight).
54
68
  ```
55
69
 
56
70
  ## Writing rules
@@ -59,4 +73,5 @@ their evidence. Delete the section once every entry is resolved.
59
73
  - Concrete over abstract: "rejects amounts over 10,000 with error E402" beats "validates input".
60
74
  - Evidence over confidence: touch points name real file paths; a dependency capability claim carries the doc check and its date; what couldn't be verified goes to Assumptions, never stated as fact.
61
75
  - The brief binds the agent, so ambiguity is a bug in the brief — if two readings exist, the interview wasn't done.
76
+ - Post-approval edits follow the revision-marker rule in dev-setup's `references/conventions.md` (heading `(v2)`, marker `rev=2`, a `Revisions:` line).
62
77
  - A `Decision:` comment exists only for a choice that passes the Decisions test in `.vegastack/dev.md` — feature requests and implementation details never qualify; they are brief content, not register lines.
@@ -0,0 +1,93 @@
1
+ # Workflow conventions
2
+
3
+ The single spec for the artifacts every dev-family skill reads and writes. One home per rule: skills cite this file, never restate it. Everything here is harness-neutral.
4
+
5
+ ## Comment metadata markers
6
+
7
+ Every workflow-generated issue comment opens with an invisible HTML marker followed by a human heading:
8
+
9
+ ```markdown
10
+ <!-- vsk:v1 type=<type> rev=<n> [key=value ...] -->
11
+ ## <Human title> (v<n>)
12
+ ```
13
+
14
+ | type | required keys | instances |
15
+ |---|---|---|
16
+ | `approval` | `scope=<brief\|brief+plan\|plan>` | one per approval event |
17
+ | `plan` | `rev` | one, edited in place |
18
+ | `ledger` | `branch` | one, edited in place |
19
+ | `evidence` | `rev branch sha` | one, edited in place |
20
+ | `review` | `round sha agent=<claude\|codex> verdict=<clean\|needs-fixes>` | one per review cycle, rounds appended inside |
21
+ | `decision` | — | one per decision proposal |
22
+ | `handback` | — | one per stop event |
23
+
24
+ `rev=<n>` and the matching `(v<n>)` heading suffix appear only on revisable artifacts — the brief (issue description), `plan`, and `evidence` — starting at `rev=1`/`(v1)`. Single-event comments (`approval`, `decision`, `handback`) and the `ledger` carry neither. Scripts and agents locate comments strictly by marker, never by heading text. A comment without its marker does not count as the artifact — there is no legacy fallback.
25
+
26
+ ## Operator identity
27
+
28
+ Every human reference in every artifact — approvals, revisions, decisions, changelog attributions, review adjudications — is written `operator (<github-username>)`:
29
+
30
+ - Approval: `Approved by operator (<username>) on DD-MM-YYYY: "<their words>"`
31
+ - Register line: `- DD-MM-YYYY operator (<username>) — <decision>`
32
+
33
+ ## Revision markers
34
+
35
+ Any artifact edited after its first approval: the heading gains `(v2)`, the marker gains `rev=2`, and a `Revisions:` line is appended at the bottom — `v2 — DD-MM-YYYY: <what changed>, per operator (<username>) correction`. Existing revision lines are never rewritten.
36
+
37
+ ## Scope classes
38
+
39
+ Set at intake, applied as a label, announced with its reason (operator can override):
40
+
41
+ - **`research`** — a question to answer; throwaway code allowed, never merged. No branch/PR/changelog; findings + recommendation are the evidence comment.
42
+ - **`quick-build`** — small change and the flow being changed already exists in the repo to read. Brief (description) + plan (comment) are drafted in the same conversation; **one approval covers both**; then straight to `ready`.
43
+ - **`full-plan`** — big or new ground. Brief approval → `needs-plan` → a separate, fresh-grounded planning session posts the plan → `needs-operator` → "plan approved" → `ready`. Multi-deliverable work becomes an epic; each sub-issue is classified independently.
44
+
45
+ Scope calls are revisited through the one-way ratchet, whose rules and mechanics live in the `dev-plan` skill — the one home for upgrade/downgrade behavior.
46
+
47
+ ## Labels
48
+
49
+ State — exactly one per issue (creation colors live in dev-setup's labels row, their one home):
50
+
51
+ | label | meaning |
52
+ |---|---|
53
+ | `needs-operator` | waiting on the operator: a question, a brief or plan to approve, a proposal |
54
+ | `needs-plan` | brief approved; waiting for the planning stage (full-plan only) |
55
+ | `ready` | fully approved — an agent may start |
56
+ | `working` | claimed, in progress; the ledger comment shows live progress |
57
+ | `for-operator` | done — evidence posted, awaiting operator review |
58
+
59
+ Modifiers (may coexist with the state label): `risky` · scope `research` / `quick-build` / `full-plan` · `epic` (map parents, only where the org has no native Epic issue type).
60
+
61
+ ## Titles, types, hierarchy
62
+
63
+ - **Title prefixes** on issues, branches, and PRs identically: dev.md's `branch:` knob type list (that knob stays the list's one home) plus `research:` for research issues. PR title = issue title.
64
+ - **Native issue types** where the org defines them: Feature (feat) · Bug (fix) · Task (docs/chore/refactor/research) · Epic for parents (label fallback otherwise).
65
+ - **Hierarchy:** epic parent = map only (Destination · Decisions so far as one-line gists · Not clear yet · Out of scope), children attached as native sub-issues; issues = the unit of work (brief in description, own approvals/branch/PR/evidence); tasks = checkboxes **in the plan comment only**. Blockers use native issue dependencies; phases use milestones. Only issues — never epics — get `ready`. GitHub caps issue bodies and comments at ~65,536 characters; what a plan nearing that cap means is the `dev-plan` ratchet's call.
66
+
67
+ ## The ledger
68
+
69
+ Maintained by the implement session as one comment, edited in place:
70
+
71
+ ```markdown
72
+ <!-- vsk:v1 type=ledger branch=<branch> -->
73
+ ## Ledger — <branch>
74
+ - Task <N>: complete (commits <base7>..<head7>[, review clean | K parked])
75
+ - Task <N>: fix round <R>/3 (<X> addressed, <Y> open — <one-liners>; commits <a>..<b>)
76
+ - Ruling: <what> — <why> — cost if wrong: <cost>
77
+ - Task <N>: parked — <finding> — Ruling: <why the code stands>
78
+ - Deferred minor: <one-liner>
79
+ ```
80
+
81
+ **Resume protocol:** a fresh, compacted, or (operator-handed) takeover session reads, in order: the brief → the plan comment → the ledger → `git log` on the branch — **nothing else**. Tasks with a `complete` line are DONE, never re-executed; a task whose last line is a fix round resumes at the next round. After compaction, trust the ledger and `git log` over recollection. Every `Ruling:` line surfaces in the evidence comment — a ruling that dies with the session was a decision made in secret.
82
+
83
+ ## `.vegastack/.tmp/` workspace
84
+
85
+ All transitory artifacts — subagent reports, review packages, plan drafts, extracted diffs — live at `.vegastack/.tmp/<issue-number>-<title-slug>/` (pre-issue intake drafts, which have no number yet: `.vegastack/.tmp/intake-<slug>/`), kept out of git by a self-ignoring `.gitignore` (`printf '*\n' > .vegastack/.tmp/.gitignore`, created on first use). Subagents write full reports to files there and return only short status — a dead subagent's findings survive on disk, and the primary session never holds full reports in context. The workspace lives in the working tree (never under `.git/`, which harnesses protect from writes).
86
+
87
+ ## Verification gate
88
+
89
+ Before claiming any status: **IDENTIFY** the command that proves the claim → **RUN** it fresh and complete → **READ** the full output and exit code → only then claim, with the evidence. "Should pass", a previous run, or a subagent's say-so are never evidence. Guard scripts follow the same doctrine: machine-verifiable facts **block** (exit 2 with the reason); regex or judgment heuristics only **warn** — no AI inference inside guards, and an unverifiable state fails closed.
90
+
91
+ ## Plain-language collaboration
92
+
93
+ Every skill run ends with a simple-language summary: what happened, which paths were taken — cross-agent invocations announced at trigger time AND summarized at the end — and what is worth the operator double-checking. Use mermaid or ASCII diagrams in issues wherever a picture beats prose. A vague or self-contradicting operator answer gets pushback with concrete options, never silent absorption.