@vegastack/skills 0.1.0 → 0.2.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 (66) hide show
  1. package/README.md +27 -7
  2. package/dist/index.js +191 -95
  3. package/package.json +16 -5
  4. package/skill/{vegastack-arch-guardian → arch-guardian}/SKILL.md +1 -1
  5. package/skill/arch-guardian/agents/openai.yaml +4 -0
  6. package/skill/{vegastack-arch-guardian → arch-guardian}/assets/architecture-profile.schema.json +1 -1
  7. package/skill/{vegastack-arch-guardian → arch-guardian}/refresh/REFRESH.md +1 -1
  8. package/skill/{vegastack-arch-guardian → arch-guardian}/refresh/sources.json +10 -10
  9. package/skill/{vegastack-arch-guardian → arch-guardian}/scripts/refresh-evidence.mjs +4 -1
  10. package/skill/skill-maintainer/SKILL.md +79 -0
  11. package/skill/skill-maintainer/agents/openai.yaml +4 -0
  12. package/skill/skill-maintainer/references/release-ops.md +63 -0
  13. package/skill/skill-maintainer/references/standards.md +92 -0
  14. package/skill/skill-maintainer/refresh/REFRESH.md +40 -0
  15. package/skill/skill-maintainer/refresh/sources.json +103 -0
  16. package/skill/skillify/SKILL.md +154 -0
  17. package/skill/skillify/agents/openai.yaml +4 -0
  18. package/skill/skillify/assets/templates/README.md.template +26 -0
  19. package/skill/skillify/assets/templates/REFRESH.md.template +21 -0
  20. package/skill/skillify/assets/templates/SKILL.md.template +26 -0
  21. package/skill/skillify/assets/templates/openai.yaml.template +4 -0
  22. package/skill/skillify/assets/templates/skill.test.ts.template +40 -0
  23. package/skill/skillify/assets/templates/sources.json.template +6 -0
  24. package/skill/skillify/references/authoring.md +72 -0
  25. package/skill/skillify/references/eval-playbook.md +62 -0
  26. package/skill/skillify/refresh/REFRESH.md +24 -0
  27. package/skill/skillify/refresh/sources.json +6 -0
  28. package/skill/skillify/scripts/scaffold-skill.mjs +138 -0
  29. package/skill-integrity.json +75 -45
  30. package/skill/vegastack-arch-guardian/agents/openai.yaml +0 -4
  31. /package/skill/{vegastack-arch-guardian → arch-guardian}/assets/adr-template.md +0 -0
  32. /package/skill/{vegastack-arch-guardian → arch-guardian}/assets/answers-example.json +0 -0
  33. /package/skill/{vegastack-arch-guardian → arch-guardian}/assets/architecture-profile.json +0 -0
  34. /package/skill/{vegastack-arch-guardian → arch-guardian}/assets/deployment-review-template.md +0 -0
  35. /package/skill/{vegastack-arch-guardian → arch-guardian}/assets/service-design-template.md +0 -0
  36. /package/skill/{vegastack-arch-guardian → arch-guardian}/assets/threat-model-template.md +0 -0
  37. /package/skill/{vegastack-arch-guardian → arch-guardian}/references/architecture/agent-product.md +0 -0
  38. /package/skill/{vegastack-arch-guardian → arch-guardian}/references/architecture/ai-cost.md +0 -0
  39. /package/skill/{vegastack-arch-guardian → arch-guardian}/references/architecture/ai-data-boundaries.md +0 -0
  40. /package/skill/{vegastack-arch-guardian → arch-guardian}/references/architecture/ai-evals.md +0 -0
  41. /package/skill/{vegastack-arch-guardian → arch-guardian}/references/architecture/connectors-sandbox.md +0 -0
  42. /package/skill/{vegastack-arch-guardian → arch-guardian}/references/architecture/data-memory.md +0 -0
  43. /package/skill/{vegastack-arch-guardian → arch-guardian}/references/architecture/delivery-operations.md +0 -0
  44. /package/skill/{vegastack-arch-guardian → arch-guardian}/references/architecture/durable-execution.md +0 -0
  45. /package/skill/{vegastack-arch-guardian → arch-guardian}/references/architecture/flutter.md +0 -0
  46. /package/skill/{vegastack-arch-guardian → arch-guardian}/references/architecture/foundation.md +0 -0
  47. /package/skill/{vegastack-arch-guardian → arch-guardian}/references/architecture/hosting-reliability.md +0 -0
  48. /package/skill/{vegastack-arch-guardian → arch-guardian}/references/architecture/identity-tenancy.md +0 -0
  49. /package/skill/{vegastack-arch-guardian → arch-guardian}/references/architecture/model-lifecycle.md +0 -0
  50. /package/skill/{vegastack-arch-guardian → arch-guardian}/references/architecture/models-observability.md +0 -0
  51. /package/skill/{vegastack-arch-guardian → arch-guardian}/references/architecture/realtime-channels.md +0 -0
  52. /package/skill/{vegastack-arch-guardian → arch-guardian}/references/architecture/security-privacy.md +0 -0
  53. /package/skill/{vegastack-arch-guardian → arch-guardian}/references/architecture/topology-monorepo.md +0 -0
  54. /package/skill/{vegastack-arch-guardian → arch-guardian}/references/architecture/web.md +0 -0
  55. /package/skill/{vegastack-arch-guardian → arch-guardian}/references/control-catalog.json +0 -0
  56. /package/skill/{vegastack-arch-guardian → arch-guardian}/references/foundation-compatibility.json +0 -0
  57. /package/skill/{vegastack-arch-guardian → arch-guardian}/references/golden-patterns.md +0 -0
  58. /package/skill/{vegastack-arch-guardian → arch-guardian}/references/profile-governance.md +0 -0
  59. /package/skill/{vegastack-arch-guardian → arch-guardian}/references/rule-model.json +0 -0
  60. /package/skill/{vegastack-arch-guardian → arch-guardian}/references/workflows.md +0 -0
  61. /package/skill/{vegastack-arch-guardian → arch-guardian}/scripts/architecture-check.mjs +0 -0
  62. /package/skill/{vegastack-arch-guardian → arch-guardian}/scripts/lib.mjs +0 -0
  63. /package/skill/{vegastack-arch-guardian → arch-guardian}/scripts/profile-tool.mjs +0 -0
  64. /package/skill/{vegastack-arch-guardian → arch-guardian}/scripts/schema-validate.mjs +0 -0
  65. /package/skill/{vegastack-arch-guardian → arch-guardian}/scripts/validate-profile.mjs +0 -0
  66. /package/skill/{vegastack-arch-guardian → arch-guardian}/scripts/verify-corpus.mjs +0 -0
