@open-agent-toolkit/cli 0.2.63 → 0.2.64

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 (92) hide show
  1. package/assets/bundle-metadata.json +1 -1
  2. package/assets/docs/cli-utilities/tool-packs.md +83 -0
  3. package/assets/docs/contributing/skills.md +42 -7
  4. package/assets/docs/provider-sync/manifest-and-drift.md +105 -0
  5. package/assets/public-package-versions.json +4 -4
  6. package/assets/skills/create-agnostic-skill/SKILL.md +9 -7
  7. package/assets/skills/create-agnostic-skill/references/skill-template.md +9 -7
  8. package/assets/skills/oat-project-autonomous/references/gate-inventory.md +1 -0
  9. package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +1 -0
  10. package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +1 -0
  11. package/assets/skills/oat-project-lite/references/docs/autonomy-contract.md +1 -0
  12. package/assets/skills/oat-project-pr-final/SKILL.md +281 -6
  13. package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +1 -0
  14. package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +1 -0
  15. package/dist/agents/canonical/resolve.d.ts.map +1 -1
  16. package/dist/agents/canonical/resolve.js +25 -4
  17. package/dist/commands/doctor/index.d.ts +7 -0
  18. package/dist/commands/doctor/index.d.ts.map +1 -1
  19. package/dist/commands/doctor/index.js +10 -2
  20. package/dist/commands/init/tools/index.d.ts.map +1 -1
  21. package/dist/commands/init/tools/index.js +68 -36
  22. package/dist/commands/shared/frontmatter.d.ts +51 -0
  23. package/dist/commands/shared/frontmatter.d.ts.map +1 -1
  24. package/dist/commands/shared/frontmatter.js +118 -6
  25. package/dist/commands/status/index.d.ts.map +1 -1
  26. package/dist/commands/status/index.js +5 -3
  27. package/dist/commands/sync/index.d.ts +14 -0
  28. package/dist/commands/sync/index.d.ts.map +1 -1
  29. package/dist/commands/sync/index.js +21 -0
  30. package/dist/commands/tools/info/index.d.ts.map +1 -1
  31. package/dist/commands/tools/info/index.js +14 -1
  32. package/dist/commands/tools/info/info-tool.d.ts +12 -0
  33. package/dist/commands/tools/info/info-tool.d.ts.map +1 -1
  34. package/dist/commands/tools/info/info-tool.js +54 -6
  35. package/dist/commands/tools/info/skill-views.d.ts +86 -0
  36. package/dist/commands/tools/info/skill-views.d.ts.map +1 -0
  37. package/dist/commands/tools/info/skill-views.js +383 -0
  38. package/dist/commands/tools/install/index.d.ts.map +1 -1
  39. package/dist/commands/tools/install/index.js +3 -25
  40. package/dist/commands/tools/list/list-tools.d.ts +2 -0
  41. package/dist/commands/tools/list/list-tools.d.ts.map +1 -1
  42. package/dist/commands/tools/list/list-tools.js +23 -4
  43. package/dist/commands/tools/remove/index.d.ts.map +1 -1
  44. package/dist/commands/tools/remove/index.js +35 -42
  45. package/dist/commands/tools/remove/remove-tools.d.ts +3 -2
  46. package/dist/commands/tools/remove/remove-tools.d.ts.map +1 -1
  47. package/dist/commands/tools/remove/remove-tools.js +14 -4
  48. package/dist/commands/tools/shared/auto-sync.d.ts +12 -1
  49. package/dist/commands/tools/shared/auto-sync.d.ts.map +1 -1
  50. package/dist/commands/tools/shared/auto-sync.js +20 -4
  51. package/dist/commands/tools/shared/format-pack-inventory.d.ts +12 -1
  52. package/dist/commands/tools/shared/format-pack-inventory.d.ts.map +1 -1
  53. package/dist/commands/tools/shared/format-pack-inventory.js +48 -6
  54. package/dist/commands/tools/shared/in-process-sync.d.ts +11 -0
  55. package/dist/commands/tools/shared/in-process-sync.d.ts.map +1 -0
  56. package/dist/commands/tools/shared/in-process-sync.js +79 -0
  57. package/dist/commands/tools/shared/pack-evidence.d.ts +78 -2
  58. package/dist/commands/tools/shared/pack-evidence.d.ts.map +1 -1
  59. package/dist/commands/tools/shared/pack-evidence.js +96 -2
  60. package/dist/commands/tools/shared/pack-lifecycle-outcome.d.ts +11 -0
  61. package/dist/commands/tools/shared/pack-lifecycle-outcome.d.ts.map +1 -1
  62. package/dist/commands/tools/shared/pack-lifecycle-outcome.js +24 -3
  63. package/dist/commands/tools/shared/pack-provider-evidence.d.ts +73 -0
  64. package/dist/commands/tools/shared/pack-provider-evidence.d.ts.map +1 -0
  65. package/dist/commands/tools/shared/pack-provider-evidence.js +161 -0
  66. package/dist/commands/tools/shared/provider-context.d.ts +88 -0
  67. package/dist/commands/tools/shared/provider-context.d.ts.map +1 -0
  68. package/dist/commands/tools/shared/provider-context.js +77 -0
  69. package/dist/commands/tools/shared/provider-reachability.d.ts +93 -0
  70. package/dist/commands/tools/shared/provider-reachability.d.ts.map +1 -0
  71. package/dist/commands/tools/shared/provider-reachability.js +358 -0
  72. package/dist/commands/tools/shared/sync-evidence.d.ts +57 -0
  73. package/dist/commands/tools/shared/sync-evidence.d.ts.map +1 -0
  74. package/dist/commands/tools/shared/sync-evidence.js +147 -0
  75. package/dist/commands/tools/update/index.d.ts +0 -4
  76. package/dist/commands/tools/update/index.d.ts.map +1 -1
  77. package/dist/commands/tools/update/index.js +22 -40
  78. package/dist/commands/tools/update/update-tools.d.ts.map +1 -1
  79. package/dist/commands/tools/update/update-tools.js +23 -8
  80. package/dist/config/json.d.ts +36 -0
  81. package/dist/config/json.d.ts.map +1 -1
  82. package/dist/config/json.js +135 -3
  83. package/dist/drift/index.d.ts +2 -0
  84. package/dist/drift/index.d.ts.map +1 -1
  85. package/dist/drift/index.js +1 -0
  86. package/dist/drift/skill-view-diagnostic.d.ts +197 -0
  87. package/dist/drift/skill-view-diagnostic.d.ts.map +1 -0
  88. package/dist/drift/skill-view-diagnostic.js +343 -0
  89. package/dist/validation/skills.d.ts +1 -0
  90. package/dist/validation/skills.d.ts.map +1 -1
  91. package/dist/validation/skills.js +181 -19
  92. package/package.json +2 -2
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "oatVersion": "0.2.63"
3
+ "oatVersion": "0.2.64"
4
4
  }
