@awebai/oats 0.22.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 (112) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +380 -0
  3. package/bin/oats.mjs +3294 -0
  4. package/capabilities/oats-authoring/oats.json +12 -0
  5. package/capabilities/oats-aweb/bin/oats-aweb.mjs +297 -0
  6. package/capabilities/oats-aweb/injects/aweb.md +55 -0
  7. package/capabilities/oats-aweb/oats.json +47 -0
  8. package/capabilities/oats-aweb/package.json +20 -0
  9. package/capabilities/oats-jira/bin/oats-jira.mjs +40 -0
  10. package/capabilities/oats-jira/injects/jira.md +10 -0
  11. package/capabilities/oats-jira/oats.json +22 -0
  12. package/capabilities/oats-jira/package.json +25 -0
  13. package/capabilities/oats-jira/skills/jira-tasks/SKILL.md +176 -0
  14. package/capabilities/oats-linear/README.md +234 -0
  15. package/capabilities/oats-linear/bin/oats-linear-hook.mjs +32 -0
  16. package/capabilities/oats-linear/bin/oats-linear.mjs +344 -0
  17. package/capabilities/oats-linear/injects/linear.md +8 -0
  18. package/capabilities/oats-linear/oats.json +24 -0
  19. package/capabilities/oats-linear/package.json +29 -0
  20. package/capabilities/oats-linear/skills/linear-tasks/SKILL.md +217 -0
  21. package/capabilities/oats-linear/test/oats-linear.test.mjs +168 -0
  22. package/capabilities/oats-okf/agents/memory-harvest.md +25 -0
  23. package/capabilities/oats-okf/bin/oats-okf.mjs +283 -0
  24. package/capabilities/oats-okf/injects/okf.md +62 -0
  25. package/capabilities/oats-okf/oats.json +20 -0
  26. package/capabilities/oats-okf/package.json +22 -0
  27. package/capabilities/oats-okf/skills/memory-harvest/SKILL.md +100 -0
  28. package/capabilities/oats-okf/skills/okf/SKILL.md +107 -0
  29. package/capabilities/oats-okf/skills/okf/scripts/okf-validate.mjs +123 -0
  30. package/capabilities/oats-review/agents/reviewer/AGENTS.md +53 -0
  31. package/capabilities/oats-review/agents/reviewer/soul.yaml +6 -0
  32. package/capabilities/oats-review/injects/review.md +68 -0
  33. package/capabilities/oats-review/oats.json +10 -0
  34. package/capabilities/oats-review/skills/code-review/SKILL.md +44 -0
  35. package/capabilities/oats-review/skills/security-review/SKILL.md +59 -0
  36. package/docs/capabilities.md +505 -0
  37. package/docs/capability-manifest.schema.json +223 -0
  38. package/docs/configuration.md +482 -0
  39. package/docs/conventions.md +73 -0
  40. package/docs/design/desktop-ux-plan.md +362 -0
  41. package/docs/design/package-engine-contract.md +813 -0
  42. package/docs/design/package-runtime-api.md +414 -0
  43. package/docs/desktop-cli-api.md +89 -0
  44. package/docs/desktop-succession.md +51 -0
  45. package/docs/desktop.md +187 -0
  46. package/docs/implementation.md +282 -0
  47. package/docs/integrations.md +123 -0
  48. package/docs/knowledge-theory.md +97 -0
  49. package/docs/knowledge.md +139 -0
  50. package/docs/layers.md +110 -0
  51. package/docs/migration-from-oas.md +122 -0
  52. package/docs/oats-config.schema.json +140 -0
  53. package/docs/oats-lock.schema.json +175 -0
  54. package/docs/oats-package.schema.json +129 -0
  55. package/docs/packages.md +442 -0
  56. package/docs/release-lane.md +132 -0
  57. package/docs/release-notes/v0.18.2.md +79 -0
  58. package/docs/release-notes/v0.18.3.md +63 -0
  59. package/docs/release-notes/v0.18.4.md +65 -0
  60. package/docs/release-notes/v0.18.5.md +66 -0
  61. package/docs/release-notes/v0.18.6.md +87 -0
  62. package/docs/release-notes/v0.19.0.md +186 -0
  63. package/docs/release-notes/v0.19.1.md +24 -0
  64. package/docs/release-notes/v0.19.2.md +32 -0
  65. package/docs/release-notes/v0.19.3.md +16 -0
  66. package/docs/release-notes/v0.19.4.md +12 -0
  67. package/docs/release-notes/v0.20.0.md +89 -0
  68. package/docs/release-notes/v0.22.0.md +180 -0
  69. package/docs/souls-and-instances.md +344 -0
  70. package/injects/framework-workspace.md +7 -0
  71. package/injects/instance-boundary.md +43 -0
  72. package/injects/local-soul.md +19 -0
  73. package/injects/oats.md +11 -0
  74. package/injects/work-attached.md +16 -0
  75. package/injects/work-checkout.md +12 -0
  76. package/injects/work-workspace.md +22 -0
  77. package/injects/work-worktree.md +13 -0
  78. package/lib/core.mjs +6792 -0
  79. package/lib/packages.mjs +1375 -0
  80. package/lib/tmux-config.mjs +35 -0
  81. package/package-catalog.json +44 -0
  82. package/package.json +55 -0
  83. package/packages/record/README.md +151 -0
  84. package/packages/record/bin/capture.mjs +256 -0
  85. package/packages/record/bin/recall.mjs +102 -0
  86. package/packages/record/bin/setup.mjs +281 -0
  87. package/packages/record/bin/turn-record.mjs +47 -0
  88. package/packages/record/docs/turn-record-sot.md +350 -0
  89. package/packages/record/lib/canonical.mjs +151 -0
  90. package/packages/record/lib/capture-aw.mjs +179 -0
  91. package/packages/record/lib/capture-cc.mjs +322 -0
  92. package/packages/record/lib/formats.mjs +296 -0
  93. package/packages/record/lib/ignore.mjs +155 -0
  94. package/packages/record/lib/index-db.mjs +524 -0
  95. package/packages/record/lib/project-aweb.mjs +251 -0
  96. package/packages/record/lib/segments.mjs +186 -0
  97. package/packages/record/lib/store.mjs +447 -0
  98. package/packages/record/lib/tags.mjs +114 -0
  99. package/packages/record/package.json +45 -0
  100. package/packages/record/test/vectors/README.md +34 -0
  101. package/packages/record/test/vectors/aweb-projection-v1.json +231 -0
  102. package/packages/record/test/vectors/journal-merge-v1.json +261 -0
  103. package/packages/record/test/vectors/turn-id-v1.json +152 -0
  104. package/packages/record/test/vectors/validate.mjs +391 -0
  105. package/skills/integration-authoring/SKILL.md +76 -0
  106. package/skills/oats/SKILL.md +151 -0
  107. package/skills/oats-config/SKILL.md +162 -0
  108. package/skills/oats-getting-started/SKILL.md +159 -0
  109. package/skills/oats-packages/SKILL.md +180 -0
  110. package/skills/oats-support/SKILL.md +79 -0
  111. package/skills/skill-craft/SKILL.md +109 -0
  112. package/skills/soul-craft/SKILL.md +109 -0