@@ -0,0 +1,154 @@
1
+ ---
2
+ name: skillify
3
+ description: Repo-local skill factory and auditor for the vegastack-skills monorepo. Use when asked to "skillify this", "make this a skill", "turn this workflow into a skill", or scaffold a new skill under skills/; when asked to "audit this skill", "is this skill complete", "check skill completeness", or score a skill against the repo contract; when deciding whether a workflow, script, or prompt should become a skill at all; when a skill description under- or over-triggers and needs tuning; or when a skill in this repo is missing tests, a README, a refresh contract, behavioral eval evidence, or repo wiring. Only for skills inside this repository, not for authoring skills in other projects or installing third-party skills.
4
+ ---
5
+
6
+ # Skillify
7
+
8
+ Turn a raw workflow into a properly-skilled unit of this monorepo, or audit an existing `skills/<name>/` tree against the full repo contract (CONTRIBUTING.md, "Adding a new skill"). Skillify is repo-only: it creates and scores skills in this repository, not anywhere else. Deep wiring/release mechanics belong to `skill-maintainer`; cross-reference it rather than restating it.
9
+
10
+ ## The completeness checklist
11
+
12
+ Score every item pass / fail / N/A. N/A requires a one-line rationale; N/A without one is a fail.
13
+
14
+ 1. **SKILL.md spec-compliant** — frontmatter is exactly `name` + `description`; name matches the directory and the grammar (starts with a lowercase letter, `[a-z0-9-]`, no consecutive hyphens, max 64); description max 1024 chars with no angle brackets; body under 500 lines; no harness-specific body syntax. `bun run validate:skill` agrees.
15
+ 2. **Description triggers well** — states triggering conditions only (never the workflow), third person, trigger words front-loaded, per [authoring](references/authoring.md); a should/should-not-trigger query set with near-miss negatives exists at `tests/fixtures/trigger-queries.json`.
16
+ 3. **README walkthrough** — repo-side `README.md`: install, contents table, behavior contract.
17
+ 4. **References routed** — `references/` for on-demand detail with a routing table in SKILL.md; or N/A for a self-contained skill.
18
+ 5. **Scripts deterministic** — dependency-free Node under `scripts/`, `--json` for machine output, documented exit codes, atomic writes and symlink refusal for anything mutating; or N/A.
19
+ 6. **Assets** — templates/schemas/examples under `assets/`; or N/A.
20
+ 7. **Unit tests + fixtures** — `tests/*.test.ts` (bun test) covering every deterministic branch; fixtures under `tests/fixtures/`.
21
+ 8. **Consistency test** — a test asserting prose, scripts, templates, and registry agree: relative links resolve, documented flags exist, template inventory matches the scaffolder.
22
+ 9. **Behavioral eval evidence** — with-skill vs baseline subagent runs on 2–3 realistic prompts per the [eval playbook](references/eval-playbook.md); summary in the PR body; unresolved gaps in a KNOWN_GAPS section of the skill's README.
23
+ 10. **Refresh contract** — `refresh/sources.json` + `refresh/REFRESH.md` tracking every volatile claim; or an explicit evergreen waiver in REFRESH.md stating why nothing in the skill decays.
24
+ 11. **Codex metadata** — `agents/openai.yaml`.
25
+ 12. **Repo wiring** — sync-skill allowlist entry, root README table row, CHANGELOG entry (`skill-maintainer` owns the detail).
26
+ 13. **Green check** — `bun run check` passes.
27
+
28
+ **Verdict:** all pass → `properly skilled`. At most three misses, none of items 1, 7, or 13 → `close — create: <missing items>`. Otherwise → `needs skillify — run skillify on <target>`. Always report the score as `<passed>/13` plus the verdict.
29
+
30
+ ## Phase 0 — Should this be a skill?
31
+
32
+ Before anything else, check:
33
+
34
+ - Will it be invoked 2+ times? One-off work is not a skill.
35
+ - Is there more than ~20 lines of logic or judgment? Trivial helpers do not need the full contract.
36
+ - Is there a trigger phrase a user would actually say?
37
+
38
+ If any answer is no: it is a script or a doc, not a skill. Stop — do not scaffold, do not write a SKILL.md. Say why and move on.
39
+
40
+ Scope upper bound: **one skill = one capability = one coherent trigger family.** If the target spans distinct intents users would invoke separately ("run the build" / "roll back the deploy" / "notify the team" are three intents), do not build one skill covering them all. Propose the split and ask which target to skillify first.
41
+
42
+ ## Phase 1 — Audit
43
+
44
+ For an existing skill, score the checklist against the actual tree and stop with the verdict:
45
+
46
+ ```
47
+ Skill: <name> Path: skills/<name>/
48
+ Score: <passed>/13 Verdict: <verdict>
49
+ Missing: <item>: <one-line evidence> ...
50
+ ```
51
+
52
+ For a new skill the audit is trivially 0/13 — proceed. When the request was only "audit" / "is this complete", deliver the verdict and the shortest path to `properly skilled`; do not start editing unasked.
53
+
54
+ ## Phase 2 — Elicit requirements
55
+
56
+ Interview before writing (skip questions the conversation already answers):
57
+
58
+ - **Triggers:** what exact phrases should invoke this? What near-miss requests should NOT? (These become the query set.)
59
+ - **Output:** what does done look like — files, report shape, side effects?
60
+ - **Edge cases:** empty input, missing config, offline, partial state?
61
+ - **Existing behavior:** is there code/prose to absorb? What did its author correct over time?
62
+
63
+ Then classify every factual claim the skill will make:
64
+
65
+ | Class | Meaning | Where it lives |
66
+ |---|---|---|
67
+ | Durable | versionless principle | references prose; refresh never edits |
68
+ | Mechanism-coupled | durable intent through a vendor-named mechanism | marked `<!-- source: SOURCE-ID -->`; edited only with registry evidence |
69
+ | Volatile | version pins, limits, model names, URLs | `refresh/sources.json` entries or refresh-tracked files only |
70
+
71
+ Every mechanism-coupled or volatile claim needs a registry source — or the skill declares an evergreen waiver. No unclassified claims ship.
72
+
73
+ ## Phase 3 — Scaffold and write
74
+
75
+ Scaffold the contract tree (dry-run first; `--write` to create; `--json` for machine output):
76
+
77
+ ```sh
78
+ node <skill-dir>/scripts/scaffold-skill.mjs <name> --dir <repo-root>
79
+ node <skill-dir>/scripts/scaffold-skill.mjs <name> --dir <repo-root> --write
80
+ ```
81
+
82
+ The scaffolder validates the name grammar, refuses existing directories and symlinks, stages in a temp sibling then renames, and prints the manual wiring steps. Then write, in this order:
83
+
84
+ 1. *Description + trigger query set* — engineer the description per [authoring](references/authoring.md); write 8–10 should-trigger and 8–10 near-miss should-not-trigger queries into `tests/fixtures/trigger-queries.json`.
85
+ 2. *SKILL.md body* — workflow, one excellent example, routing table. Respect the token budgets in [authoring](references/authoring.md).
86
+ 3. *References* — detail that only some invocations need.
87
+ 4. *Scripts* — only for work that is deterministic and repeated (criteria in [authoring](references/authoring.md)).
88
+ 5. *Draft tests* — but do not treat them as the quality bar yet; that is Phase 4's job.
89
+
90
+ ## Phase 4 — Behavioral eval — the quality gate
91
+
92
+ **Tests lock in behavior. If the behavior is mediocre, tests lock in mediocrity.** Prove quality first, then let tests cement it.
93
+
94
+ Follow the [eval playbook](references/eval-playbook.md): for each of 2–3 realistic prompts, launch two subagents in the same turn — one told to follow the new SKILL.md, one baseline without it — and compare outputs against the skill's claimed value. This is a procedure you execute with your own subagents, never a custom eval harness or tooling.
95
+
96
+ Iterate at most 3 cycles: eval → apply the top improvements to the skill → re-eval. Pass, or ship with a KNOWN_GAPS section (format in the playbook). If the baseline already matches the with-skill output, the skill is not earning its tokens — cut it or narrow it.
97
+
98
+ ## Phase 5 — Lock in
99
+
100
+ Now that quality is proven:
101
+
102
+ 1. Finalize unit tests and fixtures locking in the eval-proven behavior; add the consistency test (item 8).
103
+ 2. Write `refresh/sources.json` + `refresh/REFRESH.md` from the Phase 2 claim classification — or the evergreen waiver.
104
+ 3. Finish `README.md` and `agents/openai.yaml`.
105
+ 4. Wire the repo: sync-skill allowlist, root README row, CHANGELOG entry — as printed by the scaffolder; `skill-maintainer` documents each step in depth.
106
+
107
+ ## Phase 6 — Verify
108
+
109
+ ```sh
110
+ node packages/cli/scripts/validate-skill.mjs skills/<name>
111
+ bun test skills/<name>
112
+ bun run check
113
+ ```
114
+
115
+ Re-score the checklist and report `<passed>/13` with the verdict. Anything below `properly skilled` ships only with named gaps.
116
+
117
+ ## Worked example: skillifying a "release-notes" workflow
118
+
119
+ ```
120
+ Phase 0: yes — run at every release, ~80 lines of conventions, trigger "draft the release notes"
121
+ Phase 1: 0/13 (new)
122
+ Phase 2: triggers "draft/write the release notes", NOT "write a changelog entry for this PR";
123
+ output = CHANGELOG section + npm summary; claims: changeset flow = durable,
124
+ npm publish mechanics = mechanism-coupled (source NPM-PUBLISH), CLI version pin = volatile
125
+ Phase 3: scaffold-skill.mjs release-notes --dir . --write; description + 18 trigger queries;
126
+ body + references/format.md; no scripts (judgment-heavy, N/A with rationale)
127
+ Phase 4: eval cycle 1 — baseline subagent invents section headings, with-skill misses breaking-change
128
+ callouts → add callout contract to SKILL.md; cycle 2 — with-skill clearly better, baseline still
129
+ wrong shape → pass
130
+ Phase 5: tests lock the section contract; sources.json gets NPM-PUBLISH; wiring done
131
+ Phase 6: bun run check green; 13/13 → properly skilled
132
+ ```
133
+
134
+ ## Anti-patterns
135
+
136
+ - Writing lock-in tests before the behavioral eval — locks in mediocrity.
137
+ - A description that summarizes the workflow — agents follow the description and skip the body.
138
+ - Skipping the baseline run because "the output looks fine" — that is not evidence.
139
+ - Eval without a fix cycle — vanity metrics.
140
+ - Obviously-irrelevant negatives in the trigger query set — near-misses or nothing.
141
+ - Version pins or model names in SKILL.md — volatile facts live in refresh-tracked locations.
142
+ - Multi-intent skills spanning unrelated triggers — split them.
143
+ - Two skills answering the same trigger — merge or kill one.
144
+ - Prose and scripts disagreeing about flags or paths — that is what the consistency test catches.
145
+ - Building eval tooling — evals are instructions you run with subagents, not code you write.
146
+
147
+ ## Routing
148
+
149
+ | Need | Read |
150
+ |---|---|
151
+ | description engineering, numeric limits, token budgets, script-vs-instructions, claim classes | [authoring](references/authoring.md) |
152
+ | eval method, pass criteria, trigger-query doctrine, cycle protocol, KNOWN_GAPS, model guidance | [eval playbook](references/eval-playbook.md) |
153
+ | the scaffolded starting points | `assets/templates/` |
154
+ | skillify's own freshness stance | [refresh/REFRESH.md](refresh/REFRESH.md) |
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "VegaStack Skillify"
3
+ short_description: "Create and audit skills for the vegastack-skills repo"
4
+ default_prompt: "Use $skillify to audit or scaffold a skill in skills/ against the full repo contract."
@@ -0,0 +1,26 @@
1
+ # {{name}}
2
+
3
+ TODO: one-paragraph summary for humans and agents browsing the repo. The agent entry point is [SKILL.md](SKILL.md); everything else loads progressively from there.
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ npx @vegastack/skills add {{name}}
9
+ ```
10
+
11
+ ## What's in this skill
12
+
13
+ | Path | Purpose |
14
+ |---|---|
15
+ | [SKILL.md](SKILL.md) | Agent entry point |
16
+ | `references/` | TODO: on-demand detail, or delete this row |
17
+ | `scripts/` | TODO: deterministic dependency-free Node scripts, or delete this row |
18
+ | `assets/` | TODO: templates/schemas/examples, or delete this row |
19
+ | [refresh/sources.json](refresh/sources.json) | Source registry for volatile claims |
20
+ | [refresh/REFRESH.md](refresh/REFRESH.md) | Freshness contract |
21
+ | [agents/openai.yaml](agents/openai.yaml) | Codex interface metadata |
22
+ | `tests/` | Bun tests and fixtures (never packaged) |
23
+
24
+ ## Behavior
25
+
26
+ TODO: what the skill does when invoked, its output contract, and its guardrails.
@@ -0,0 +1,21 @@
1
+ # Refresh contract — {{name}}
2
+
3
+ Instructions for the scheduled refresh agent (and any human running a manual refresh). This file plus `sources.json` is the complete freshness contract for this skill.
4
+
5
+ ## What this skill claims
6
+
7
+ TODO: classify before shipping (see skillify references/authoring.md):
8
+
9
+ - **Durable rules**: versionless principles in this skill's prose. The refresh agent NEVER edits these; if a source change invalidates one, open an issue quoting the evidence.
10
+ - **Mechanism-coupled claims**: sentences marked with a source comment naming a SOURCE-ID from `sources.json`. The agent may propose edits to these marked sentences only, in the same PR as the registry update that evidences the change.
11
+ - **Volatile layer**: `refresh/sources.json` itself (checksums, versions, retrieval times) — the only file the agent edits freely.
12
+
13
+ ## Evergreen waiver
14
+
15
+ TODO: if this skill has NO mechanism-coupled or volatile claims, replace the sources TODO in `sources.json` with this waiver, filled in: "This skill's content is evergreen: it asserts no version pins, vendor mechanism names, numeric vendor limits, or dated facts. Rationale: ... Revisit if a future edit introduces any." Then delete the refresh steps below. Otherwise delete this section.
16
+
17
+ ## How to refresh
18
+
19
+ 1. TODO: deterministic pass (which command, which registry).
20
+ 2. TODO: what may be auto-accepted vs what needs human review.
21
+ 3. One PR per refresh, evidence-linked; refresh branches touch only `refresh/` metadata.
@@ -0,0 +1,26 @@
1
+ ---
2
+ name: {{name}}
3
+ description: TODO - state only the conditions that should load this skill. Third person, trigger phrases in quotes first, symptoms and situations next, one clause naming what this skill is NOT for. Never summarize the workflow. Max 1024 characters, no angle brackets.
4
+ ---
5
+
6
+ # {{name}}
7
+
8
+ TODO: one-paragraph overview - what this skill guarantees and the single trigger family it serves.
9
+
10
+ ## When to use
11
+
12
+ - TODO: concrete situations and user phrasings
13
+ - TODO: when NOT to use - the nearest adjacent intent and where it goes instead
14
+
15
+ ## Workflow
16
+
17
+ 1. TODO
18
+ 2. TODO
19
+
20
+ ## Example
21
+
22
+ TODO: one excellent, realistic example (input and output). One great example beats five mediocre ones.
23
+
24
+ ## Routing
25
+
26
+ TODO: if this skill has references/, add a routing table (Need | Read) here; otherwise delete this section and record item 4 as N-A in the checklist with a rationale.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "{{name}}"
3
+ short_description: "TODO: imperative, under 60 characters"
4
+ default_prompt: "Use ${{name}} to TODO."
@@ -0,0 +1,40 @@
1
+ import { describe, expect, test } from 'bun:test'
2
+ import { existsSync, readFileSync } from 'node:fs'
3
+ import { join, resolve } from 'node:path'
4
+ import { validateSkill } from '../../../packages/cli/scripts/validate-skill.mjs'
5
+
6
+ const skillRoot = resolve(import.meta.dir, '..')
7
+
8
+ describe('{{name}} contract', () => {
9
+ test('SKILL.md passes repo validation', () => {
10
+ const result = validateSkill(skillRoot)
11
+ expect(result.message).toBe('Skill is valid!')
12
+ expect(result.ok).toBe(true)
13
+ })
14
+
15
+ test('frontmatter carries only name and description', () => {
16
+ const content = readFileSync(join(skillRoot, 'SKILL.md'), 'utf8')
17
+ const frontmatter = /^---\n([\s\S]*?)\n---/.exec(content)
18
+ expect(frontmatter).not.toBeNull()
19
+ const keys = (frontmatter as RegExpExecArray)[1]
20
+ .split('\n')
21
+ .filter(line => /^[A-Za-z]/.test(line))
22
+ .map(line => line.split(':')[0])
23
+ expect(keys.sort()).toEqual(['description', 'name'])
24
+ })
25
+
26
+ test('relative markdown links resolve', () => {
27
+ for (const file of ['SKILL.md', 'README.md']) {
28
+ const body = readFileSync(join(skillRoot, file), 'utf8')
29
+ for (const match of body.matchAll(/\]\(([^)#\s]+)\)/g)) {
30
+ const target = match[1]
31
+ if (/^[a-z][a-z0-9+.-]*:/.test(target)) continue
32
+ expect(`${file} -> ${target}: ${existsSync(join(skillRoot, target))}`).toBe(`${file} -> ${target}: true`)
33
+ }
34
+ }
35
+ })
36
+
37
+ // TODO: add unit tests for every deterministic branch of scripts/, plus the
38
+ // consistency test (prose, scripts, templates, and registry agree). Lock in
39
+ // eval-proven behavior only AFTER the behavioral eval passes (skillify Phase 4).
40
+ })
@@ -0,0 +1,6 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "retrievalBaseline": "{{date}}",
4
+ "note": "TODO: add one entry per volatile or mechanism-coupled external claim (see skillify references/authoring.md, claim classification), or record an evergreen waiver in REFRESH.md and keep sources empty.",
5
+ "sources": []
6
+ }
@@ -0,0 +1,72 @@
1
+ # Authoring reference
2
+
3
+ Rules for writing the parts of a skill that determine whether it triggers, how much it costs, and whether it stays true over time.
4
+
5
+ ## Description engineering
6
+
7
+ The description is the primary triggering mechanism: it is always in context, and the agent decides from it alone whether to load the body.
8
+
9
+ - **Triggering conditions only — never the workflow.** A description that summarizes the process becomes a shortcut: agents follow the summary and skip the body. State when to load the skill, not what the skill will do step by step.
10
+ - **Third person.** The text is injected into a system prompt ("Creates and audits...", "Use when..."), never "I can help you...".
11
+ - **Front-load trigger words.** Harness skill lists truncate long descriptions; the first clause must carry the strongest triggers.
12
+ - **Cover the ways users actually ask.** Exact phrases in quotes, symptoms, file types, adjacent phrasings, casual variants. Include the situations where the skill competes with a neighbor and should win.
13
+ - **Name the boundary.** One clause on what the skill is NOT for prevents over-triggering ("Only for skills inside this repository...").
14
+ - **No angle brackets** — the repo validator rejects them.
15
+
16
+ Bad: `Helps with skills.` (no triggers, no boundary)
17
+ Bad: `Audits a skill by scoring 13 checklist items, then scaffolds, evals, and wires it.` (workflow summary — the body will be skipped)
18
+ Good: `Use when asked to "skillify this", "make this a skill", audit a skill's completeness, or decide whether a workflow should become a skill. Only for skills inside this repository.`
19
+
20
+ ## Numeric limits
21
+
22
+ <!-- mirrored: these numbers are volatile and mirrored from the standards sources tracked by the skill-maintainer registry; on drift, fix them there first, then here. -->
23
+
24
+ | Thing | Limit |
25
+ |---|---|
26
+ | `name` | 1–64 chars, starts with a lowercase letter, `[a-z0-9-]`, no consecutive hyphens, no leading/trailing hyphen, must equal the directory name |
27
+ | `description` | 1–1024 chars |
28
+ | Frontmatter keys | `name` + `description` only in this repo (spec also allows `license`, `compatibility`, `metadata`, `allowed-tools`; unknown keys hard-error on claude.ai packaging) |
29
+ | SKILL.md body | under 500 lines / ~5k tokens |
30
+ | Listing budgets | Claude truncates listed name+description around 1,536 chars; Codex caps the whole skill list at ~2% of context / 8,000 chars — front-load triggers |
31
+ | Relative references | one level deep, plain relative paths, no harness-specific syntax in the body |
32
+
33
+ ## Trigger query sets
34
+
35
+ Every skill ships `tests/fixtures/trigger-queries.json`: an array of `{"query": "...", "should_trigger": true|false}`.
36
+
37
+ - 8–10 should-trigger: different phrasings of the same intent — formal, casual, typo-ridden; cases that never name the skill but clearly need it; cases where a neighboring skill competes and this one should win.
38
+ - 8–10 should-NOT-trigger: **near-misses only.** Queries sharing keywords or domain with the skill but needing something else — adjacent intents, ambiguous phrasing a naive keyword match would catch. "Write a fibonacci function" as a negative for a PDF skill tests nothing.
39
+ - Queries must be realistic: concrete detail, file paths, a little backstory — what a user would actually type, not abstract category labels.
40
+
41
+ The set is both a design artifact (it forces the description to draw a real boundary) and eval input (see the [eval playbook](eval-playbook.md)).
42
+
43
+ ## Token economy
44
+
45
+ Three loading levels; spend accordingly:
46
+
47
+ 1. **Metadata (name + description)** — in every conversation, always. ~100 tokens. Every word must earn its place.
48
+ 2. **SKILL.md body** — loaded on every trigger. Keep the workflow, one excellent example, and a routing table; push everything else down a level. One great example beats five mediocre ones.
49
+ 3. **references/ / scripts/ / assets/** — loaded or executed on demand; effectively unlimited, but give each reference a clear routing condition so agents read only what the task needs.
50
+
51
+ Cross-reference other skills by name (`skill-maintainer`) instead of restating their content. Don't document a script's flags in prose beyond what routing needs — the script's own `--help`/usage error is the source of truth, and the consistency test keeps the two honest.
52
+
53
+ ## Scripts vs instructions
54
+
55
+ **Deterministic and repeated → script. Judgment → instructions.**
56
+
57
+ - If two invocations with the same input must produce the same bytes, that is a script.
58
+ - Watch eval/test transcripts for agents independently rewriting the same helper — three subagents each writing their own `parse_frontmatter` is a strong signal the skill should bundle that script once.
59
+ - Repo conventions for bundled scripts: dependency-free Node (`.mjs`), runnable from the skill dir with plain relative paths, `--json` for machine-readable output, documented exit codes (0 ok / 1 finding-or-refusal / 2 usage), atomic writes (stage then rename), symlink refusal, and an explicit `--write` gate for anything mutating — dry-run is the default.
60
+ - Do NOT script judgment: descriptions, verdicts, review prose. A script that fakes judgment produces confident garbage.
61
+
62
+ ## Claim classification for refresh
63
+
64
+ Classify every factual claim while writing, not after:
65
+
66
+ | Class | Test | Treatment |
67
+ |---|---|---|
68
+ | **Durable** | still true if every vendor renames everything | plain prose; refresh automation never touches it |
69
+ | **Mechanism-coupled** | durable intent expressed through a vendor-named mechanism (an option name, an API shape) | mark the sentence `<!-- source: SOURCE-ID -->`; editable only alongside registry evidence for that source |
70
+ | **Volatile** | version pins, numeric limits, model names, URLs, anything with a date | lives in `refresh/sources.json` entries or other refresh-tracked files — never inline in SKILL.md |
71
+
72
+ The refresh contract falls out of this table: each distinct SOURCE-ID becomes a registry entry with URLs, checksum, threshold; REFRESH.md states which files the refresh agent may edit (the volatile layer), which sentences it may propose edits to (marked ones), and which it must only flag (durable). A skill with no mechanism-coupled or volatile claims declares an **evergreen waiver** in REFRESH.md — one paragraph stating why nothing decays — and keeps `sources: []`.
@@ -0,0 +1,62 @@
1
+ # Behavioral eval playbook
2
+
3
+ How to prove a skill actually improves agent behavior before tests cement it. This is a procedure you execute with your own subagents (Task tool or equivalent) — never a custom eval harness, script, or viewer. If you find yourself writing eval tooling, stop; write instructions instead.
4
+
5
+ ## Why eval before tests
6
+
7
+ Tests lock in behavior. If the behavior is mediocre, tests lock in mediocrity. The eval proves the quality bar first; only then do unit tests cement the proven-good behavior. The corollary: if you didn't watch an agent fail *without* the skill, you don't know the skill teaches anything.
8
+
9
+ ## Method: with-skill vs baseline
10
+
11
+ 1. **Pick 2–3 realistic prompts.** The kind of thing a user would actually type — concrete, with file paths and context, exercising the skill's hardest documented use case, not its happy path. Reuse the strongest entries from `tests/fixtures/trigger-queries.json` where they fit.
12
+ 2. **Launch both runs per prompt in the same turn.** One subagent instructed to read and follow the new SKILL.md at its path; one baseline subagent given the identical prompt with no mention of the skill. (When improving an existing skill, the baseline is a snapshot of the old version instead.) Same-turn launch keeps the comparison honest and fast.
13
+ 3. **Capture outputs to a scratch workspace** (never committed): `<scratch>/eval/<prompt-id>/{with_skill,baseline}/`.
14
+ 4. **Compare against the skill's claimed value**, reading transcripts, not just final outputs.
15
+
16
+ ## Pass criteria
17
+
18
+ The with-skill run must be *materially* better on the dimensions the skill exists for:
19
+
20
+ - Output has the contract shape the skill defines (sections, verdicts, file layout) where the baseline's does not.
21
+ - The with-skill agent uses bundled scripts/templates instead of reinventing them; note any helper both runs wrote independently — that helper should become a bundled script.
22
+ - No contract violations the checklist would catch (frontmatter keys, name grammar, missing pieces).
23
+ - The transcript shows the skill's guidance being *used*, not just loaded — sections nobody used are bloat to cut.
24
+
25
+ **Failure that matters most:** the baseline matches the with-skill output. Then the skill is not earning its tokens — cut it, narrow it, or fold it into a reference.
26
+
27
+ ## Trigger-query eval (description level)
28
+
29
+ The body eval above assumes the skill got loaded. Separately check the description triggers correctly: walk `tests/fixtures/trigger-queries.json` and judge, for each query, whether an agent seeing only the skill list (name + description) would load this skill. Near-miss negatives are the valuable half — a description that survives them draws a real boundary. Fix failures by editing the *description* (triggers, boundary clause), never by stuffing workflow summary into it.
30
+
31
+ ## Cycle protocol (at most 3)
32
+
33
+ ```
34
+ CYCLE 1: run evals → list concrete improvements → apply them to the skill files
35
+ CYCLE 2: re-run the SAME prompts → compare before/after → apply what remains
36
+ CYCLE 3: re-run → pass, or ship with KNOWN_GAPS
37
+ ```
38
+
39
+ Hard stop after 3 cycles. Endless polishing is worse than an honest gap list. Generalize from feedback — fix the pattern that caused the failure, don't overfit wording to one prompt.
40
+
41
+ ## KNOWN_GAPS format
42
+
43
+ Ships at the bottom of the skill's README.md when the eval did not fully pass:
44
+
45
+ ```markdown
46
+ ## KNOWN_GAPS
47
+
48
+ - gap: baseline-quality section ordering under multi-file inputs
49
+ evidence: eval cycle 3, prompt "draft release notes for the 0.4 tag"
50
+ why unresolved: would require restructuring the routing table
51
+ next: revisit when references/format.md is split by artifact type
52
+ ```
53
+
54
+ One entry per gap: `gap` / `evidence` (cycle + prompt) / `why unresolved` / `next`. The eval summary itself (prompts used, cycles run, verdict per prompt) goes in the PR body, not the repo.
55
+
56
+ ## Model guidance
57
+
58
+ <!-- volatile: everything in this section decays; keep model facts out of SKILL.md and update here only. -->
59
+
60
+ - Run both arms of every comparison on the **same model** — otherwise you measure the model gap, not the skill.
61
+ - Use the model that will actually run the skill in production (typically the one powering the current session); a weaker grader cannot judge a stronger writer.
62
+ - If a separate grading pass is used, grade blind: give the grader both outputs unlabeled and ask which better satisfies the skill's stated contract.
@@ -0,0 +1,24 @@
1
+ # Refresh contract — skillify
2
+
3
+ Instructions for the scheduled refresh agent (and any human running a manual refresh). This file plus `sources.json` is the complete freshness contract for this skill.
4
+
5
+ ## What this skill claims
6
+
7
+ - **Durable rules** (SKILL.md, most of `references/`): the phase model, checklist structure, eval-before-tests ordering, description doctrine, claim-classification taxonomy. Versionless; the refresh agent NEVER edits these. If external evidence invalidates one, open an issue quoting the evidence — do not edit.
8
+ - **Mirrored volatile claims**: skillify does not track its own external sources. Its two volatile spots are marked in place:
9
+ - the numeric limits and harness listing budgets table in `references/authoring.md` (marked `<!-- mirrored -->`);
10
+ - the model guidance section in `references/eval-playbook.md` (marked `<!-- volatile -->`).
11
+
12
+ Both mirror facts whose sources of truth are the agent-skills standards sources tracked in the **skill-maintainer** registry (`skills/skill-maintainer/refresh/sources.json`). `sources` here is therefore deliberately empty, and the refresh runner treats this registry as valid with nothing to fetch.
13
+
14
+ ## How to refresh
15
+
16
+ 1. There is no deterministic fetch pass for this skill — an automated run against this registry selects zero sources and exits 0. Do not add sources here that duplicate skill-maintainer's; one registry per fact.
17
+ 2. When skill-maintainer's standards sources drift (spec limits, harness listing budgets, model catalogs), that skill's refresh PR is the evidence. Update skillify's two marked sections to match **on a normal branch** (refresh branches are CI-restricted to `refresh/` metadata), referencing the skill-maintainer refresh PR as evidence.
18
+ 3. If a future edit gives skillify a directly-owned external claim (its own vendor URL, pin, or protocol fact), stop mirroring for that claim: add a real entry to `sources.json` and mark the sentence `<!-- source: SOURCE-ID -->`.
19
+
20
+ ## Never
21
+
22
+ - Never edit the phase model, checklist items, or verdict grammar in a refresh.
23
+ - Never hand-write checksum/version/timestamp values anywhere in this repo.
24
+ - Never duplicate a skill-maintainer source entry into this registry.
@@ -0,0 +1,6 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "retrievalBaseline": "2026-08-08T00:00:00Z",
4
+ "note": "Deliberately empty. Skillify's only time-decaying claims (agent-skill numeric limits and harness listing budgets in references/authoring.md; model guidance in references/eval-playbook.md) are mirrored from the standards sources tracked in the skill-maintainer registry and are refreshed through that skill's registry, not duplicated here. See REFRESH.md.",
5
+ "sources": []
6
+ }
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env node
2
+ // Scaffold a new skill tree at skills/<name>/ from skillify's templates.
3
+ //
4
+ // node scripts/scaffold-skill.mjs <skill-name> --dir <repo-root> [--write] [--json]
5
+ //
6
+ // Dry-run by default: prints the plan (files that would be created plus the
7
+ // remaining manual wiring steps) and creates nothing. --write stages the tree
8
+ // in a temporary sibling inside skills/ and renames it into place, refusing
9
+ // existing directories and symlinks. Exit codes: 0 ok, 1 refusal or failure,
10
+ // 2 usage error.
11
+ import { lstat, mkdir, mkdtemp, readFile, rename, rm, writeFile } from 'node:fs/promises'
12
+ import { dirname, join, resolve } from 'node:path'
13
+ import { fileURLToPath } from 'node:url'
14
+
15
+ const here = dirname(fileURLToPath(import.meta.url))
16
+ const templatesRoot = resolve(here, '..', 'assets', 'templates')
17
+
18
+ // Template file -> output path inside skills/<name>/ (null = tests/<name>.test.ts).
19
+ export const templateFiles = [
20
+ ['SKILL.md.template', 'SKILL.md'],
21
+ ['README.md.template', 'README.md'],
22
+ ['sources.json.template', 'refresh/sources.json'],
23
+ ['REFRESH.md.template', 'refresh/REFRESH.md'],
24
+ ['openai.yaml.template', 'agents/openai.yaml'],
25
+ ['skill.test.ts.template', null],
26
+ ]
27
+
28
+ // Full grammar shared by the repo validator and every target harness: starts
29
+ // with a lowercase letter, then lowercase letters/digits/hyphens, no
30
+ // consecutive hyphens, no trailing hyphen, at most 64 characters.
31
+ export function validateName(name) {
32
+ if (typeof name !== 'string' || name.length === 0) return 'skill name is required'
33
+ if (name.length > 64) return `name is ${name.length} characters; the maximum is 64`
34
+ if (!/^[a-z]/.test(name)) return 'name must start with a lowercase letter'
35
+ if (!/^[a-z0-9-]+$/.test(name)) return 'name may contain only lowercase letters, digits, and hyphens'
36
+ if (name.includes('--')) return 'name must not contain consecutive hyphens'
37
+ if (name.endsWith('-')) return 'name must not end with a hyphen'
38
+ return null
39
+ }
40
+
41
+ export function wiringSteps(name) {
42
+ return [
43
+ `Add skills/${name}/ packaged files to the allowlist in packages/cli/scripts/sync-skill.mjs (the build fails loudly on unlisted files)`,
44
+ `Add a ${name} row to the Skills table in the root README.md`,
45
+ `Add a CHANGELOG entry (changeset) introducing ${name}`,
46
+ ]
47
+ }
48
+
49
+ async function entryAt(path) {
50
+ try {
51
+ return await lstat(path)
52
+ } catch {
53
+ return null
54
+ }
55
+ }
56
+
57
+ export async function scaffoldSkill({ name, dir, write = false, now = new Date() }) {
58
+ const nameError = validateName(name)
59
+ if (nameError) throw new Error(`Invalid skill name ${JSON.stringify(name ?? null)}: ${nameError}`)
60
+ if (!dir) throw new Error('--dir <repo-root> is required')
61
+ const repoRoot = resolve(dir)
62
+ const skillsRoot = join(repoRoot, 'skills')
63
+ const skillsEntry = await entryAt(skillsRoot)
64
+ // lstat does not follow symlinks, so a symlinked skills/ fails isDirectory().
65
+ if (!skillsEntry || !skillsEntry.isDirectory()) {
66
+ throw new Error(`${skillsRoot} is not a real directory - point --dir at the vegastack-skills repo root`)
67
+ }
68
+ const target = join(skillsRoot, name)
69
+ if (await entryAt(target)) throw new Error(`Refusing to scaffold: ${target} already exists`)
70
+
71
+ const outputs = templateFiles.map(([source, output]) => [source, output ?? `tests/${name}.test.ts`])
72
+ const plan = { name, target, files: outputs.map(([, output]) => output), wiring: wiringSteps(name), wrote: false }
73
+ if (!write) return plan
74
+
75
+ const date = now.toISOString().slice(0, 10)
76
+ const staging = await mkdtemp(join(skillsRoot, `.${name}.scaffold-`))
77
+ try {
78
+ for (const [source, output] of outputs) {
79
+ const body = await readFile(join(templatesRoot, source), 'utf8')
80
+ const rendered = body.replaceAll('{{name}}', name).replaceAll('{{date}}', date)
81
+ const destination = join(staging, output)
82
+ await mkdir(dirname(destination), { recursive: true })
83
+ await writeFile(destination, rendered)
84
+ }
85
+ if (await entryAt(target)) throw new Error(`Refusing to scaffold: ${target} already exists`)
86
+ await rename(staging, target)
87
+ } catch (error) {
88
+ await rm(staging, { recursive: true, force: true })
89
+ throw error
90
+ }
91
+ return { ...plan, wrote: true }
92
+ }
93
+
94
+ function parseArguments(argv) {
95
+ const options = { name: undefined, dir: undefined, write: false, json: false }
96
+ const rest = [...argv]
97
+ while (rest.length) {
98
+ const flag = rest.shift()
99
+ if (flag === '--dir') {
100
+ const value = rest.shift()
101
+ if (value === undefined || value.startsWith('-')) throw new Error('--dir requires a value')
102
+ options.dir = value
103
+ } else if (flag === '--write') options.write = true
104
+ else if (flag === '--json') options.json = true
105
+ else if (flag.startsWith('-')) throw new Error(`Unknown option: ${flag}`)
106
+ else if (options.name === undefined) options.name = flag
107
+ else throw new Error(`Unexpected argument: ${flag}`)
108
+ }
109
+ if (!options.name || !options.dir) {
110
+ throw new Error('Usage: node scripts/scaffold-skill.mjs <skill-name> --dir <repo-root> [--write] [--json]')
111
+ }
112
+ return options
113
+ }
114
+
115
+ const invokedDirectly = process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)
116
+ if (invokedDirectly) {
117
+ let options
118
+ try {
119
+ options = parseArguments(process.argv.slice(2))
120
+ } catch (error) {
121
+ console.error(String(error.message ?? error))
122
+ process.exit(2)
123
+ }
124
+ try {
125
+ const result = await scaffoldSkill(options)
126
+ if (options.json) {
127
+ console.log(JSON.stringify(result, null, 2))
128
+ } else {
129
+ console.log(result.wrote ? `Created ${result.target}` : `Dry run - pass --write to create ${result.target}`)
130
+ for (const file of result.files) console.log(` ${file}`)
131
+ console.log('Remaining manual wiring:')
132
+ for (const step of result.wiring) console.log(` - ${step}`)
133
+ }
134
+ } catch (error) {
135
+ console.error(String(error.message ?? error))
136
+ process.exit(1)
137
+ }
138
+ }