@@ -307,6 +307,57 @@ application-process restart requirement, or proof of visibility. No advice is
307
307
  emitted for current/no-op, planned-only, failed, missing, inactive, or
308
308
  unsupported materialization.
309
309
 
310
+ Every pack lifecycle outcome (`install`, `update`, `remove`, and the aggregate
311
+ init path) and every pack inventory surface (`oat tools list`, `oat tools
312
+ info`, `oat status`, `oat doctor`) carries per-provider reachability evidence
313
+ in its JSON, derived from the same config-aware registry the sync engine uses:
314
+ activation, content capability, projection, materialization, catalog-refresh
315
+ visibility, and recovery guidance. Human output names the provider on its own
316
+ line and on any provider-attributed diagnostic. Reachability is never inferred
317
+ from the presence of a provider directory on disk.
318
+
319
+ The four inventory surfaces agree on managed user-scope roles. `list` and
320
+ `info` resolve the same provider surface as `status` and `doctor`, so an
321
+ active Codex or Cursor adapter that supplies managed roles suppresses the
322
+ unmaterialized-user-agent report on all four rather than only two.
323
+
324
+ Each provider state maps to exactly one row below. Pack evidence status and
325
+ the lifecycle exit code derive from the **severity** column, never from the
326
+ code name, so adding a code later cannot silently change an exit code.
327
+
328
+ | Provider state (per provider, scope, content kind) | Diagnostic code | Severity | Pack evidence status | Lifecycle outcome / exit code |
329
+ | ---------------------------------------------------------------------- | --------------------------------------- | --------- | -------------------- | ------------------------------------------------ |
330
+ | Active, supported, projection and materialization succeeded | none | -- | `ok` | `complete` / 0 |
331
+ | Explicitly disabled in sync config for this scope | `provider-inactive` | `info` | `ok` | `complete` / 0 |
332
+ | Active but the content kind is unsupported by the adapter | `provider-unsupported` | `info` | `ok` | `complete` / 0 |
333
+ | Active, supported, no projection exists (never synced or sync skipped) | `provider-materialization-missing` | `warning` | `partial` | `complete` / 0 (install succeeded; sync advised) |
334
+ | Active, supported, the sync operation for this asset failed | `provider-materialization-failed` | `error` | `partial` | `partial` / 1 |
335
+ | Active, projected, no sourced refresh contract for the host | `visibility-unknown` | `info` | `ok` | `complete` / 0 |
336
+ | Active, projected, host catalog needs a refresh or a restart | `refresh-required` / `restart-required` | `info` | `ok` | `complete` / 0 |
337
+ | Read-only inventory (`list`, `info`, `status`, `doctor`): no sync ran | registry-derived codes only | as above | as above | not applicable |
338
+ | Auto-sync not run (disabled or skipped) after a lifecycle operation | none; `providerSync.status: 'not-run'` | -- | `ok` | `complete` / 0 |
339
+
340
+ Rows with `info` severity are visible in JSON and in the human provider line
341
+ but do not turn `ok` into `partial`. A provider that was never detected and
342
+ never configured is not reported per pack: its inactive state is still carried
343
+ on the evidence row, but emitting a diagnostic for every registered provider on
344
+ every pack would bury the actionable rows. `unknown` visibility is reported as
345
+ unknown; it never claims reachability and never fails an otherwise successful
346
+ install. A read-only inventory surface ran no sync, so it never reports
347
+ `provider-materialization-failed`.
348
+
349
+ The three visibility codes — `visibility-unknown`, `refresh-required`, and
350
+ `restart-required` — are lifecycle-only for the same reason. They require an
351
+ established projection, and a read-only surface never establishes one: it
352
+ observed no sync, so it reports materialization as a non-claim rather than
353
+ asserting the provider view exists. For an active provider that supports the
354
+ content kind, the registered catalog state remains readable in the row's
355
+ `visibility` field on every surface; only the diagnostics are withheld. Run
356
+ `oat tools install`, `update`, or `remove` to see them emitted. An inactive or
357
+ unsupported row reports `not-applicable` visibility instead, matching its
358
+ `not-applicable` projection: catalog advice about a provider that cannot
359
+ receive the content would read as a step to act on.
360
+
310
361
  Repository templates under `.oat/templates/` are **owner-owned seeds**. OAT
