@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.
- package/README.md +8 -3
- package/dist/index.js +5 -5
- package/package.json +1 -1
- package/skill/dev-architect/SKILL.md +96 -0
- package/skill/dev-architect/agents/openai.yaml +4 -0
- package/skill/dev-architect/references/ai-agents.md +89 -0
- package/skill/dev-architect/references/conventions.md +93 -0
- package/skill/{architect → dev-architect}/references/data.md +43 -44
- package/skill/dev-architect/references/infra.md +98 -0
- package/skill/dev-architect/references/mobile.md +75 -0
- package/skill/{architect → dev-architect}/references/pinned-facts.md +17 -16
- package/skill/dev-architect/references/principles.md +117 -0
- package/skill/{architect → dev-architect}/references/security.md +37 -44
- package/skill/dev-architect/references/stack.md +38 -0
- package/skill/dev-architect/references/web.md +102 -0
- package/skill/{architect → dev-architect}/refresh/REFRESH.md +8 -6
- package/skill/{architect → dev-architect}/refresh/sources.json +5 -10
- package/skill/dev-chronicle/SKILL.md +45 -0
- package/skill/dev-chronicle/agents/openai.yaml +4 -0
- package/skill/dev-chronicle/references/conventions.md +93 -0
- package/skill/dev-chronicle/refresh/REFRESH.md +3 -0
- package/skill/dev-chronicle/refresh/sources.json +6 -0
- package/skill/dev-debug/SKILL.md +43 -0
- package/skill/dev-debug/agents/openai.yaml +4 -0
- package/skill/dev-debug/references/conventions.md +93 -0
- package/skill/dev-debug/references/loop-ladder.md +20 -0
- package/skill/dev-debug/refresh/REFRESH.md +3 -0
- package/skill/dev-debug/refresh/sources.json +6 -0
- package/skill/dev-implement/SKILL.md +41 -36
- package/skill/dev-implement/references/conventions.md +93 -0
- package/skill/dev-implement/references/ledger-and-resume.md +27 -0
- package/skill/dev-implement/scripts/evidence-check.mjs +57 -0
- package/skill/dev-implement/scripts/lib/gh.mjs +93 -0
- package/skill/dev-implement/scripts/preflight.mjs +101 -0
- package/skill/dev-intake/SKILL.md +39 -33
- package/skill/dev-intake/references/brief-template.md +27 -12
- package/skill/dev-intake/references/conventions.md +93 -0
- package/skill/dev-intake/scripts/brief-lint.mjs +87 -0
- package/skill/dev-plan/SKILL.md +53 -0
- package/skill/dev-plan/agents/openai.yaml +4 -0
- package/skill/dev-plan/references/conventions.md +93 -0
- package/skill/dev-plan/references/plan-format.md +54 -0
- package/skill/dev-plan/refresh/REFRESH.md +3 -0
- package/skill/dev-plan/refresh/sources.json +6 -0
- package/skill/dev-plan/scripts/plan-lint.mjs +86 -0
- package/skill/dev-review/SKILL.md +69 -0
- package/skill/dev-review/agents/openai.yaml +4 -0
- package/skill/dev-review/assets/review-known-patterns.md.template +30 -0
- package/skill/dev-review/references/conventions.md +93 -0
- package/skill/dev-review/references/cross-agent.md +39 -0
- package/skill/dev-review/references/dispatch-prompts.md +104 -0
- package/skill/dev-review/references/security-axis.md +33 -0
- package/skill/dev-review/refresh/REFRESH.md +3 -0
- package/skill/dev-review/refresh/sources.json +6 -0
- package/skill/dev-setup/SKILL.md +14 -9
- package/skill/dev-setup/assets/agents-section.md.template +2 -2
- package/skill/dev-setup/assets/dev-profile.md.template +23 -5
- package/skill/dev-setup/references/conventions.md +93 -0
- package/skill/dev-setup/references/stack-playbooks.md +1 -1
- package/skill/dev-ship/SKILL.md +14 -7
- package/skill/dev-ship/references/conventions.md +93 -0
- package/skill/dev-ship/references/runbook.md +1 -1
- package/skill/dev-ship/scripts/ship-gate.mjs +213 -0
- package/skill/dev-status/SKILL.md +45 -0
- package/skill/dev-status/agents/openai.yaml +4 -0
- package/skill/dev-status/references/conventions.md +93 -0
- package/skill/dev-status/refresh/REFRESH.md +3 -0
- package/skill/dev-status/refresh/sources.json +6 -0
- package/skill/dev-status/scripts/status.mjs +152 -0
- package/skill/skill-maintainer/references/release-ops.md +3 -3
- package/skill/skillify/SKILL.md +1 -1
- package/skill/skillify/references/eval-playbook.md +6 -0
- package/skill-integrity.json +93 -33
- package/skill/architect/SKILL.md +0 -68
- package/skill/architect/agents/openai.yaml +0 -4
- package/skill/architect/assets/adr-template.md +0 -21
- package/skill/architect/assets/arch-template.md +0 -20
- package/skill/architect/references/advisory.md +0 -102
- package/skill/architect/references/ai-agents.md +0 -95
- package/skill/architect/references/infra.md +0 -128
- package/skill/architect/references/mobile.md +0 -78
- package/skill/architect/references/principles.md +0 -91
- package/skill/architect/references/project-profile.md +0 -37
- package/skill/architect/references/stack.md +0 -38
- 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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
17
|
-
- **Verify dependencies.** Any library, service, or API capability the approach leans on gets checked against current official docs
|
|
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
|
|
19
|
-
- **Triage every unknown** into exactly three bins: *findable* → find it now, yourself; *only-the-
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
31
|
+
## The interview
|
|
30
32
|
|
|
31
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
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
|
-
|
|
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
|
|
54
|
-
- Approval is only the
|
|
55
|
-
- Record it
|
|
56
|
-
-
|
|
57
|
-
- An issue
|
|
58
|
-
-
|
|
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
|
|
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
|
|
30
|
-
|
|
31
|
-
|
|
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)
|
|
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)
|
|
41
|
-
|
|
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
|
|
52
|
-
unconfirmed. Verified facts never appear here — they live in their section
|
|
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.
|