@vegastack/skills 0.14.0 → 0.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -26,6 +26,8 @@ Facts are your job; decisions are the user's. Gather these silently and present
26
26
  | existing labels | `gh label list` |
27
27
  | native issue types | `gh api orgs/<org>/issue-types` — an `Epic` type routes parents to it; absent endpoint or type → the `epic` label fallback ([conventions](references/conventions.md)) |
28
28
  | Codex CLI (cross-agent review) | `command -v codex` — absent → record the gap in dev.md `## Environments` and recommend installing it |
29
+ | agent skills in the repo | a directory holding skill folders, flat or one group deep — each folder carrying its own entry point — drafts the `skill-scan:` knob at that path; none found drafts `none`. Declare it **once**: a second `skill-scan:` line with a different value, even in a prose example, makes the profile ambiguous and the guard refuses. Where the project builds a flattened bundle the knob names the **built** directory, because unpackaged test fixtures are deliberately adversarial and score higher than anything that ships |
30
+ | SkillSpector (skill scanning) | `command -v skillspector` — absent while `skill-scan:` is set → record it in `## Environments` with `uv tool install git+https://github.com/NVIDIA/skillspector.git`; the guard refuses rather than skipping, so this is a real gap |
29
31
 
30
32
  Not a git repo, or no origin remote → this is a **greenfield run, not an error**: follow the greenfield playbook in [stack-playbooks](references/stack-playbooks.md) — interview for the intended stack, offer `git init` and `gh repo create` each on its own yes, and render dev.md from the chosen playbook's conventions with TODO lines where machinery doesn't exist yet. A declined remote skips labels and records the TODO plainly.
31
33
 
@@ -47,6 +49,7 @@ Ask with your harness's question tool — AskUserQuestion in Claude Code, `reque
47
49
  - Playbook matched → show the drafted `## Ship` runbook (each step `auto:`, `ask:`, or `guard:` — every `guard:` line carries its runnable command inline), the `changelog:` convention, and the `release:` knob (per-merge or on-request) for confirmation; a keep-a-changelog convention with no CHANGELOG.md yet → offer to seed the skeleton; no machinery → "Ship: merge only" and move on
48
50
  - Guards drafted → offer to write their CI backstop steps into the project's workflow files (the local `guard:` lines run without CI); each file on the user's yes — release guards only, never general CI
49
51
  - Environments or run commands detected → confirm the drafted `## Environments` and `## Verify` bullets
52
+ - Agent skills detected → confirm the drafted `skill-scan:` root, the `## Verify` bullet running the guard (preceded by the build command when the root is a build output), and a blocking `guard:` line in `## Ship` before the publish step — the published artifact is what the world installs. Skills detected but the operator declines the scan → `skill-scan: none`, said plainly, not silently omitted
50
53
  - Evidence repo (`ui-evidence: playwright`) → default is the owner's **shared** `<owner>/dev-review-evidence`; if it doesn't exist, offer `gh repo create <owner>/dev-review-evidence --private --add-readme` + the layout/retention README — created once, every project points at it. An org naming policy that rejects the name → pick the closest compliant name with the user and record it in the knob (the name is a knob value, not a contract)