@@ -0,0 +1,442 @@
1
+ # Distribution packages — capabilities, config templates, and host requirements
2
+
3
+ An **OATS distribution package** is the acquire, update, and review unit above
4
+ capabilities. It is *transport*, not the installed entity. A package is one
5
+ `oats-package.json` at a package root that declares one or more **capabilities**
6
+ and, optionally, one or more reference **config templates**.
7
+
8
+ Acquisition stages the package in a temporary transaction directory, validates
9
+ the whole selected payload, **materializes each declared capability** into
10
+ `.agents/capabilities/installed/<id>/`, writes the exact lock, and discards the
11
+ staging directory. There is no persistent package store. The engine side
12
+ (acquisition, materialization, lock, per-capability trust) has its own contract
13
+ in [`design/package-engine-contract.md`](design/package-engine-contract.md);
14
+ this document covers the config side — adopting templates, whole-workspace
15
+ reconciliation, and consented host-requirement installs.
16
+
17
+ A Git repository **contains** a package rather than being one. Which directory
18
+ holds it is part of the source contract:
19
+
20
+ ```bash
21
+ oats install git:github.com/org/repo@v1.0.0 # → repo's oats-package/ (the DEFAULT)
22
+ oats install git:github.com/org/repo@v1.0.0#dist/oats # → repo's dist/oats/
23
+ oats install git:github.com/org/repo@v1.0.0#. # → the repository ROOT
24
+ oats install /repo/custom-root # local: that EXACT directory
25
+ ```
26
+
27
+ Official examples, scaffolds, and conventions use `oats-package/`. Catalog
28
+ entries carry their own `path`. Local paths take no fragment and never apply the
29
+ default. Only the selected subtree is installed and hashed, so repository docs,
30
+ CI configuration, owner souls, and sibling packages stay outside the package's
31
+ payload and integrity. One repository may ship several packages at different
32
+ paths. The lock pins the selected root in its own `path` field, and only an
33
+ explicit `oats update <package>` may move it. See
34
+ [`design/package-engine-contract.md` §1.1](design/package-engine-contract.md).
35
+
36
+ Ground truth for the contract: [`oats-package.schema.json`](oats-package.schema.json),
37
+ [`oats-lock.schema.json`](oats-lock.schema.json), and
38
+ [`design/package-engine-contract.md`](design/package-engine-contract.md).
39
+
40
+ ## Package is transport; capability is the installed entity
41
+
42
+ Installing a package materializes **every** capability it exports. Each installed
43
+ capability is a self-contained, independently hashable directory at
44
+ `.agents/capabilities/installed/<capability-id>/`, containing that capability's
45
+ own `oats.json`, skills, injections, commands, hooks, and any runtime closure.
46
+ That directory is where you inspect installed behavior, and it is the only thing
47
+ executable trust binds to.
48
+
49
+ Every package must export at least one capability. Config-only and empty
50
+ packages are rejected. A capability ID is unique at a scope, so two packages may
51
+ not both supply the same capability there.
52
+
53
+ ```text
54
+ <scope>/
55
+ oats-config.yaml # zero or one active config
56
+ oats-lock.json # committed provenance
57
+ .agents/
58
+ capabilities/
59
+ owned/<capability-id>/ # authored source; committed
60
+ installed/<capability-id>/ # materialized artifact; gitignored
61
+ config-templates/
62
+ adopted/<package-id>/<template-name>/
63
+ oats-config.yaml # the exact adopted base; commit-safe
64
+ adoption.json # source/version/commit/path/hash
65
+ ```
66
+
67
+ At a Git-backed scope, OATS keeps `.agents/capabilities/.gitignore` ignoring only
68
+ `installed/`. Authored `owned/` capabilities and everything under
69
+ `.agents/config-templates/adopted/` are meant to be reviewed and committed, so
70
+ they are never ignored. Non-Git scopes use the same layout without pretending
71
+ Git owns their durability.
72
+
73
+ ## Package config templates (`oats init --package`)
74
+
75
+ A **config template** is a complete reference `oats-config.yaml` a package ships,
76
+ named in `oats-package.json` under `configTemplates`. It is a recommended
77
+ starting point, not installed policy. Adopting one is explicit and always
78
+ separate from installing capabilities:
79
+
80
+ ```bash
81
+ oats init --package example.engineering # official catalog id (latest)
82
+ oats init --package example.engineering@1.2.0 # catalog id + pinned selector
83
+ oats init --package ../engineering-oats --config minimal # local path + named template
84
+ oats init --package https://example.invalid/pkg.git # git URL (default branch)
85
+ ```
86
+
87
+ `oats install <package>` never adopts a template — it materializes capabilities
88
+ and reports available templates as optional follow-ups. Only `oats init --package`
89
+ (and the guided `oats config adopt`) adopt one.
90
+
91
+ New packages ship templates under a `config-templates/` directory and name them
92
+ with the manifest's `configTemplates` map. Each package must also give every
93
+ capability a dedicated self-contained root. The legacy `configs` manifest
94
+ spelling and a `.` (package-root) capability root stay readable only so
95
+ already-published tags remain consumable — new authoring never emits them.
96
+
97
+ Behavior:
98
+
99
+ - **Preview and validation first.** The template must be valid against the
100
+ config schema. Every `from: installed` capability it references must be
101
+ supplied by the package or its dependency closure. Layer bindings must agree
102
+ with the capability manifests. Agent types must be syntactically valid. No
103
+ path — injection overrides, work-mode setup scripts — may escape the target
104
+ scope. A failing template is never written, and the scope is left untouched.
105
+ - **Default selection.** A template marked `"default": true` is chosen when
106
+ `--config` is omitted. A single template is chosen implicitly. Several
107
+ unmarked templates require `--config <name>`, and refusing to guess is the
108
+ point.
109
+ - **Overwrite refusal.** `oats init --package` refuses when an `oats-config.yaml`
110
+ already exists at the scope. Use `oats config adopt` to switch an existing
111
+ scope to another template.
112
+ - **The adopted base is recorded.** Adoption writes the exact template as a
113
+ commit-safe base under `.agents/config-templates/adopted/<package>/<template>/`,
114
+ alongside an `adoption.json` recording source, version, commit, path, and hash.
115
+ Commit it — `oats config diff` and `oats config sync` compare against it. For a
116
+ local `path:` source, `adoption.json` records `source: null` with
117
+ `localSource: true`, so no absolute machine path leaks into the committed
118
+ metadata; the exact source stays only in the authoritative lock.
119
+
120
+ ### Your config is yours (adopter sovereignty)
121
+
122
+ The adopted config is an **ordinary scoped config**. It is not live inheritance
123
+ and not ambient package policy. `oats use`, `oats type`, `oats inject eject`, and
124
+ hand edits keep their meaning, and package updates never rewrite it or the
125
+ adopted base. Every capability an installed package exports stays individually
126
+ addressable, so you may
127
+
128
+ - **retarget** a capability from global to an agent type or soul
129
+ (`oats use example.review --type reviewers`);
130
+ - **disable** something the template enabled
131
+ (`oats use example.review --global --disable`, or `knowledge: none` for a
132
+ layer);
133
+ - **re-set settings** per family (`oats use example.review --soul dev
134
+ --settings depth=high`);
135
+ - **replace** an exclusive-layer provider with another capability; and
136
+ - **override from a nested repository** — a closer repo's `oats-config.yaml`
137
+ wins per the normal cascade:
138
+
139
+ ```yaml
140
+ # member-repo/oats-config.yaml — this repo opts out of the workspace default
141
+ name: member
142
+ capabilities:
143
+ layers:
144
+ knowledge: none
145
+ ```
146
+
147
+ Nothing a package ships is mandatory. Every copied setting is fully locally
148
+ editable, and the resolved local config is always authoritative.
149
+
150
+ ### Guided template sync (`oats config diff | sync | adopt`)
151
+
152
+ Your config and a package's template drift as you edit locally and as the
153
+ package updates. Three commands manage that, and all three share one three-way
154
+ comparison — the recorded **adopted base**, your current local
155
+ `oats-config.yaml`, and the selected template read from the currently locked
156
+ package.
157
+
158
+ ```bash
159
+ oats config diff # report only; nothing is written
160
+ oats config sync # apply upstream changes; keep local edits
161
+ oats config sync --accept <id>=local # resolve one conflict region in favor of local
162
+ oats config sync --accept <id>=package # resolve one conflict region in favor of the template
163
+ oats config sync --reset --yes # discard local changes; take the template verbatim
164
+ oats config adopt other.package --config default # switch to a different base
165
+ ```
166
+
167
+ - **`oats config diff`** reports how your config, the adopted base, and the
168
+ package's current template differ. It classifies each region as
169
+ upstream-only, local-only, or a conflict, and writes nothing.
170
+ - **`oats config sync`** applies upstream-only changes and keeps local-only
171
+ edits. It presents the complete plan before touching anything, preserves the
172
+ untouched bytes, comments, order, and formatting of your file, and advances
173
+ the adopted base only after a successful write. A recoverable `.bak` backup
174
+ survives the run.
175
+ - **Conflicts require an explicit choice.** A region changed both locally and
176
+ upstream is a conflict. `oats config sync` never picks a side for you.
177
+ Interactively it prompts per region. Noninteractively (or with `--json`) it
178
+ fails with `E_SYNC_AMBIGUOUS` unless you pass `--accept <regionId>=local` or
179
+ `--accept <regionId>=package` for each one.
180
+ - **`oats config sync --reset`** is the exact-template replacement path. It
181
+ previews every local change region it will discard, backs up the current
182
+ config, then replaces both the config and the adopted-base metadata. It
183
+ demands strong confirmation interactively, and `--yes` to accept the loss
184
+ noninteractively.
185
+ - **`oats config adopt <package> --config <name>`** switches the one local config
186
+ to a different base. It rebases your config against the new template rather
187
+ than creating a second config, and exactly one adopted base remains afterward.
188
+
189
+ ## Workspace reconciliation (bare `oats install`)
190
+
191
+ At a config scope that declares `team:`, bare `oats install` reconciles the whole
192
+ workspace instead of only the ancestor chain:
193
+
194
+ 1. prints the chosen boundary **before any network or host work**;
195
+ 2. restores the boundary scope's locked graph;
196
+ 3. discovers descendant scopes containing `oats-config.yaml` or `oats-lock.json`,
197
+ in deterministic path order, pruning `.git`, generated stores (`.agents/`),
198
+ dependency/vendor directories (`node_modules`, `vendor`, virtualenvs), agent
199
+ instances/worktrees, `local-agents/`, **package payload** (below), and
200
+ **nested team boundaries** (each is its own reconciliation unit);
201
+ 4. restores each descendant scope once;
202
+ 5. validates that every config-referenced installed capability is supplied by a
203
+ visible locked package (or capability lock); and
204
+ 6. aggregates missing requirements and failures **by scope**.
205
+
206
+ **Package payload is never a scope.** A directory holding an `oats-package.json`
207
+ is a package root, and everything beneath it is content the package *exports* —
208
+ including the `configTemplates` files under `config-templates/`. Those templates
209
+ bind layers to capabilities the adopting deployment has not installed yet, so
210
+ reconciling one as a live scope would report phantom "supplied by no visible
211
+ locked package" failures for the whole team. Discovery therefore excludes any
212
+ candidate whose containing **ancestor** directory carries an `oats-package.json`,
213
+ whatever the payload root is named — templates are never reconciled, validated,
214
+ or acquired. The rule is the manifest, not the path: a repository that ships a
215
+ package *and* is itself a deployment scope (its own `oats-config.yaml` at the
216
+ root, with the manifest in a subdirectory) stays a scope exactly as before.
217
+
218
+ At a non-team scope, bare `oats install` keeps current-chain behavior. Pass
219
+ `--recursive` to request descendant reconciliation outside a team boundary — the
220
+ boundary is still printed first. OATS never scans downward from the laptop/home
221
+ config by default.
222
+
223
+ ## Host requirements — a separate consent gate
224
+
225
+ A capability `requires` entry may declare structured, platform-aware install
226
+ methods (the legacy `install: "https://…"` docs URL still works):
227
+
228
+ ```json
229
+ {
230
+ "command": "example-cli",
231
+ "why": "send and receive team messages",
232
+ "install": {
233
+ "docs": "https://example.invalid/install",
234
+ "methods": [
235
+ { "platform": "darwin", "manager": "npm-global", "package": "@example/cli@1.2.3" }
236
+ ]
237
+ }
238
+ }
239
+ ```
240
+
241
+ Rules (all enforced):
242
+
243
+ - **Allowlisted managers only**: `npm-global` and `brew`
244
+ (download-with-checksum is declared but not implemented yet). Recipes are
245
+ data — argv arrays, never shell snippets, no sudo, no shell metacharacters, no
246
+ authentication.
247
+ - **Informed, per-requirement consent.** Interactive `oats install` shows the
248
+ exact command, source, version, and whether it changes user- or machine-level
249
+ state, then asks per requirement. A plan may take more than one command — a
250
+ runtime package can need its source registered first — so both the human and
251
+ `--json` renderings carry `steps`, the ordered argv sequence that will run,
252
+ alongside `argv` (its final command). What you consent to is the whole
253
+ sequence. Nothing runs that the plan did not show.
254
+ - **Aggregation is scoped**: only capabilities *activated somewhere in the
255
+ reconciled scopes* are considered, deduplicated by required command, and the
256
+ report names which capabilities requested each command.
257
+ - **Noninteractive runs never install by default.** Automation names each
258
+ accepted requirement: `oats install --accept-requirement example-cli`.
259
+ `--no-requirements` restores packages only (CI). A **consented** install that
260
+ fails (manager error, or the command still absent from PATH) makes
261
+ `oats install` exit nonzero so automation can detect it. Unaccepted or skipped
262
+ requirements stay non-fatal.
263
+ - **PATH verification** runs after each install. A tool that does not land on
264
+ PATH is reported honestly.
265
+ - **Skipping is safe**: `oats doctor` keeps an actionable warning (the consent
266
+ command to run) until the command is on PATH.
267
+ - **Trust and requirement consent are distinct gates.** Installing a binary
268
+ neither activates nor approves any capability, and capability trust never
269
+ authorizes host installs.
270
+
271
+ When no safe recipe matches the host, OATS prints the documented install URL.
272
+
273
+ ## Lock, trust, and restore
274
+
275
+ The scope's `oats-lock.json` uses `lockfileVersion: 2` and records both levels of
276
+ the model in separate top-level maps:
277
+
278
+ ```json
279
+ {
280
+ "lockfileVersion": 2,
281
+ "packages": {
282
+ "example.engineering": {
283
+ "source": "git:https://example.invalid/engineering.git@v3.0.0",
284
+ "version": "3.0.0",
285
+ "commit": "0123456789abcdef0123456789abcdef01234567",
286
+ "path": "oats-package",
287
+ "integrity": "sha256-…",
288
+ "dependencies": []
289
+ }
290
+ },
291
+ "capabilities": {
292
+ "example.review": {
293
+ "version": "2.1.0",
294
+ "package": "example.engineering",
295
+ "path": "capabilities/example-review",
296
+ "integrity": "sha256-…",
297
+ "trusted": false
298
+ }
299
+ }
300
+ }
301
+ ```
302
+
303
+ - The `packages` map proves **where the bytes came from** — exact source,
304
+ commit, selected root path, payload integrity, and package-identity
305
+ dependencies. It does not describe an installed directory, because there is no
306
+ persistent package store.
307
+ - The `capabilities` map proves **each materialized artifact** — its version,
308
+ its provider package (a key of the `packages` map), its dedicated root path
309
+ inside that package, its artifact integrity, and its executable trust.
310
+ - **Trust binds to the capability artifact integrity, never to package
311
+ identity.** `oats trust <capability>` approves that capability's commands and
312
+ hooks at exactly its current artifact integrity. Any integrity change,
313
+ including `oats update`, resets `trusted` to false and forces re-review.
314
+ Official catalog identity grants no executable trust, and there is no
315
+ package-level approval.
316
+ - Bare `oats install` fetches the exact locked source, verifies package
317
+ integrity, re-materializes any missing capability artifact, verifies its
318
+ individual integrity, and never advances source, version, or commit.
319
+
320
+ ## Upgrading a 0.18 deployment to the official packages
321
+
322
+ Deployments created before official packages existed hold ordinary
323
+ `oats-config.yaml` files, **v1** `oats-lock.json` files, and acquired capability
324
+ artifacts under `.agents/capabilities/installed/`. Those keep working. A valid
325
+ v1 lock still restores, activates, trusts, and spawns, and installing this
326
+ release migrates nothing on its own.
327
+
328
+ The upgrade is one explicit, guided command, and it lands directly in the
329
+ revised `lockfileVersion: 2`:
330
+
331
+ ```bash
332
+ oats migrate --official --recursive --dry-run --dir <team-root> # plan first
333
+ oats migrate --official --recursive --dir <team-root> # apply
334
+ ```
335
+
336
+ - **Scope discovery** is deterministic and covers every *visible* lock-owning
337
+ scope: the explicit scope's ancestor chain (so an outer repo/laptop lock the
338
+ deployment actually reads is migrated too), the team boundary, and descendant
339
+ config/lock scopes found with reconciliation's pruning (nested team boundaries
340
+ stay self-owned). Scopes are planned and applied in path order, ancestors
341
+ first. Without `--recursive` only the named scope is migrated.
342
+ - **Plan first, always.** The complete per-scope plan is printed (and available
343
+ as stable JSON) before anything is applied. `--dry-run` stops after it.
344
+ - **Which package supplies which capability is catalog data**, never code. The
345
+ catalog maps identity by default (capability `oats.okf` → package `oats.okf`)
346
+ and carries explicit aliases for capabilities a package exports under another
347
+ identity (`oats.review` → package `oats.dev`). See the catalog shape below.
348
+ - **Config files are not rewritten.** Packages export the same capability IDs,
349
+ so activation, layer bindings, targets, settings, exclusions, and injection
350
+ overrides remain valid byte-for-byte.
351
+ - **Held, never half-converted.** If any official capability cannot map, the
352
+ whole scope stays byte-identical v1 and the run is nonzero. A `--dry-run`
353
+ reports the same blocked status, so readiness cannot be mistaken for success.
354
+ - **Custom entries block a mixed guided scope.** `git:`/`path:`/unknown v1
355
+ sources are never acquired by `--official`. A scope containing only those
356
+ entries is skipped and reports their IDs under `retained`; a scope mixing them
357
+ with official capabilities is refused before any write. Plain `oats migrate`
358
+ can convert custom sources only when every entry in the scope maps to a
359
+ package. There is no residue container.
360
+ - **One package, several capabilities.** When catalog aliases map more than one
361
+ legacy capability onto the same package, all of them convert together and the
362
+ package is acquired once.
363
+ - **Per scope transactional.** Each scope acquires its package closure, writes
364
+ a fresh revised v2 lock, and only then removes the superseded v1 artifacts. A
365
+ failing scope is rolled back byte-identically. Other scopes keep their
366
+ (truthfully reported) result, and the aggregate exit is nonzero.
367
+ - **Trust is re-earned, never transferred.** A capability's materialized
368
+ integrity is not its v1 artifact's integrity, so approvals do not carry over.
369
+ The run prints the exact `oats trust <capability> --dir <scope>` commands, then
370
+ the bare `oats install --dir <scope>` pass (already-installed host requirements
371
+ verify and are not reinstalled; anything missing gets its
372
+ `oats install --accept-requirement <cmd>` consent command).
373
+
374
+ Rerunning the command after a successful migration changes nothing.
375
+
376
+ ### The transitional v2 lock is not migrated
377
+
378
+ An earlier, unreleased shape of `lockfileVersion: 2` stored capability lists and
379
+ trust on the package rows and used a persistent `.agents/packages/installed/`
380
+ store. That transitional shape receives no product migration path. The reader
381
+ rejects it centrally as `invalid-lock` with actionable guidance. It is recreated
382
+ by a fresh acquisition, never converted or partially interpreted. There is no
383
+ `lockfileVersion: 3`. Because the transitional contract had no external
384
+ adoption, the founder chose to replace it in place rather than carry a migration
385
+ for it.
386
+
387
+ ### Catalog shape
388
+
389
+ The official catalog is data (`package-catalog.json`, or the file named by
390
+ `OATS_PACKAGE_CATALOG`):
391
+
392
+ ```json
393
+ {
394
+ "packages": {
395
+ "oats.okf": { "url": "https://github.com/awebai/oats-okf.git", "ref": "v1.4.1", "path": "oats-package" },
396
+ "oats.dev": { "url": "https://github.com/awebai/oats-dev.git", "ref": "v1.0.0", "path": "oats-package" }
397
+ },
398
+ "capabilities": { "oats.review": "oats.dev" }
399
+ }
400
+ ```
401
+
402
+ `packages` is identity and discovery only — resolving through it never advances
403
+ a lock and never grants executable trust. The released kernel bundles the
404
+ official awebai entries. Once a short id appears there, `oats install <id>`
405
+ prefers the distribution package over the legacy bundled capability marketplace.
406
+ Existing v1 locks and artifacts remain supported until you run guided migration.
407
+ `capabilities` is the legacy-capability → package alias map the guided migration
408
+ reads; identity mappings need no entry. An alias value may also be spelled
409
+ `{ "package": "<id>" }`.
410
+
411
+ ## Doctor
412
+
413
+ `oats doctor` reports, in addition to its capability diagnostics:
414
+
415
+ - **Distribution packages** visible in the lock (`packages:` in
416
+ `oats-lock.json`), with source and the capabilities each supplies;
417
+ - **adopted config templates** in the chain — the package and template each
418
+ scope adopted, its recorded base, and whether local changes have drifted from
419
+ it;
420
+ - **available-but-unadopted templates** — a locked, installed package exporting
421
+ config templates that no scope has adopted;
422
+ - **missing host commands** for active capabilities, with the exact consent
423
+ command when a safe installer exists;
424
+ - **official capability migration** (`officialMigration` in `--json`) when the
425
+ chain still holds legacy `marketplace:` locks: each capability with the
426
+ package that supplies it, and either `ready` with the exact
427
+ `oats migrate --official --recursive --dir <boundary>` command, or `unavailable`
428
+ with the reason — the catalog has no mapping yet and the legacy capabilities
429
+ remain supported.
430
+
431
+ ## Engine integration
432
+
433
+ The package engine (acquisition, capability materialization, revised v2 lock,
434
+ exact restore, capability indexing, per-capability trust — see
435
+ [`design/package-engine-contract.md`](design/package-engine-contract.md) and
436
+ [`design/package-runtime-api.md`](design/package-runtime-api.md)) is merged.
437
+ `oats init --package` acquires and exact-locks the full closure through the
438
+ engine's `acquirePackage` for every source kind (git, catalog, local path), then
439
+ adopts exactly one template. The team-boundary reconciliation above wraps the
440
+ engine's exact-restore primitive (integrity, capability, and runtime-closure
441
+ verification) per scope. Legacy v1 capability locks keep restoring via the
442
+ capability path and are reported as LEGACY with the `oats migrate` pointer.
@@ -0,0 +1,132 @@
1
+ # The runnerless release lane
2
+
3
+ `scripts/release-lane.mjs` releases OATS without GitHub Actions. It is the
4
+ same release as [`.github/workflows/release.yml`](../.github/workflows/release.yml),
5
+ run phase by phase on operator machines, with every output written under a
6
+ stage directory so the release can stop and resume at any phase.
7
+
8
+ The policy it satisfies: no release capability may permanently depend on
9
+ GitHub or GitHub Actions. Registry publish works on its own; tags and hosted
10
+ release assets can follow later.
11
+
12
+ ## When to use it
13
+
14
+ - **Runner outage.** GitHub Actions is down, queued, or a runner image has
15
+ broken under the workflow. Build and publish here; push the tag and let the
16
+ workflow catch up when it can.
17
+ - **Urgent release.** The kernel fix must reach npm now. `build` and
18
+ `publish-npm` are enough for that; Desktop installers and the GitHub Release
19
+ follow when they are ready.
20
+ - **By choice.** Any release may be cut this way. The gates are the workflow's
21
+ gates; only the host differs.
22
+
23
+ ## Phases
24
+
25
+ Every phase takes `--tag vX.Y.Z` and reads or writes `stage/<tag>/`
26
+ (gitignored; `--stage <dir>` overrides). `MANIFEST.json` there records the
27
+ SHA, the tarballs and their digests, the assets, and which phases completed.
28
+ Every external command is printed before it runs and its output is logged
29
+ under `stage/<tag>/logs/`; a failing step exits non-zero with the log path.
30
+
31
+ | Phase | Mirrors in `release.yml` | Writes |
32
+ | --- | --- | --- |
33
+ | `build --tag vX.Y.Z [--sha <commit>]` | job `build-and-test`: notes gate, three-manifest bump, `node --check`, `npm ci`, `npm run check`, Desktop test deps, `npm test`, `pack:check` and the tarball greps, `smoke:tarball`, the `version --json` probe | `npm/*.tgz`, `MANIFEST.json` |
34
+ | `desktop --tag vX.Y.Z --arch arm64\|x64` | one `desktop-build` matrix leg: desktop `npm ci`, `npm test`, `npm run dist -- --<arch>`, strict deep `codesign --verify` (macOS), `dist:smoke` in build-verify mode | `assets/oats-desktop-*` |
35
+ | `stage --tag vX.Y.Z` | publish job, "Checksums" (`shasum -a 256`) | `assets/SHA256SUMS.txt` |
36
+ | `publish-npm --tag vX.Y.Z [--dry-run] --yes` | publish job, the two guarded `npm publish --access public` steps, kernel then adapter | — |
37
+ | `tag --tag vX.Y.Z [--push --yes]` | the tag push that triggers the workflow | annotated tag |
38
+ | `release-github --tag vX.Y.Z --yes` | publish job, `gh release create` / `gh release upload --clobber` | GitHub Release |
39
+ | `status --tag vX.Y.Z` | — | prints what ran, what exists, what remains |
40
+
41
+ `build` refuses on a dirty working tree and, like the workflow, refuses a SHA
42
+ that is not on `origin/main` (`--allow-off-main` is the explicit human
43
+ override; report the risk you accepted). It never touches the checkout it
44
+ runs from: it exports the SHA into a detached worktree under the system
45
+ temporary directory (recorded in `MANIFEST.json`, `--export <dir>` overrides)
46
+ and runs every build step there. The bumped manifests exist only in that
47
+ export; the version-bump commit to `main` remains the workflow's job, or a
48
+ manual PR.
49
+
50
+ `publish-npm` and `release-github` print their plan and refuse without
51
+ `--yes`. `tag` creates the local tag without `--yes` but pushes only with
52
+ `--push --yes`. Authentication for npm is whatever `npm whoami` reports, or
53
+ `NPM_TOKEN` when set: the token goes into a temporary `.npmrc` handed to npm
54
+ through `NPM_CONFIG_USERCONFIG` and deleted afterwards, never into the repo.
55
+
56
+ ## A full release from a Mac plus a Linux host
57
+
58
+ Release notes must exist at `docs/release-notes/<tag>.md` on the commit being
59
+ released, and the commit must be on `origin/main`. On the Mac:
60
+
61
+ ```bash
62
+ git fetch origin
63
+ node scripts/release-lane.mjs build --tag v0.22.0 # minutes
64
+ node scripts/release-lane.mjs desktop --tag v0.22.0 --arch arm64
65
+ node scripts/release-lane.mjs desktop --tag v0.22.0 --arch x64 # needs Rosetta on an arm64 Mac
66
+ node scripts/release-lane.mjs status --tag v0.22.0
67
+ ```
68
+
69
+ On the Linux host, from a checkout of the same commit:
70
+
71
+ ```bash
72
+ node scripts/release-lane.mjs build --tag v0.22.0
73
+ node scripts/release-lane.mjs desktop --tag v0.22.0 --arch x64
74
+ # then copy stage/v0.22.0/assets/oats-desktop-*-linux-x64.* back to the Mac's stage/v0.22.0/assets/
75
+ ```
76
+
77
+ The Linux `build` repeats the kernel checks on that host; its tarballs are
78
+ not used. Only the assets travel. Back on the Mac:
79
+
80
+ ```bash
81
+ node scripts/release-lane.mjs stage --tag v0.22.0 # SHA256SUMS.txt over all six assets
82
+ node scripts/release-lane.mjs publish-npm --tag v0.22.0 --dry-run --yes
83
+ node scripts/release-lane.mjs publish-npm --tag v0.22.0 --yes # kernel, then adapter
84
+ node scripts/release-lane.mjs tag --tag v0.22.0 --push --yes
85
+ node scripts/release-lane.mjs release-github --tag v0.22.0 --yes
86
+ ```
87
+
88
+ An urgent kernel-only release is `build`, `publish-npm --yes`, and `tag --push
89
+ --yes`; the Desktop legs, `stage`, and `release-github` run later against the
90
+ same stage directory.
91
+
92
+ ## What is resumable
93
+
94
+ Everything after `build` reads `MANIFEST.json` and the files already staged:
95
+
96
+ - A failed step is rerun by rerunning its phase. `build` is build-once: it
97
+ recreates the export and the tarballs; it refuses a stage directory built
98
+ from a different SHA unless `--force`.
99
+ - `desktop` legs run in any order, on any number of hosts, days apart. A
100
+ missing export is recreated from the recorded SHA.
101
+ - `stage` recomputes the checksums over whatever is in `assets/` and lists
102
+ the legs still missing.
103
+ - `publish-npm` skips any version `npm view` already reports live, exactly as
104
+ the workflow does on a same-tag retry, so it can be rerun after a partial
105
+ failure or after the workflow published one of the two.
106
+ - `release-github` uploads with `--clobber` when the release exists.
107
+
108
+ ## What the lane cannot produce
109
+
110
+ - **Build-provenance attestations.** `actions/attest-build-provenance` and
111
+ npm's provenance both require the GitHub OIDC identity; nothing off-runner
112
+ can mint them. A lane-published npm version has no provenance badge, and a
113
+ lane-created GitHub Release has no attestation. Pushing the tag afterwards
114
+ runs `release.yml`, whose steps are idempotent: it skips the live npm
115
+ versions, re-uploads the same assets, and attaches the attestations. That
116
+ later pass is the way to add provenance; nothing is republished.
117
+ - **The version-bump PR.** The workflow's final step; open it by hand if the
118
+ workflow does not run.
119
+ - **Legs for hosts you do not have.** The Linux AppImage/DEB need a Linux
120
+ host; the lane says so and `stage` lists what is missing.
121
+
122
+ ## How it relates to `release.yml`
123
+
124
+ `release.yml` is unchanged and remains the default path: pushing a tag runs
125
+ it end to end. The lane mirrors its jobs and steps rather than reimplementing
126
+ their checks — it calls the same `npm run check`, `npm test`, `pack:check`,
127
+ `smoke:tarball`, `dist`, and `dist:smoke` scripts with the same environment
128
+ the workflow sets. `test/release-workflow.test.mjs` pins the workflow's
129
+ contract; `test/release-lane.test.mjs` covers the lane's gates and phase
130
+ logic against fixtures, with `npm` stubbed. The two can run in either order:
131
+ a lane release followed by a workflow run, or a broken workflow run finished
132
+ by the lane, and neither republishes what the other already did.
@@ -0,0 +1,79 @@
1
+ # OATS v0.18.2
2
+
3
+ One public release, built from one tag: `@awebai/oats@0.18.2`,
4
+ `@awebai/oats-pi@0.18.2`, and **OATS Desktop 0.18.2** (attached to this
5
+ GitHub Release).
6
+
7
+ ## OATS Desktop
8
+
9
+ The Desktop app is the control panel for OATS deployments: roster/hierarchy,
10
+ brain/markdown/task/state views, terminal attach to existing tmux windows,
11
+ and — with a compatible CLI installed — spawning agents from the Soul
12
+ roster.
13
+
14
+ Downloads (assets on this release):
15
+
16
+ | Platform | Artifacts |
17
+ | --- | --- |
18
+ | macOS arm64 (Apple Silicon) | DMG + ZIP |
19
+ | macOS x64 (Intel) | DMG + ZIP |
20
+ | Linux x64 | AppImage + DEB |
21
+
22
+ Verify with `SHA256SUMS.txt`; GitHub build-provenance attestations are
23
+ published for all assets.
24
+
25
+ **Windows and Linux arm64 are not supported in 0.18.2.**
26
+
27
+ The 0.18.2 installers are **unsigned and not notarized**. On macOS, open via
28
+ right-click → Open (or `xattr -dr com.apple.quarantine` the app) the first
29
+ time. On Linux, `tmux` is a prerequisite.
30
+
31
+ ### CLI compatibility
32
+
33
+ Desktop 0.18 requires an `oats` CLI with Desktop API v1: version
34
+ `>=0.18.0 <0.19.0`. Install or update:
35
+
36
+ ```bash
37
+ npm install -g @awebai/oats@0.18.2
38
+ ```
39
+
40
+ Without a compatible CLI, Desktop remains usable read-only (roster, files,
41
+ existing terminals); Spawn is disabled with guidance to install the CLI
42
+ (memory harvest runs through the same CLI boundary in the backend; no
43
+ dedicated button in this release). The probe contract is documented in
44
+ `docs/desktop-cli-api.md`; the full install/migration/support guide is
45
+ [docs/desktop.md](https://github.com/awebai/oats/blob/main/docs/desktop.md).
46
+
47
+ ## Breaking changes (root package)
48
+
49
+ This release removes the legacy web/TUI panel surfaces. Removal was approved
50
+ after the operator confirmed there were no other legacy-panel users.
51
+
52
+ - **`oats.web` capability removed.** Deployments that still declare it get a
53
+ doctor-guided migration error: remove the `oats.web` entry from
54
+ `oats-config.yaml` (`capabilities.additive`) and from `oats-lock.json` at
55
+ that scope. `oats doctor`/`oats doctor --json` reports stale config entries,
56
+ stale locks (`retiredLocks`), and leftover installed artifacts
57
+ (`retiredArtifacts`) with the cleanup instruction.
58
+ - **`oats pane` removed.** The command now errors with a pointer to the
59
+ Desktop app.
60
+ - **`@awebai/oats/control-pane` export removed.** No replacement —
61
+ the Desktop app bundles its own server.
62
+
63
+ ## New in the CLI
64
+
65
+ - `oats version [--json]` — the Desktop API v1 probe:
66
+ `{"schemaVersion":1,"name":"@awebai/oats","version":"0.18.2","desktopApi":1}`.
67
+ - `oats spawn … --json` and `oats okf harvest --json` now emit the stable
68
+ Desktop API v1 envelope (`{"schemaVersion":1,"ok":…}`), with exactly one
69
+ JSON object on stdout and stable error codes. Non-JSON output is unchanged.
70
+
71
+ ## Migration
72
+
73
+ 1. Update the CLI everywhere: `npm install -g @awebai/oats@0.18.2`
74
+ (the pi bridge `@awebai/oats-pi` publishes in lockstep; restart pi
75
+ sessions).
76
+ 2. Run `oats doctor` at each workspace/repo scope and follow its guidance to
77
+ remove stale `oats.web` config entries, locks, and installed artifacts.
78
+ 3. Replace any `oats pane` / control-pane usage with the Desktop app
79
+ (download above).