311
362
  compares a source-backed seed with its bundled default: a byte-equivalent copy
312
363
  is reported as current, while an edited copy is retained and reported as a
@@ -512,8 +563,40 @@ Key behavior:
512
563
 
513
564
  - Displays name, type (skill/agent), version, bundled version, pack, scope, and status
514
565
  - Reports whether the tool is invocable (for skills) and whether an update is available
566
+ - For a skill, adds a read-only provider-view section per active provider and scope: the expected provider path, the view class, and versions where a copy makes them comparable
567
+ - Suggests the narrowest safe repair, one `oat sync --scope <concrete>` per affected scope and never `--scope all`
515
568
  - Returns exit code 1 if the tool is not found in any scope
516
569
 
570
+ An unknown name keeps the existing `Tool '<name>' not found.` wording and prints
571
+ no provider-view section, so a skill that exists but was never distributed is
572
+ never confused with a name the repository does not have.
573
+
574
+ ```text
575
+ $ oat tools info probe-skill --scope project
576
+ probe-skill
577
+ Type: skill
578
+ Version: 1.4.2
579
+ Pack: custom
580
+ Scope: project
581
+ Status: not-bundled
582
+ Provider views (project):
583
+ claude: missing-additive .claude/skills/probe-skill
584
+ Canonical skill has never been projected to this view: no manifest entry and nothing at the expected path.
585
+ cursor: inactive
586
+ Repair: oat sync --scope project
587
+ ```
588
+
589
+ The section is additive in `--json` output as `providerViews`, an array of one
590
+ entry per concrete scope where the canonical skill exists. The command reads the
591
+ manifest, the sync config, and the filesystem; it never writes, and it never
592
+ runs a sync. If the sync config or the manifest cannot be read, that scope's
593
+ section reports `unavailable` with a redacted reason and the tool detail and exit
594
+ code are unchanged; a failure reading one provider's view degrades only that row,
595
+ to `unverified` with the same redacted reason. An absent sync config is not a
596
+ failure: it resolves to the defaults and the scope is diagnosed normally. See
597
+ [Manifest and Drift](../provider-sync/manifest-and-drift.md#resolution-time-skill-view-classes)
598
+ for the view classes.
599
+
517
600
  ### `oat tools has <pack>`
518
601
 
519
602
  Purpose:
@@ -179,20 +179,55 @@ direct managed-role intent still retains the canonical agent.
179
179
 
180
180
  - `name`
181
181
  - `description`
182
- - `version`
182
+ - `metadata.version` (top-level `version` is the deprecated alias)
183
183
  - `disable-model-invocation`
184
184
  - `user-invocable`
185
185
  - `allowed-tools`
186
186
  - `oat_gateable`
187
187
 
188
- ### The `version` field is gated
188
+ ### How a skill's version is resolved
189
+
190
+ The Agent Skills specification carries a skill's version under `metadata`, so
191
+ that is where a new skill declares it:
192
+
193
+ ```yaml
194
+ metadata:
195
+ version: 1.0.0
196
+ ```
197
+
198
+ OAT resolves a version from `metadata.version` first and from the top-level
199
+ `version` field second, and it resolves it the same way everywhere it reads
200
+ one: the installed-versus-bundled comparison behind `oat tools list`,
201
+ `oat tools update`, and `oat doctor`; skill validation; and canonical role
202
+ resolution. `resolveSkillVersion` in
203
+ `packages/cli/src/commands/shared/frontmatter.ts` owns that order, so the
204
+ runtime helper and the validators cannot disagree.
205
+
206
+ The top-level `version` field remains supported as a deprecated alias. Every
207
+ bundled skill still uses it today, so `pnpm oat:validate-skills` reports each
208
+ one as a non-blocking warning; the value is still read, and nothing breaks.
209
+ Migrating the bundled skills is tracked separately.
210
+
211
+ A skill that carries both fields with different values is a conflict. The
212
+ resolver reports the `metadata.version` value together with the conflict, and
213
+ the callers that must not guess act on it: validation reports an error rather
214
+ than silently picking one, and canonical role resolution treats the identity as
215
+ invalid. The runtime version readers still return the `metadata.version` value,
216
+ so an installed-versus-bundled comparison keeps working while the conflict is
217
+ being fixed. Carrying both with the _same_ value is accepted.
218
+
219
+ ### The version is gated
189
220
 
190
221
  Changing any canonical skill's `SKILL.md` requires bumping its frontmatter
191
- `version` in the same PR — one bump per changed skill in the final PR diff,
192
- even if the skill was edited multiple times on the branch. The rule is
193
- enforced by `pnpm run check:skill-bumps`, which runs locally (root `AGENTS.md`
194
- Definition of Done) and in CI; a changed skill whose version matches
195
- `origin/main` fails the gate.
222
+ version in the same PR — one bump per changed skill in the final PR diff,
223
+ even if the skill was edited multiple times on the branch. The gate reads the
224
+ resolved version, so it enforces the bump whether the skill declares
225
+ `metadata.version` or the top-level alias. The rule is enforced by
226
+ `pnpm run check:skill-bumps`, which runs locally (root `AGENTS.md` Definition
227
+ of Done) and in CI; a changed skill whose version matches `origin/main` fails
228
+ the gate. The deprecation warning above is deliberately not part of that gate:
229
+ `check:skill-bumps` fails on any finding it receives, so an alias warning
230
+ routed through it would fail every changed skill until the migration lands.
196
231
 
197
232
  ## Practical Authoring Flow
198
233
 
@@ -84,6 +84,111 @@ An exact alias is `in_sync`; an absent alias is `missing`; and a broken,
84
84
  replaced, foreign, or otherwise unverifiable alias is `drifted`. Provider list
85
85
  and inspect output summarize collection ownership separately from copy mode.
86
86
 
87
+ ### Resolution-time skill view classes
88
+
89
+ Drift states answer "does the tracked view still match?", which presupposes a
90
+ manifest entry. A canonical skill that was never synced has no entry at all, so
91
+ `oat tools info <name>` adds a second, additive classification beside the
92
+ unchanged drift state. Provider and path identity for an untracked projection
93
+ come from the active provider set and the adapter's scope mappings, not from
94
+ the manifest.
95
+
96
+ - `missing-additive` — active, supported, no manifest entry, nothing at the expected path: the only true projection gap
97
+ - `removed` — a manifest entry exists but the provider file is gone
98
+ - `modified` — a manifest entry exists and the view no longer agrees with what the last sync recorded, or its version has fallen behind canonical. A `copy` view also reaches this class through the known limitation below, where the difference may be nothing but the generated banner
99
+ - `in-sync` — a symlinked, collection-aliased, or natively read view _is_ the canonical file; a `copy` view matches the content recorded at its last sync
100
+ - `untracked` — something exists at the expected path that no manifest entry tracks; stray detection skips provider entries whose name matches a canonical entry, so `oat status` does not report it as a stray and reports the untracked projection as `missing` instead
101
+ - `unverified` — the view's state is unknown: either a manifest entry arrived with no drift observation, or reading that one view failed and the row carries the redacted reason
102
+ - `inactive`, `unsupported`, `excluded` — no projection is expected in this scope, so none of them is reported as missing
103
+
104
+ `unsupported` and `excluded` are defensive: no shipped adapter or config
105
+ produces them today. Every shipped adapter maps skills in both scopes and the
106
+ command passes no canonical-path filter. The branches exist so a future adapter
107
+ or filter cannot be silently reported as a projection gap. `unverified` is
108
+ reachable: an unreadable provider path makes drift detection throw, and that one
109
+ view degrades to `unverified` with its reason.
110
+
111
+ A row for `inactive`, `unsupported`, or `excluded` prints neither a projection
112
+ qualifier nor a path, because no view is projected for it: naming an expected
113
+ path and a sync strategy for a file that is never produced described work that
114
+ is never going to happen.
115
+
116
+ Only `missing-additive`, `removed`, and `modified` carry a repair, and it is
117
+ always one concrete `oat sync --scope project` or `oat sync --scope user` for
118
+ the scope where the gap was observed. Versions are compared only for `copy`
119
+ views: a symlinked, collection-aliased, or natively read view is the canonical
120
+ file, so it has no second version.
121
+
122
+ If reading the sync config or the manifest fails — an invalid, unreadable, or
123
+ otherwise non-loadable `.oat/sync/config.json` or `.oat/sync/manifest.json`, for
124
+ instance — the section for that scope reports `unavailable` with the reason, and
125
+ the rest of the command is unaffected. A failure while reading one provider's
126
+ view, such as drift detection throwing on an unreadable provider path, is
127
+ narrower: only that row degrades, to `unverified` with the same redacted reason,
128
+ and the other providers keep their real rows. The
129
+ diagnostic is additive evidence, so it never changes the exit code or removes
130
+ the tool detail of a user whose sync state is already broken. A broken sync
131
+ config is one of the likeliest reasons a provider view is missing, which is
132
+ exactly what this command is run to explain, so it is reported rather than
133
+ dropped: printing no section at all would read as "no providers configured".
134
+ An absent `.oat/sync/config.json` is a different case and not a failure — it
135
+ resolves to the defaults, and the scope is diagnosed normally. Reasons are
136
+ redacted; the scope root becomes `<project>` or `~` (only at a path boundary, so
137
+ a sibling directory that merely shares the prefix is left alone), and any
138
+ absolute path outside it is replaced entirely with `<path>`, quoted or not and
139
+ whatever punctuation precedes it. A manifest `providerPath` that escapes its own
140
+ scope is redacted the same way rather than rendered in the row, and no version
141
+ is read from it: its `SKILL.md` is a file outside the tree the command was asked
142
+ about.
143
+
144
+ A drift state and a view class can legitimately disagree. Drift compares a copy
145
+ against the hash recorded at its last sync, so a copy that was never re-synced
146
+ after a canonical edit still matches its own manifest entry and reads as
147
+ `in_sync`. When the two versions differ, the view class is `modified` and the
148
+ drift state is reported unchanged beside it.
149
+
150
+ The manifest is keyed by `(canonicalPath, provider)` and never by path, so a
151
+ manifest entry can track a view somewhere other than the adapter's expected
152
+ projection path — reachable after a `providerDir` change or from a manifest
153
+ written under an older layout. Drift resolves the entry's own `providerPath`, so
154
+ in that case the row names the tracked path rather than the expected one, and
155
+ its `--json` record carries the expected path separately as
156
+ `expectedProviderPath`. The detail says which path the state describes and
157
+ whether anything exists at the expected path. A drift verdict computed for one
158
+ path is never attached to a row labelled with another: doing so reported `removed`
159
+ with "the provider file is gone from disk" against a healthy file that was
160
+ sitting at the expected path all along.
161
+
162
+ Both sides resolve their version through the same shared reader, so
163
+ `metadata.version` takes precedence over the deprecated top-level `version`
164
+ alias for a projected view exactly as it does for the canonical source; the only
165
+ extra step for a view is stripping the generated banner. When a projected
166
+ `SKILL.md` contradicts itself — a top-level `version` and a differing
167
+ `metadata.version` — or declares a version the reader cannot use at all, the
168
+ comparison is withheld rather than decided: no version is reported for that
169
+ view, and the class is left to the drift state alone. That is deliberately
170
+ conservative and has a cost, since a copy in that state could be genuinely
171
+ stale and would not be reported as such. The view's detail names the two
172
+ declared values and says the comparison was skipped, so the ambiguity is
173
+ visible rather than silently resolved. When the resolver's answer happens to
174
+ agree with canonical, nothing is withheld and the detail says so instead.
175
+
176
+ ### Known limitation: copy-strategy skill views
177
+
178
+ A `copy` skill view is reported `modified` immediately after a successful sync,
179
+ and stays that way. The engine writes an OAT-managed banner into the copied
180
+ `SKILL.md` and an `.oat-generated` sentinel beside it, and neither is accounted
181
+ for in the manifest hash, so `oat status` reports `drifted:modified` and every
182
+ later `oat sync --dry-run` plans another `update_copy`. Because no sync clears
183
+ that state, `oat tools info` prints no repair line when a `modified` copy's
184
+ version still matches canonical.
185
+
186
+ That suppression is a conservative heuristic rather than a proof: equal versions
187
+ do not establish equal bodies, so an edit to the canonical source or to the copy
188
+ that kept the version reaches the same branch, and a sync _would_ repair that
189
+ one. The class detail says so and names the concrete scope command to run if you
190
+ know either side was edited. Tracked as `BL-260908-make-copy-strategy-skill`.
191
+
87
192
  ## Stray adoption
88
193
 
89
194
  `oat init` and `oat status` can offer adoption of unmanaged provider entries into canonical `.agents`.
@@ -1,6 +1,6 @@
1
1
  {
2
- "cli": "0.2.63",
3
- "docs-config": "0.2.63",
4
- "docs-theme": "0.2.63",
5
- "docs-transforms": "0.2.63"
2
+ "cli": "0.2.64",
3
+ "docs-config": "0.2.64",
4
+ "docs-theme": "0.2.64",
5
+ "docs-transforms": "0.2.64"
6
6
  }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: create-agnostic-skill
3
- version: 1.4.1
3
+ version: 1.4.2
4
4
  description: Use when adding a reusable workflow skill for AI coding agents. Scaffolds a new .agents/skills skill using the Agent Skills open standard.
5
5
  argument-hint: '[skill-name]'
6
6
  disable-model-invocation: true
@@ -98,12 +98,13 @@ For detailed guidance, see `references/skill-template.md`.
98
98
  ```markdown
99
99
  ---
100
100
  name: skill-name
101
- version: 1.0.0
102
101
  description: Use when [trigger condition]. [What it does for disambiguation].
103
102
  argument-hint: '[arg1] [--flag]'
104
103
  disable-model-invocation: true
105
104
  allowed-tools: Read, Write, Glob, Grep
106
105
  user-invocable: true
106
+ metadata:
107
+ version: 1.0.0
107
108
  ---
108
109
 
109
110
  # Skill Title
@@ -172,9 +173,10 @@ Natural language request that triggers this skill
172
173
  - `argument-hint`, `allowed-tools`, `user-invocable`, `context`, `hooks` are Claude Code specific
173
174
  - Other agents ignore unknown frontmatter fields, so it's safe to include Claude-specific fields everywhere
174
175
  - `name`: max 64 chars for cross-provider portability (Codex allows 100, but 64 is the spec limit)
175
- - `version`: include valid semver and start new skills at `1.0.0`
176
+ - `metadata.version`: include valid semver and start new skills at `1.0.0`. The Agent Skills specification puts the version under `metadata`, and OAT resolves `metadata.version` first and the top-level `version` second — `resolveSkillVersion` in `packages/cli/src/commands/shared/frontmatter.ts` owns that order, backstopped by `packages/cli/src/commands/shared/frontmatter.test.ts`
177
+ - `version` (top-level): the deprecated alias, still read when `metadata.version` is absent. Do not set both to different values: OAT reports the conflict, skill validation fails on it, and canonical role identity rejects it
176
178
  - `description`: **single line, ≤ 500 chars** (Codex enforces single-line ≤ 500 chars; spec allows 1024)
177
- - Bump `version` on future edits: patch for fixes/clarifications, minor for backward-compatible behavior additions, major for breaking workflow/interface changes
179
+ - Bump `metadata.version` on future edits: patch for fixes/clarifications, minor for backward-compatible behavior additions, major for breaking workflow/interface changes
178
180
 
179
181
  **Writing the `description` field:**
180
182
 
@@ -200,7 +202,7 @@ Create the skill at `.agents/skills/{skill-name}/SKILL.md`
200
202
  **Key requirements:**
201
203
 
202
204
  - Skill name matches directory name
203
- - New skills include `version: 1.0.0` in frontmatter
205
+ - New skills include `metadata.version: 1.0.0` in frontmatter
204
206
  - Workflow steps use "Step 1, 2, 3..." naming
205
207
  - Include both "Basic Usage" and "Conversational" example styles
206
208
  - Use imperative form for instructions
@@ -238,7 +240,7 @@ Verify:
238
240
 
239
241
  - File created at `.agents/skills/{skill-name}/SKILL.md`
240
242
  - Frontmatter syntax is valid
241
- - Frontmatter includes valid semver `version:` (new skills start at `1.0.0`)
243
+ - Frontmatter includes valid semver `metadata.version:` (new skills start at `1.0.0`)
242
244
  - Skill appears in `AGENTS.md`
243
245
  - Examples include both invocation styles
244
246
  - If the skill name starts with `oat-`, run `pnpm oat:validate-skills` and fix any findings
@@ -264,7 +266,7 @@ Provide:
264
266
 
265
267
  - **Context window is a public good**—keep skills lean, challenge every paragraph
266
268
  - Description is the trigger—include "when to use" in frontmatter, not just body
267
- - Bump `version` for edits: patch = fixes/clarifications, minor = backward-compatible additions, major = breaking changes
269
+ - Bump `metadata.version` for edits: patch = fixes/clarifications, minor = backward-compatible additions, major = breaking changes
268
270
  - Keep SKILL.md **under 500 lines / ~5,000 tokens** (spec constraint)
269
271
  - Use clear, task-based headings
270
272
  - Include working examples for both invocation styles
@@ -28,9 +28,6 @@ Adjust based on complexity—not all sections are required:
28
28
  name: skill-name
29
29
  # Required: kebab-case, max 64 chars, must match directory name
30
30
 
31
- version: 1.0.0
32
- # Required: semver. Start new skills at 1.0.0.
33
-
34
31
  description: Use when [trigger condition]. [What it does as disambiguation keywords].
35
32
  # Required: Single line, ≤ 500 chars. Lead with "when to use" — this is the routing trigger.
36
33
  # Agents load ONLY name+description at startup to decide relevance.
@@ -38,9 +35,13 @@ description: Use when [trigger condition]. [What it does as disambiguation keywo
38
35
  # === Spec-optional fields (recognized by some providers) ===
39
36
  # license: Apache-2.0
40
37
  # compatibility: Requires Node.js 18+
41
- # metadata:
42
- # author: my-org
43
- # version: "1.0"
38
+
39
+ metadata:
40
+ version: 1.0.0
41
+ # Required: semver. Start new skills at 1.0.0. The spec carries the version
42
+ # under `metadata`; a top-level `version:` is a deprecated alias that is read
43
+ # only when `metadata.version` is absent.
44
+ # author: my-org
44
45
 
45
46
  # === Claude Code / Cursor extension fields (ignored by Codex, safe to include) ===
46
47
  argument-hint: '[required-arg] [--optional-flag]'
@@ -187,9 +188,10 @@ Successful completion means:
187
188
 
188
189
  ## Versioning Guidance
189
190
 
190
- - Include `version:` in frontmatter for every skill and use semver (`MAJOR.MINOR.PATCH`).
191
+ - Include `metadata.version` in frontmatter for every skill and use semver (`MAJOR.MINOR.PATCH`).
191
192
  - Start new skills at `1.0.0`.
192
193
  - Bump patch for fixes/clarifications, minor for backward-compatible behavior additions, major for breaking workflow/interface changes.
194
+ - A top-level `version:` is the deprecated alias for the same value: it is read only when `metadata.version` is absent, and a skill that carries both with different values is reported as a conflict that validation rejects. `resolveSkillVersion` in `packages/cli/src/commands/shared/frontmatter.ts` owns that order.
193
195
 
194
196
  ## Cross-Provider Portability Notes
195
197
 
@@ -193,6 +193,7 @@ remains.
193
193
  | PRFINAL-02 | `oat-project-pr-final` | Missing title/base | Ask for title and resolve base | Use the documented ticket/conventional-title and base-branch resolution chains | `auto-resolve` | PR artifact frontmatter and command |
194
194
  | PRFINAL-03 | `oat-project-pr-final` | Final review not passed | Ask whether to proceed anyway | Never proceed in autonomy; stop and route to final review/re-review | `boundary:unresolved-critical-findings` | Final review row and blocker report |
195
195
  | PRFINAL-04 | `oat-project-pr-final` | Push/PR policy or credentials | Ask operator to authorize or authenticate | Stop when repository policy or missing credentials prevent push/PR creation | `boundary:repository-policy-approval` / `boundary:missing-credentials` | PR state and redacted command error |
196
+ | PRFINAL-05 | `oat-project-pr-final` | Unresolved review-ledger artifact path | Report the offending row and stop | Stop before push and PR creation; a `## Reviews` artifact path that does not resolve to a regular file inside the project is never auto-resolved, and repairing the row is the only route forward | `boundary:unresolved-critical-findings` | Offending ledger row (scope, type, artifact) |
196
197
  | COMPLETE-01 | `oat-project-complete` | Batched completion/archive/summary/PR choices | Confirm completion and choose optional actions | Confirm only after gates pass; honor explicit config, refresh missing/stale summary, avoid duplicate PR, and archive only when configured | `auto-resolve` | Completion state and summary |
197
198
  | COMPLETE-02 | `oat-project-complete` | Required documentation missing | Run document or explicitly skip | Run autonomous documentation; do not silently skip a required gate | `auto-resolve` / `boundary:repository-policy-approval` | Documentation state |
198
199
  | COMPLETE-03 | `oat-project-complete` | Unsatisfied completion gates | Continue anyway | Never continue silently; unresolved final review is a review boundary and other hard policies remain boundaries | `boundary:unresolved-critical-findings` / `boundary:repository-policy-approval` | Combined gate report |
@@ -193,6 +193,7 @@ remains.
193
193
  | PRFINAL-02 | `oat-project-pr-final` | Missing title/base | Ask for title and resolve base | Use the documented ticket/conventional-title and base-branch resolution chains | `auto-resolve` | PR artifact frontmatter and command |
194
194
  | PRFINAL-03 | `oat-project-pr-final` | Final review not passed | Ask whether to proceed anyway | Never proceed in autonomy; stop and route to final review/re-review | `boundary:unresolved-critical-findings` | Final review row and blocker report |
195
195
  | PRFINAL-04 | `oat-project-pr-final` | Push/PR policy or credentials | Ask operator to authorize or authenticate | Stop when repository policy or missing credentials prevent push/PR creation | `boundary:repository-policy-approval` / `boundary:missing-credentials` | PR state and redacted command error |
196
+ | PRFINAL-05 | `oat-project-pr-final` | Unresolved review-ledger artifact path | Report the offending row and stop | Stop before push and PR creation; a `## Reviews` artifact path that does not resolve to a regular file inside the project is never auto-resolved, and repairing the row is the only route forward | `boundary:unresolved-critical-findings` | Offending ledger row (scope, type, artifact) |
196
197
  | COMPLETE-01 | `oat-project-complete` | Batched completion/archive/summary/PR choices | Confirm completion and choose optional actions | Confirm only after gates pass; honor explicit config, refresh missing/stale summary, avoid duplicate PR, and archive only when configured | `auto-resolve` | Completion state and summary |
197
198
  | COMPLETE-02 | `oat-project-complete` | Required documentation missing | Run document or explicitly skip | Run autonomous documentation; do not silently skip a required gate | `auto-resolve` / `boundary:repository-policy-approval` | Documentation state |
198
199
  | COMPLETE-03 | `oat-project-complete` | Unsatisfied completion gates | Continue anyway | Never continue silently; unresolved final review is a review boundary and other hard policies remain boundaries | `boundary:unresolved-critical-findings` / `boundary:repository-policy-approval` | Combined gate report |
@@ -193,6 +193,7 @@ remains.
193
193
  | PRFINAL-02 | `oat-project-pr-final` | Missing title/base | Ask for title and resolve base | Use the documented ticket/conventional-title and base-branch resolution chains | `auto-resolve` | PR artifact frontmatter and command |
194
194
  | PRFINAL-03 | `oat-project-pr-final` | Final review not passed | Ask whether to proceed anyway | Never proceed in autonomy; stop and route to final review/re-review | `boundary:unresolved-critical-findings` | Final review row and blocker report |
195
195
  | PRFINAL-04 | `oat-project-pr-final` | Push/PR policy or credentials | Ask operator to authorize or authenticate | Stop when repository policy or missing credentials prevent push/PR creation | `boundary:repository-policy-approval` / `boundary:missing-credentials` | PR state and redacted command error |
196
+ | PRFINAL-05 | `oat-project-pr-final` | Unresolved review-ledger artifact path | Report the offending row and stop | Stop before push and PR creation; a `## Reviews` artifact path that does not resolve to a regular file inside the project is never auto-resolved, and repairing the row is the only route forward | `boundary:unresolved-critical-findings` | Offending ledger row (scope, type, artifact) |
196
197
  | COMPLETE-01 | `oat-project-complete` | Batched completion/archive/summary/PR choices | Confirm completion and choose optional actions | Confirm only after gates pass; honor explicit config, refresh missing/stale summary, avoid duplicate PR, and archive only when configured | `auto-resolve` | Completion state and summary |
197
198
  | COMPLETE-02 | `oat-project-complete` | Required documentation missing | Run document or explicitly skip | Run autonomous documentation; do not silently skip a required gate | `auto-resolve` / `boundary:repository-policy-approval` | Documentation state |
198
199
  | COMPLETE-03 | `oat-project-complete` | Unsatisfied completion gates | Continue anyway | Never continue silently; unresolved final review is a review boundary and other hard policies remain boundaries | `boundary:unresolved-critical-findings` / `boundary:repository-policy-approval` | Combined gate report |
@@ -193,6 +193,7 @@ remains.
193
193
  | PRFINAL-02 | `oat-project-pr-final` | Missing title/base | Ask for title and resolve base | Use the documented ticket/conventional-title and base-branch resolution chains | `auto-resolve` | PR artifact frontmatter and command |
194
194
  | PRFINAL-03 | `oat-project-pr-final` | Final review not passed | Ask whether to proceed anyway | Never proceed in autonomy; stop and route to final review/re-review | `boundary:unresolved-critical-findings` | Final review row and blocker report |
195
195
  | PRFINAL-04 | `oat-project-pr-final` | Push/PR policy or credentials | Ask operator to authorize or authenticate | Stop when repository policy or missing credentials prevent push/PR creation | `boundary:repository-policy-approval` / `boundary:missing-credentials` | PR state and redacted command error |
196
+ | PRFINAL-05 | `oat-project-pr-final` | Unresolved review-ledger artifact path | Report the offending row and stop | Stop before push and PR creation; a `## Reviews` artifact path that does not resolve to a regular file inside the project is never auto-resolved, and repairing the row is the only route forward | `boundary:unresolved-critical-findings` | Offending ledger row (scope, type, artifact) |
196
197
  | COMPLETE-01 | `oat-project-complete` | Batched completion/archive/summary/PR choices | Confirm completion and choose optional actions | Confirm only after gates pass; honor explicit config, refresh missing/stale summary, avoid duplicate PR, and archive only when configured | `auto-resolve` | Completion state and summary |
197
198
  | COMPLETE-02 | `oat-project-complete` | Required documentation missing | Run document or explicitly skip | Run autonomous documentation; do not silently skip a required gate | `auto-resolve` / `boundary:repository-policy-approval` | Documentation state |
198
199
  | COMPLETE-03 | `oat-project-complete` | Unsatisfied completion gates | Continue anyway | Never continue silently; unresolved final review is a review boundary and other hard policies remain boundaries | `boundary:unresolved-critical-findings` / `boundary:repository-policy-approval` | Combined gate report |