51
54
  - App architecture detected → confirm the drafted `## Architecture` (hosting, stage, and kind are what detection usually can't fill — ask those); nothing detected → delete the section, the `stack:` line is enough
52
55
  - A legacy `.vegastack/arch.md` exists → fold its knob lines into `## Architecture`, offer each dated `notes:` line to the decision register on the user's yes, then offer to delete arch.md
@@ -14,6 +14,7 @@ ui-evidence: playwright # playwright | none
14
14
  evidence-repo: {{owner}}/dev-review-evidence # shared across projects; this project's folder = repo name; delete the line when ui-evidence is none
15
15
  gates: 3 # 3 = approve/PR/merge · 2 = approve + one "ship it" · 1 = direct-to-main, ship word merges locally and pushes, no PR
16
16
  tests: required # required | logic-only
17
+ skill-scan: none # ONE line only — directory holding the agent skills to scan (the BUILT one where a bundle is generated) | none. dev-review's guard reads this and refuses if a second line gives a different value
17
18
  merge: squash
18
19
  branch: <type>/<issue>-<slug> # type: feat | fix | docs | chore | refactor — the only place this list lives
19
20
  labels: needs-operator needs-plan ready working for-operator risky research quick-build full-plan epic # epic label marks map parents only where the org has no native Epic issue type
@@ -67,7 +68,7 @@ mobile: {{no | flutter (separate repo)}}
67
68
 
68
69
  Record a decision only when it is directional — it steers work beyond this issue: a real alternative was rejected; it constrains work not yet written; and no dev.md line, lint rule, or guard can enforce it instead (if one can, write the rule). Feature requests, one-off fixes, and routine implementation choices never qualify. Every entry needs the user's explicit yes. One line in the register (`decisions:` knob), append-only, no other metadata:
69
70
 
70
- - DD-MM-YYYY operator (github-username) — the decision
71
+ - DD-MM-YYYY (github-username) — the decision
71
72
 
72
73
  ## Stop and ask
73
74
 
@@ -25,14 +25,14 @@ Every workflow-generated issue comment opens with an invisible HTML marker follo
25
25
 
26
26
  ## Operator identity
27
27
 
28
- Every human reference in every artifact — approvals, revisions, decisions, changelog attributions, review adjudications — is written `operator (<github-username>)`:
28
+ Every human reference in every artifact — approvals, revisions, decisions, changelog attributions, review adjudications — names the operator by their GitHub username in parentheses, with no title before it — `(<github-username>)`:
29
29
 
30
- - Approval: `Approved by operator (<username>) on DD-MM-YYYY: "<their words>"`
31
- - Register line: `- DD-MM-YYYY operator (<username>) — <decision>`
30
+ - Approval: `Approved by (<username>) on DD-MM-YYYY: "<their words>"`
31
+ - Register line: `- DD-MM-YYYY (<username>) — <decision>`
32
32
 
33
33
  ## Revision markers
34
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.
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 (<username>) correction`. Existing revision lines are never rewritten.
36
36
 
37
37
  ## Scope classes
38
38
 
@@ -25,14 +25,14 @@ Every workflow-generated issue comment opens with an invisible HTML marker follo
25
25
 
26
26
  ## Operator identity
27
27
 
28
- Every human reference in every artifact — approvals, revisions, decisions, changelog attributions, review adjudications — is written `operator (<github-username>)`:
28
+ Every human reference in every artifact — approvals, revisions, decisions, changelog attributions, review adjudications — names the operator by their GitHub username in parentheses, with no title before it — `(<github-username>)`:
29
29
 
30
- - Approval: `Approved by operator (<username>) on DD-MM-YYYY: "<their words>"`
31
- - Register line: `- DD-MM-YYYY operator (<username>) — <decision>`
30
+ - Approval: `Approved by (<username>) on DD-MM-YYYY: "<their words>"`
31
+ - Register line: `- DD-MM-YYYY (<username>) — <decision>`
32
32
 
33
33
  ## Revision markers
34
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.
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 (<username>) correction`. Existing revision lines are never rewritten.
36
36
 
37
37
  ## Scope classes
38
38
 
@@ -25,14 +25,14 @@ Every workflow-generated issue comment opens with an invisible HTML marker follo
25
25
 
26
26
  ## Operator identity
27
27
 
28
- Every human reference in every artifact — approvals, revisions, decisions, changelog attributions, review adjudications — is written `operator (<github-username>)`:
28
+ Every human reference in every artifact — approvals, revisions, decisions, changelog attributions, review adjudications — names the operator by their GitHub username in parentheses, with no title before it — `(<github-username>)`:
29
29
 
30
- - Approval: `Approved by operator (<username>) on DD-MM-YYYY: "<their words>"`
31
- - Register line: `- DD-MM-YYYY operator (<username>) — <decision>`
30
+ - Approval: `Approved by (<username>) on DD-MM-YYYY: "<their words>"`
31
+ - Register line: `- DD-MM-YYYY (<username>) — <decision>`
32
32
 
33
33
  ## Revision markers
34
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.
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 (<username>) correction`. Existing revision lines are never rewritten.
36
36
 
37
37
  ## Scope classes
38
38
 
@@ -24,8 +24,8 @@ profile carries a schema version to validate against.
24
24
  ## Release flow (tag-driven)
25
25
 
26
26
  1. Every PR that changes released behavior lands with a changeset — a `.changeset/<slug>.md` written directly, since the `changeset` add prompt is interactive (`bunx changeset version` at release time is the only CLI use) — whose bump follows the table above and whose shape follows dev-implement's changelog rule.
27
- 2. Maintainer, at release time: `bunx changeset version` (applies changesets to `packages/cli/package.json` and the changelog), then `bun install` so any dependency changes riding along reach the lockfile, commit. That install does **not** update the workspace's own version inside `bun.lock`: measured on the bun the root `packageManager` line pins, the recorded version is left unchanged by a plain install, by `--force`, and even by `--lockfile-only`, so it sits at an older number indefinitely. `bun install --frozen-lockfile`, which CI and the release workflow both run, passes with it, and nothing in this repo reads it: `packages/cli/package.json` is the single release identity. Never hand-edit the lockfile to "correct" it. The release record is `packages/cli/CHANGELOG.md`, changesets-written — never by hand; the root `CHANGELOG.md` is the frozen pre-0.3.0 record pointing there.
28
- 3. Tag the release commit `v<version>`, push the tag.
27
+ 2. Maintainer, at release time: `bunx changeset version` (applies changesets to `packages/cli/package.json` and the changelog), then `bun install` so any dependency changes riding along reach the lockfile, commit on a `chore/release-<version>` branch and open its PR — main is branch-protected with no admin exemption, so the bump reaches main by merge and never by direct push. That install does **not** update the workspace's own version inside `bun.lock`: measured on the bun the root `packageManager` line pins, the recorded version is left unchanged by a plain install, by `--force`, and even by `--lockfile-only`, so it sits at an older number indefinitely. `bun install --frozen-lockfile`, which CI and the release workflow both run, passes with it, and nothing in this repo reads it: `packages/cli/package.json` is the single release identity. Never hand-edit the lockfile to "correct" it. The release record is `packages/cli/CHANGELOG.md`, changesets-written — never by hand; the root `CHANGELOG.md` is the frozen pre-0.3.0 record pointing there.
28
+ 3. Merge the release PR on the operator's word, pull main, then tag that merged commit `v<version>` and push the tag. Tags are not branch-protected, so the tag push is unaffected.
29
29
  4. The release workflow runs on the tag: `bun run check`, tag↔version guard, `npm publish` via trusted publishing (OIDC, token-free, provenance by default; idempotently skipped if already on the registry), SBOM, GitHub release. Never pass `--provenance` explicitly — it conflicts with trusted-publishing config.
30
30
 
31
31
  Contributors do not bump versions in PRs; releases are maintainer-driven.
@@ -34,7 +34,7 @@ Contributors do not bump versions in PRs; releases are maintainer-driven.
34
34
 
35
35
  `npm unpublish` is limited to 72 hours and breaks pinned consumers — it is not the rollback mechanism.
36
36
 
37
- 1. **Roll forward:** revert the offending commits on `main`, changeset, tag, release the previous known-good content as a **new patch version**.
37
+ 1. **Roll forward:** revert the offending commits through a PR onto `main` (protection applies to reverts too), changeset, tag, release the previous known-good content as a **new patch version**.
38
38
  2. **Deprecate the bad version:** `npm deprecate @vegastack/skills@<bad> "Broken — use <new>"`.
39
39
  3. Unpublish only if the bad version leaked secrets or is actively harmful, still within 72 hours, and always *in addition to* steps 1–2, never instead.
40
40
 
@@ -84,6 +84,48 @@ One authored tree, three harnesses. Every skill in `skills/` follows all seven:
84
84
 
85
85
  Repo enforcement: `packages/cli/scripts/validate-skill.mjs` (run by `bun run check`) accepts exactly the spec six (`name`, `description`, `license`, `compatibility`, `allowed-tools`, `metadata`) and rejects everything else, enforces the full name grammar (lowercase-letter start, no consecutive hyphens, ≤64 chars, name equals the skill directory name), and rejects empty or over-length descriptions and angle brackets. Policy (rule 1) is stricter than the validator; the minimal two keys are the default.
86
86
 
87
+ ## Skill scanning and the suppression baseline
88
+
89
+ Every skill this repo ships is scanned by [NVIDIA SkillSpector](https://github.com/NVIDIA/skillspector) through `dev-review`'s `scripts/skill-scan.mjs`, at the Verify gate before a push and again as a blocking `guard:` before publish. The guard blocks on any unsuppressed **HIGH or CRITICAL** finding and ignores the aggregate risk score: a skills repo documents the very mechanics the scanner matches on, so the score reflects our subject matter more than our risk.
90
+
91
+ Suppressions live in `.vegastack/skillspector-baseline.json` — a real SkillSpector baseline, passed with `--baseline`, so nothing here forks the scanner's own matching and upstream changes to it arrive for free. The rules this repo adds on top:
92
+
93
+ - **A suppression needs the operator's word.** It is a security decision on the record, the same as an operator dismissal appended to `.vegastack/review-known-patterns.md` — never a step taken to get a guard green.
94
+ - **Matchers must be LITERAL — the guard rejects `*`, `?`, `[` and `]` outright.** This is not a style preference: a rule of `{"id": "*"}` silenced all 39 findings while the guard reported "pass with warnings", and a first fix that rejected `*` and `**` was bypassed by `?*` on the next attempt. Matching wildcard *spellings* is an arms race; "name the thing" is the only mechanically checkable form of "scope a rule as narrowly as its cause". Two files means two rules, which reads better in a diff anyway. (Consequence worth knowing: a filename that literally contains `[` or `]` cannot be suppressed by a rule — the scanner would glob-interpret it too. Use a fingerprint.)
95
+ - **Scope a rule as narrowly as its cause.** `{"id": "P2"}` alone silences prompt injection across every skill forever; `{"id": "P2", "path": "references/conventions.md"}` silences one documented protocol in one file. A rule with no `path` needs a reason that explains why the whole repo is the cause.
96
+ - **`path` and `file` are the same matcher, `id` and `rule_id` likewise** — SkillSpector resolves `path = raw.get("path") or raw.get("file")`. Both spellings are accepted and both go through the literal check.
97
+ - **A baseline carrying `fingerprints:` must also set `scanner_version`** — the scanner refuses it otherwise, once per skill, and the guard catches that up front so one misconfiguration does not surface as a dozen unreadable-report failures.
98
+ - **Every `reason` carries a "Still flag if:" clause**, naming the condition that makes the pattern a real finding again. The guard blocks on a missing, empty, scanner-placeholder, or clause-less reason — this is enforced, not trusted.
99
+ - **`fingerprints:` are for one-off accepted findings only.** They are content-hashed, so any edit to the surrounding file re-triggers them — which is their re-trigger condition, and why they need a real reason but not the clause. A structural pattern suppressed by fingerprint will reappear at the worst possible moment; use a rule.
100
+ - **Never `--use-shipped-baseline`.** A baseline discovered inside a scanned skill was written by whoever wrote that skill.
101
+ - **The scan reads the built bundle** (`packages/cli/skill/`), not `skills/`: the authored tree carries unpackaged `tests/` fixtures that are deliberately adversarial and score higher than anything that ships. Build before scanning.
102
+ - **The semantic pass (`--llm`) is advisory and never a gate.** It is non-deterministic, and a run whose LLM calls partially fail reports a higher score than a clean one.
103
+ ### Triaging a scan finding — the decision order
104
+
105
+ Work down this list; stop at the first that fits. Every acceptance needs the operator's word and a `reason` carrying its "Still flag if:" clause.
106
+
107
+ 1. **Is it real?** Trace it before anything else. A real finding gets fixed, not accepted. Two on this repo turned out real and were fixed at source — a detection row whose wording introduced an `AE1`, and a template placeholder that shipped a literal `<group>`.
108
+ 2. **Is the cause one file, shared by many skills?** Use a **rule** with a literal `id` + `path`. One cause, one entry, however many skills report it — the `references/conventions.md` marker protocol produces ten findings from one rule.
109
+ 3. **Is it a one-off in specific content?** Use a **fingerprint**. Content-hashed, so it re-triggers the moment that content changes. Beware: the scanner's own `skillspector baseline` **deduplicates** what it emits, so a group of occurrences can come back as fewer hashes than the matcher needs — check the count actually drops before trusting it.
110
+ 4. **Is it a completeness signal rather than a behaviour?** Use a **`coverage:`** entry, naming the skill, the file, and the file's `sha256`. This is ours, not the scanner's — SkillSpector's baseline suppresses findings only, and has no way to accept "I could not finish reading this". `AE1` belongs here despite arriving as a HIGH finding: its own text is *"Referenced artifact was not completely inspected."* Two things to know when writing one:
111
+ - **It is content-bound and expires.** Edit the accepted file and the acceptance stops applying, and the skill blocks until you re-adjudicate. That is the point: an acceptance that outlives the file it describes is a reason with nothing behind it. Refresh the digest **after** the final `bun run build`, since the bundle is what gets scanned — and note that editing the guard's own script invalidates its own entry.
112
+ - **Say what it hides.** A coverage entry accepts every `AE1` on that file and the degradation of every analyzer for that skill. Name the reason code and the number of degraded analyzers in the reason, so the next reader can tell whether the cause is still the one that was accepted.
113
+
114
+ 5. **Write the "Still flag if:" clause so it can actually fire.** A clause naming something already true is decoration. Check it against the file before committing: "still flag if it gains a shell invocation" is worthless on a file that already shells out. Good clauses name a *change* — a different reason code, more degraded analyzers, a rule id the entry does not cover.
115
+ 6. **None of the above?** Park it with a written ruling. Do not widen an entry to make a guard green — that is the failure this whole system exists to prevent.
116
+
117
+ ### Known SkillSpector behaviours on this repo
118
+
119
+ Recorded so nobody re-derives them. All traced in issue 62.
120
+
121
+ - **A JavaScript template literal in assignment position degrades the static analyzers for the whole skill.** ``const at = `${a.file}:${a.line}`;`` trips the bounded shell parser, which reads the backticks as command substitution and exhausts its span limit. Verified experimentally: string concatenation scans clean, and forty template literals *inside function calls* do not degrade at all. It is the shape, not the volume. Any skill shipping a script with this idiom needs a `coverage:` entry — the alternative is banning ordinary JavaScript from skills.
122
+ - **`AE1` on a `SKILL.md` usually means its references, not its behaviour** — either repo-root paths that cannot resolve relative to a skill directory (correct for a repo-scoped meta-skill), or a file it links to that the parser could not finish. Check which before accepting.
123
+ - **`P2` fires on every HTML comment**, because a hidden instruction is a genuine injection vector. This repo uses HTML comments as machine-readable markers — `vsk:v1`, `vsk-dev:start`, `<!-- source: … -->`, `<!-- mirrored -->` — so the finding is the documentation of a mechanism, not an instance of one. Scope the rule to the file, never to the id alone.
124
+ - **`RA1` on a `refresh/REFRESH.md` is correct about the pattern.** The refresh contract genuinely instructs an agent to rewrite the skill's own files. It is acceptable only because the runner is the only writer, it edits marked sections, checksums are runner-only, and every change lands as a reviewed PR — write those bounds into the reason.
125
+ - **The aggregate risk score is not a gate.** It is inflated by unresolvable-path artifacts in meta-content and deflated by unrelated suppressions.
126
+
127
+ - **A skill authored elsewhere is scanned the same way, before it reaches an agent** — `--root <path to the skill>`. This repo does not yet redistribute anyone else's skill; when it does, the curation, audit, upstream-drift, release, and retirement rules are this skill's to own, and a curated skill is never hand-edited locally (a local fix is overwritten by the next upstream sync and forks us from its author). Scanning a third-party skill you are evaluating works today and needs none of that.
128
+
87
129
  ## UNVERIFIED register
88
130
 
89
131
  Do not assert any of these; if one becomes load-bearing, verify against the live source first and move it into a marked sentence:
@@ -222,20 +222,26 @@ export async function scaffoldSkill({ name, dir, group = null, write = false, no
222
222
  // Every refusal belongs in this pre-flight. wireReadme runs after the tree is renamed into
223
223
  // place and the packaging entry written, so anything discovered there would leave a half-wired
224
224
  // skill on disk while reporting a refusal - or, worse, report success with no row at all.
225
- // When a README exists, its row target must be resolvable BEFORE the tree is staged, so a
226
- // refusal writes nothing. A wholly absent README or packaging.json keeps the documented
227
- // degrade-to-`skipped:` contract (skillify's README, and the bare-repo test) - tightening that
228
- // is a behaviour change of its own, tracked separately.
225
+ // Both wiring targets a scaffolded skill cannot do without must therefore be resolvable BEFORE
226
+ // the tree is staged: an absent one is a refusal, not a `skipped:` status, because a skill with
227
+ // no README row or no packaging entry is exactly the state structure.mjs check blocks. Only
228
+ // `.changeset/` still degrades to `skipped:` - a missing changeset breaks no check.
229
229
  const readmePath = join(repoRoot, 'README.md')
230
- if ((await entryAt(readmePath))?.isFile()) {
231
- const lines = (await readFile(readmePath, 'utf8')).split('\n')
232
- const rowTarget = findRowInsertion(lines, group, groupHeading)
233
- if (rowTarget?.missingSection) {
234
- throw new Error(`README.md has no "### ${groupHeading}" section for group "${group}" - create it with structure.mjs create-group`)
235
- }
236
- if (!rowTarget) {
237
- throw new Error(`README.md has no ${group ? `table under "### ${groupHeading}"` : 'ungrouped Skills table'} to add a row to - every skill needs its row, so refusing rather than scaffolding a skill the structure check would block`)
238
- }
230
+ if (!(await entryAt(readmePath))?.isFile()) {
231
+ throw new Error(`README.md not found at ${readmePath} - every skill needs its Skills-table row, so refusing rather than scaffolding a skill the structure check would block`)
232
+ }
233
+ const lines = (await readFile(readmePath, 'utf8')).split('\n')
234
+ const rowTarget = findRowInsertion(lines, group, groupHeading)
235
+ if (rowTarget?.missingSection) {
236
+ throw new Error(`README.md has no "### ${groupHeading}" section for group "${group}" - create it with structure.mjs create-group`)
237
+ }
238
+ if (!rowTarget) {
239
+ throw new Error(`README.md has no ${group ? `table under "### ${groupHeading}"` : 'ungrouped Skills table'} to add a row to - every skill needs its row, so refusing rather than scaffolding a skill the structure check would block`)
240
+ }
241
+
242
+ const packagingPath = join(repoRoot, 'packages/cli/packaging.json')
243
+ if (!(await entryAt(packagingPath))?.isFile()) {
244
+ throw new Error(`packages/cli/packaging.json not found at ${packagingPath} - every skill needs its packaging entry, so refusing rather than scaffolding a skill the structure check would block`)
239
245
  }
240
246
 
241
247
  // The generated test imports the repo validator by relative path, so its depth follows the
@@ -8,7 +8,7 @@
8
8
  "SKILL.md": "74150dde2d3c83598769a4c9f8cd295a7496d9eb9a5e920a29cba8464eb58128",
9
9
  "agents/openai.yaml": "99023b056d5c568ff3acc059e5bb7a4e6cfa5261cd0d35a525407f9e159de562",
10
10
  "references/ai-agents.md": "565e5d480f7e342adf43f9b864ab4cb66b7e513f0ea676de66909fe0ccd95988",
11
- "references/conventions.md": "815f5189daff1b71b3251b7a57de183a4a387fcdedbd5875e673d5bd3de398fc",
11
+ "references/conventions.md": "95bf916cc11f95f3d5eefcb34db4fbc05d88ae1c8f08869800dfa417f8da17ed",
12
12
  "references/data.md": "781d3ae7d3bca0b269c123a10013226f3878503dd1224ee526edd102bfc270f0",
13
13
  "references/infra.md": "a6d07c5e9ea67788edac7b80742a5588a1f019e387163bfdab531314fb54d009",
14
14
  "references/mobile.md": "b6ee481df810f3fd5466487848287ceeb33ac98bf6db0bc2d65c4d6fa397284f",
@@ -25,9 +25,9 @@
25
25
  "group": "dev-skills",
26
26
  "repoOnly": false,
27
27
  "files": {
28
- "SKILL.md": "23c6266758726d6435de38cb0cc142a94a0b55f2329f7ab6404e42fa5d0dee3a",
28
+ "SKILL.md": "2bd58c19cdb5a55d7fefdfcd1748054aba403ff9d5161030e36a65f3b2e69b05",
29
29
  "agents/openai.yaml": "765b12e17b7fce88c53ca0fae735bf0efceb843cc3703b91bc1801ab5cac06b4",
30
- "references/conventions.md": "815f5189daff1b71b3251b7a57de183a4a387fcdedbd5875e673d5bd3de398fc",
30
+ "references/conventions.md": "95bf916cc11f95f3d5eefcb34db4fbc05d88ae1c8f08869800dfa417f8da17ed",
31
31
  "refresh/REFRESH.md": "760e66642eec426cd5ab2319613e817adf5bbd7b64c8eaa22dd13497351bf9c1",
32
32
  "refresh/sources.json": "a7ba2340964dc70410626087686145b5790a0e763a18ef2c4d9aa37e950f2e04"
33
33
  }
@@ -38,7 +38,7 @@
38
38
  "files": {
39
39
  "SKILL.md": "38ba9e67c00925f4e4738be333dc398218008df929fcf17b61398966ce4deee1",
40
40
  "agents/openai.yaml": "4aa52b5c620b0bf4de7f1609867956ce762d83dc4297ab5670a68c206ae63075",
41
- "references/conventions.md": "815f5189daff1b71b3251b7a57de183a4a387fcdedbd5875e673d5bd3de398fc",
41
+ "references/conventions.md": "95bf916cc11f95f3d5eefcb34db4fbc05d88ae1c8f08869800dfa417f8da17ed",
42
42
  "references/loop-ladder.md": "ddcb45ec2241bc5dc25936348074cdcc8f9af848e90b363351a7faf97007c256",
43
43
  "refresh/REFRESH.md": "70816e44c8d6a5d11b73eb40762e6d8931724517e0b4c138eb07bc8e91b45008",
44
44
  "refresh/sources.json": "a7ba2340964dc70410626087686145b5790a0e763a18ef2c4d9aa37e950f2e04"
@@ -48,9 +48,9 @@
48
48
  "group": "dev-skills",
49
49
  "repoOnly": false,
50
50
  "files": {
51
- "SKILL.md": "724f6bc83467c28dc61a45161d3ffba7fecef2712eff3333bdf40d762731db44",
51
+ "SKILL.md": "f79f4d312f6c03ffdcf2e2fd44169e48520445900389e2d469c0946811be3801",
52
52
  "agents/openai.yaml": "1abab383deca54d32749fd9156f9a6211fe96e02e0166dc8a16ff8459ac31b74",
53
- "references/conventions.md": "815f5189daff1b71b3251b7a57de183a4a387fcdedbd5875e673d5bd3de398fc",
53
+ "references/conventions.md": "95bf916cc11f95f3d5eefcb34db4fbc05d88ae1c8f08869800dfa417f8da17ed",
54
54
  "references/ledger-and-resume.md": "5e3deae2af67735940564e04adcbc23c0c0dc86da2f6c80d68b8c1207c8f5900",
55
55
  "refresh/REFRESH.md": "7b854109d897b78b3055bf1ab89517afdca65c12eb65a4d009141e3ee11cf58f",
56
56
  "refresh/sources.json": "7bd883e5b3512e236a909ad6ff20c97f3555785867c31fd728256c7c2c514c74",
@@ -63,10 +63,10 @@
63
63
  "group": "dev-skills",
64
64
  "repoOnly": false,
65
65
  "files": {
66
- "SKILL.md": "4754383297822d3f6e0ad8a391ac76499d83c74f424b90b928199d6c2649dc71",
66
+ "SKILL.md": "08126d2c631051bf92d400dd678b8f75af1ee7905b1c389e030e4ca435f2c548",
67
67
  "agents/openai.yaml": "5473d2d3efffc518c07dfa8e6788c6535a5054ceca696119c5856ad265ef5581",
68
68
  "references/brief-template.md": "906c6b805f9737755f4d4b34fd16d4296924b95039379ea86bc59973949d9823",
69
- "references/conventions.md": "815f5189daff1b71b3251b7a57de183a4a387fcdedbd5875e673d5bd3de398fc",
69
+ "references/conventions.md": "95bf916cc11f95f3d5eefcb34db4fbc05d88ae1c8f08869800dfa417f8da17ed",
70
70
  "refresh/REFRESH.md": "bb5265cee98c243c775c3e5fbc59de4b84ab54e828f3290d7c19e47291d66f71",
71
71
  "refresh/sources.json": "7bd883e5b3512e236a909ad6ff20c97f3555785867c31fd728256c7c2c514c74",
72
72
  "scripts/brief-lint.mjs": "7202def7c3a8b0049e67d60602a4c652d3c99f5fa1711080fd46b94ff4dc3684"
@@ -78,7 +78,7 @@
78
78
  "files": {
79
79
  "SKILL.md": "eb2ce1542b1769fa6e7d9dc7be9fc9c84df8b353ded16e39e1e578ee372c1aca",
80
80
  "agents/openai.yaml": "4b9ccc9870b4eafb73c1bc4492a0b5a530097bbcbae11dbf3235160f4f05587b",
81
- "references/conventions.md": "815f5189daff1b71b3251b7a57de183a4a387fcdedbd5875e673d5bd3de398fc",
81
+ "references/conventions.md": "95bf916cc11f95f3d5eefcb34db4fbc05d88ae1c8f08869800dfa417f8da17ed",
82
82
  "references/plan-format.md": "a915acce2fc447e685077756aeb94fdc3f84139800703034987b8409971493db",
83
83
  "refresh/REFRESH.md": "e22830102db9cf7c6db1e8fea9e73b7845b77e59da0d44e186a6b26d6dc9ebe1",
84
84
  "refresh/sources.json": "a7ba2340964dc70410626087686145b5790a0e763a18ef2c4d9aa37e950f2e04",
@@ -89,26 +89,27 @@
89
89
  "group": "dev-skills",
90
90
  "repoOnly": false,
91
91
  "files": {
92
- "SKILL.md": "be32aa737cfd3309f7413407470ebffeedf6284f0f98cef6ae185c478c896c26",
92
+ "SKILL.md": "561e0232d20fc7e6893b38a4c3d7deb41862d60d7b545a98d3ce7ba1d3c7ac06",
93
93
  "agents/openai.yaml": "3f35d3dc60f179d4ac2526997c4d10173ba3018d06f0dbe77e209ce2978fa702",
94
- "assets/review-known-patterns.md.template": "2fe7dbcc4d0eeac542e7624111130265b2bb4f08806f20dbd2087842cbb22b5c",
95
- "references/conventions.md": "815f5189daff1b71b3251b7a57de183a4a387fcdedbd5875e673d5bd3de398fc",
94
+ "assets/review-known-patterns.md.template": "7747b807ed18c4c8bf8acdc6481b2f7f27914d932d757c7243a32a41a18d32c5",
95
+ "references/conventions.md": "95bf916cc11f95f3d5eefcb34db4fbc05d88ae1c8f08869800dfa417f8da17ed",
96
96
  "references/cross-agent.md": "3541715d0563703373ea3d93582119b80356d1cbdee19ce17f958c0f7c914884",
97
- "references/dispatch-prompts.md": "259e8f468cedb961359bad6d080515d4682a9e5aafd268a192d51454d2842c50",
98
- "references/security-axis.md": "a152d4500ec8ba21b07be130a529156485737921625c91ab50d90a187b5f8b1f",
97
+ "references/dispatch-prompts.md": "cb8134a7b6ff9e20ec4db02d0af2f8767f71bf13fa9a21b28b7a586c2747ec1d",
98
+ "references/security-axis.md": "e207071fc48f761f2deb24c73ef4f5ebcf28c130264dab7c3061ae6c0eee6543",
99
99
  "refresh/REFRESH.md": "242c1efe630327abe12bf9db4c4085aaf05b262a4dbd885b12b0f29cdd4a285d",
100
- "refresh/sources.json": "a7ba2340964dc70410626087686145b5790a0e763a18ef2c4d9aa37e950f2e04"
100
+ "refresh/sources.json": "a7ba2340964dc70410626087686145b5790a0e763a18ef2c4d9aa37e950f2e04",
101
+ "scripts/skill-scan.mjs": "2d74ebd63ffd66cca5208b5dab2984ace47ef4e832e188f6811ff7c2e303095d"
101
102
  }
102
103
  },
103
104
  "dev-setup": {
104
105
  "group": "dev-skills",
105
106
  "repoOnly": false,
106
107
  "files": {
107
- "SKILL.md": "d8eb7741983998f56ff8aff52f66ec3887b7fd055c26cc232e1ff41da6fab7c1",
108
+ "SKILL.md": "4b29049b8ce165fb03f554c8784e095cbe97cef16752b57b86321352a1017ce7",
108
109
  "agents/openai.yaml": "be790c04fdf910e71642cfadf1a7c07c217bf7fad18581610feb4c31a79651f2",
109
110
  "assets/agents-section.md.template": "6c9591d50f73e1e05e78c8969c7836767432cf32487af7205b2cb9f4a410440e",
110
- "assets/dev-profile.md.template": "45b2a90fc7aee39e7b975151f1281787d6dd4d3b7d5f9df5b8f282d020a1d7a9",
111
- "references/conventions.md": "815f5189daff1b71b3251b7a57de183a4a387fcdedbd5875e673d5bd3de398fc",
111
+ "assets/dev-profile.md.template": "26e244b488d181e23ff4b49addd9ab519c8f5d43e2d914638033648a7ca5bd3a",
112
+ "references/conventions.md": "95bf916cc11f95f3d5eefcb34db4fbc05d88ae1c8f08869800dfa417f8da17ed",
112
113
  "references/harness-facts.md": "2be1d81f6a616d40dc865aaeefaf53c61bc13ade4ba1de8fb406c520bf15be40",
113
114
  "references/stack-playbooks.md": "8f457c3d0f96e3c99d745b04332590fdf8af53a9694541181d9c878ae0718ea2",
114
115
  "refresh/REFRESH.md": "debda6ab96e899dd7e38309f714e9d65a3fbc53fd8ca68b8156f1348226c87b9",
@@ -121,7 +122,7 @@
121
122
  "files": {
122
123
  "SKILL.md": "aa3bd8b0a1ac076309190f2008896f24ebe1216352872ff428c1b88b55c06e65",
123
124
  "agents/openai.yaml": "8f18cfd505131557eb4c9f7b7f54e9069f787be4c162403fc30253eed49a06ea",
124
- "references/conventions.md": "815f5189daff1b71b3251b7a57de183a4a387fcdedbd5875e673d5bd3de398fc",
125
+ "references/conventions.md": "95bf916cc11f95f3d5eefcb34db4fbc05d88ae1c8f08869800dfa417f8da17ed",
125
126
  "references/runbook.md": "5cbf3f89b2fcad1a2873f729b6c1a027566344d5dffcb799ed1d039e76b3e679",
126
127
  "refresh/REFRESH.md": "06894b54fcbde12d3b5804523f20d5544ba1a18bb5e36960caa4f98454c6203e",
127
128
  "refresh/sources.json": "7bd883e5b3512e236a909ad6ff20c97f3555785867c31fd728256c7c2c514c74",
@@ -134,7 +135,7 @@
134
135
  "files": {
135
136
  "SKILL.md": "56415c2f69bb1a2fcb488b9846a20e632eb902b05c5b2b58ae9206d3eaffd77b",
136
137
  "agents/openai.yaml": "72435947f5afef0c8a2c170e987b14fe6057b174318c16b6b538ae8d129791fb",
137
- "references/conventions.md": "815f5189daff1b71b3251b7a57de183a4a387fcdedbd5875e673d5bd3de398fc",
138
+ "references/conventions.md": "95bf916cc11f95f3d5eefcb34db4fbc05d88ae1c8f08869800dfa417f8da17ed",
138
139
  "refresh/REFRESH.md": "52aee9bae64d8342e127704d1db282e43ed57c101148727bf10172d6cb975bfa",
139
140
  "refresh/sources.json": "a7ba2340964dc70410626087686145b5790a0e763a18ef2c4d9aa37e950f2e04",
140
141
  "scripts/status.mjs": "bc56d0b5d996676cfccb752d9d77d0e9e7d64932741cd39d6a503e9761fbe34d"
@@ -146,8 +147,8 @@
146
147
  "files": {
147
148
  "SKILL.md": "1733d2f1fa756cbb37c74ecee0d48ddd9abf31155c4dd72eba10af31c33d88ec",
148
149
  "agents/openai.yaml": "0b89d4e6416cf20b448f5322f3d7433cfde333d2b4a05b42ed53db3759701fb4",
149
- "references/release-ops.md": "b5df1922b34daf7751c332c019a0ea770a48283aaa2e25f83c9851bef47999b1",
150
- "references/standards.md": "0dd7fcb6e2f0dd3aae7167227d7ec085481bc629aa027af35d48e5d0f7b9df86",
150
+ "references/release-ops.md": "d213f66976e24942560d611582d27409f8ba4392886b4663d7dfbc7d395ef2ef",
151
+ "references/standards.md": "b44122822a320a305728ee023ed8e3140bf87aaaef400a43d45b778e53ad2c02",
151
152
  "refresh/REFRESH.md": "d3ba44be2c264b849d8a815111c049e782720428d5d0c5cea23998b05e50d58f",
152
153
  "refresh/sources.json": "4977152381d53555196ac676f95e61b4eaa301309a17560da5cda722010eb80f"
153
154
  }
@@ -169,7 +170,7 @@
169
170
  "references/eval-playbook.md": "1f463dfea8d69b7022712776794369892643aa020186fe3a3707c493a6c2d4e9",
170
171
  "refresh/REFRESH.md": "695f3283b27c14accf4095137898ce1f6dc40749483c5a5705e80aa9693f08c2",
171
172
  "refresh/sources.json": "e554e80c72c16dc70587361804db9e0cf2716c128820b2612d5983a009b2b242",
172
- "scripts/scaffold-skill.mjs": "8bc3314f800fcff0bf5f797fdd82424ceb16a45ac03c4ee0eebcc416dfc41b97"
173
+ "scripts/scaffold-skill.mjs": "849370bd152e488c66753882928cdb18db356f21468647c8e0a51ee58a385183"
173
174
  }
174
175
  }
175
176
  }