@awebai/oats 0.24.12 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/oats.mjs +936 -2822
- package/docs/capabilities.md +136 -323
- package/docs/configuration.md +68 -533
- package/docs/design/2026-09-16-fresh-operator-walkthrough.md +19 -14
- package/docs/design/2026-09-16-portable-migration-evidence.md +2 -0
- package/docs/design/2026-09-16-portable-onboarding.md +4 -2
- package/docs/design/2026-09-20-redesign-program-board.md +1 -1
- package/docs/design/2026-09-20-workspace-and-portable-adoption-plan.md +2 -0
- package/docs/design/2026-09-23-simplified-workspace-model.md +711 -0
- package/docs/design/2026-09-23-workspace-module-contracts.md +309 -0
- package/docs/design/2026-09-23-workspace-v2-implementation-plan.md +65 -0
- package/docs/design/README.md +20 -8
- package/docs/design/operations-contract.md +1 -0
- package/docs/design/package-engine-contract.md +1 -1
- package/docs/design/package-runtime-api.md +1 -1
- package/docs/desktop-cli-api.md +386 -6
- package/docs/desktop-succession.md +3 -4
- package/docs/first-team.md +107 -224
- package/docs/implementation.md +6 -4
- package/docs/integrations.md +45 -44
- package/docs/knowledge-capability-authoring.md +10 -4
- package/docs/knowledge-migration.md +5 -4
- package/docs/knowledge-reference/package-craft.md +11 -3
- package/docs/knowledge.md +24 -8
- package/docs/layers.md +3 -3
- package/docs/oats-local.schema.json +50 -0
- package/docs/oats-membership.schema.json +23 -0
- package/docs/oats-workspace.schema.json +133 -48
- package/docs/official-marketplace.md +9 -6
- package/docs/packages.md +229 -440
- package/docs/rebuild-to-v2.md +233 -0
- package/docs/release-notes/v0.24.13.md +51 -0
- package/docs/release-notes/v0.25.0.md +99 -0
- package/docs/soul.schema.json +41 -68
- package/docs/souls-and-instances.md +175 -108
- package/docs/workspace-adoption.md +70 -345
- package/docs/workspaces.md +429 -119
- package/lib/core.mjs +419 -55
- package/lib/instance-resolution.mjs +312 -0
- package/lib/materialize.mjs +580 -0
- package/lib/packages.mjs +501 -1273
- package/lib/remote.mjs +639 -0
- package/lib/resolve.mjs +576 -0
- package/lib/schedule.mjs +194 -34
- package/lib/workspace.mjs +635 -0
- package/package.json +1 -1
- package/lib/portable-migration-artifacts.mjs +0 -135
- package/lib/portable-migration-evidence.mjs +0 -305
- package/lib/portable-migration-store.mjs +0 -199
- package/lib/portable-migration.mjs +0 -104
- package/lib/portable-onboarding-acceptance.mjs +0 -66
- package/lib/setup-expert-source.mjs +0 -100
package/docs/packages.md
CHANGED
|
@@ -1,478 +1,267 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Packages — the versioned tier
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
A **package** is a place to fetch capabilities from *with a version attached*.
|
|
4
|
+
It is one of the two kinds of capability source in the
|
|
5
|
+
[workspace model](workspaces.md); the other — a member repo — is never
|
|
6
|
+
versioned. Nothing is installed: a package is resolved to an exact commit by
|
|
7
|
+
`oats sync`, recorded in `oats-lock.json`, approved once per version, and
|
|
8
|
+
**copied whole into each instance at spawn** (`<home>/.oats/modules/<cap>/`).
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
Ground truth: [`oats-package.schema.json`](oats-package.schema.json) (the
|
|
11
|
+
package manifest), [`oats-lock-v3.schema.json`](oats-lock-v3.schema.json) (the
|
|
12
|
+
lock), and the module contract
|
|
13
|
+
[design/2026-09-23-workspace-module-contracts.md §4](design/2026-09-23-workspace-module-contracts.md).
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
the whole selected payload, **materializes each declared capability** into
|
|
14
|
-
`.agents/capabilities/installed/<id>/`, writes the exact lock, and discards the
|
|
15
|
-
staging directory. There is no persistent package store. The engine side
|
|
16
|
-
(acquisition, materialization, lock, per-capability trust) has its own contract
|
|
17
|
-
in [`design/package-engine-contract.md`](design/package-engine-contract.md);
|
|
18
|
-
this document covers the config side — adopting templates, whole-workspace
|
|
19
|
-
reconciliation, and consented host-requirement installs.
|
|
15
|
+
## What a package is
|
|
20
16
|
|
|
21
|
-
A Git repository **contains** a package
|
|
22
|
-
holds it is part of the source contract:
|
|
17
|
+
A Git repository **contains** a package at `oats-package/`:
|
|
23
18
|
|
|
24
|
-
```bash
|
|
25
|
-
oats install git:github.com/org/repo@v1.0.0 # → repo's oats-package/ (the DEFAULT)
|
|
26
|
-
oats install git:github.com/org/repo@v1.0.0#dist/oats # → repo's dist/oats/
|
|
27
|
-
oats install git:github.com/org/repo@v1.0.0#. # → the repository ROOT
|
|
28
|
-
oats install /repo/custom-root # local: that EXACT directory
|
|
29
19
|
```
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
selector (`catalog:oats.aweb@v1.8.0`) keeps that selector on a plain update;
|
|
39
|
-
to advance it to another published ref, give the spec or `--to`:
|
|
40
|
-
`oats update oats.aweb oats.aweb@v1.10.1` or `oats update oats.aweb --to v1.10.1`
|
|
41
|
-
(same transactional path, approvals invalidated, then `oats trust`). See
|
|
42
|
-
[`design/package-engine-contract.md` §1.1](design/package-engine-contract.md).
|
|
43
|
-
|
|
44
|
-
Ground truth for the contract: [`oats-package.schema.json`](oats-package.schema.json),
|
|
45
|
-
[`oats-lock.schema.json`](oats-lock.schema.json), and
|
|
46
|
-
[`design/package-engine-contract.md`](design/package-engine-contract.md).
|
|
47
|
-
|
|
48
|
-
## Package is transport; capability is the installed entity
|
|
49
|
-
|
|
50
|
-
Installing a package materializes **every** capability it exports. Each installed
|
|
51
|
-
capability is a self-contained, independently hashable directory at
|
|
52
|
-
`.agents/capabilities/installed/<capability-id>/`, containing that capability's
|
|
53
|
-
own `oats.json`, skills, injections, commands, hooks, and any runtime closure.
|
|
54
|
-
That directory is where you inspect installed behavior, and it is the only thing
|
|
55
|
-
executable trust binds to.
|
|
56
|
-
|
|
57
|
-
Every package must export at least one capability. Config-only and empty
|
|
58
|
-
packages are rejected. A capability ID is unique at a scope, so two packages may
|
|
59
|
-
not both supply the same capability there.
|
|
60
|
-
|
|
61
|
-
```text
|
|
62
|
-
<scope>/
|
|
63
|
-
oats-config.yaml # zero or one active config
|
|
64
|
-
oats-lock.json # committed provenance
|
|
65
|
-
.agents/
|
|
66
|
-
capabilities/
|
|
67
|
-
owned/<capability-id>/ # authored source; committed
|
|
68
|
-
installed/<capability-id>/ # materialized artifact; gitignored
|
|
69
|
-
config-templates/
|
|
70
|
-
adopted/<package-id>/<template-name>/
|
|
71
|
-
oats-config.yaml # the exact adopted base; commit-safe
|
|
72
|
-
adoption.json # source/version/commit/path/hash
|
|
20
|
+
<repo>/
|
|
21
|
+
└── oats-package/
|
|
22
|
+
├── oats-package.json # { "package": "acme.tools", "version": "0.4.0", "capabilities": ["capabilities/acme-lint", "capabilities/acme-deploy"] }
|
|
23
|
+
└── capabilities/
|
|
24
|
+
├── acme-lint/oats.json # ordinary capability manifests (docs/capabilities.md)
|
|
25
|
+
└── acme-deploy/
|
|
26
|
+
├── oats.json
|
|
27
|
+
└── bin/acme-deploy.mjs # an executable → approved once per version
|
|
73
28
|
```
|
|
74
29
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
30
|
+
`oats-package.json` must declare `package` and `capabilities` (a list of
|
|
31
|
+
directories relative to the package root, each holding an `oats.json`). A
|
|
32
|
+
directory entry need not equal the capability's name
|
|
33
|
+
(`capabilities/oats-okf` → capability `oats.okf`). A package declaring one
|
|
34
|
+
capability name twice, a listed directory without a manifest, or a manifest
|
|
35
|
+
without `capability` is `E_PACKAGE_MANIFEST`. Catalog entries may name another
|
|
36
|
+
`path` than `oats-package`; a `git:` ref always reads `oats-package/`.
|
|
80
37
|
|
|
81
|
-
##
|
|
38
|
+
## Declaring packages — two forms, in one place
|
|
82
39
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
starting point, not installed policy. Adopting one is explicit and always
|
|
86
|
-
separate from installing capabilities:
|
|
40
|
+
The workspace file's `packages:` map is the **only** list of versions in the
|
|
41
|
+
whole organisation:
|
|
87
42
|
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
oats
|
|
91
|
-
oats
|
|
92
|
-
|
|
43
|
+
```yaml
|
|
44
|
+
packages:
|
|
45
|
+
oats.framework: v1.1.3 # bare version → the official catalog
|
|
46
|
+
oats.okf: v2.1.3
|
|
47
|
+
acme.tools: git:github.com/acme/tools@v0.4.0 # direct ref: git:<repo>@<tag or full OID>
|
|
93
48
|
```
|
|
94
49
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
already exists at the scope. Use `oats config adopt` to switch an existing
|
|
119
|
-
scope to another template.
|
|
120
|
-
- **The adopted base is recorded.** Adoption writes the exact template as a
|
|
121
|
-
commit-safe base under `.agents/config-templates/adopted/<package>/<template>/`,
|
|
122
|
-
alongside an `adoption.json` recording source, version, commit, path, and hash.
|
|
123
|
-
Commit it — `oats config diff` and `oats config sync` compare against it. For a
|
|
124
|
-
local `path:` source, `adoption.json` records `source: null` with
|
|
125
|
-
`localSource: true`, so no absolute machine path leaks into the committed
|
|
126
|
-
metadata; the exact source stays only in the authoritative lock.
|
|
127
|
-
|
|
128
|
-
### Your config is yours (adopter sovereignty)
|
|
129
|
-
|
|
130
|
-
The adopted config is an **ordinary scoped config**. It is not live inheritance
|
|
131
|
-
and not ambient package policy. `oats use`, `oats type`, `oats inject eject`, and
|
|
132
|
-
hand edits keep their meaning, and package updates never rewrite it or the
|
|
133
|
-
adopted base. Every capability an installed package exports stays individually
|
|
134
|
-
addressable, so you may
|
|
135
|
-
|
|
136
|
-
- **retarget** a capability from global to an agent type or soul
|
|
137
|
-
(`oats use example.review --type reviewers`);
|
|
138
|
-
- **disable** something the template enabled
|
|
139
|
-
(`oats use example.review --global --disable`, or `knowledge: none` for a
|
|
140
|
-
layer);
|
|
141
|
-
- **re-set settings** per family (`oats use example.review --soul dev
|
|
142
|
-
--settings depth=high`);
|
|
143
|
-
- **replace** an exclusive-layer provider with another capability; and
|
|
144
|
-
- **override from a nested repository** — a closer repo's `oats-config.yaml`
|
|
145
|
-
wins per the normal cascade:
|
|
146
|
-
|
|
147
|
-
```yaml
|
|
148
|
-
# member-repo/oats-config.yaml — this repo opts out of the workspace default
|
|
149
|
-
name: member
|
|
150
|
-
capabilities:
|
|
151
|
-
layers:
|
|
152
|
-
knowledge: none
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
Nothing a package ships is mandatory. Every copied setting is fully locally
|
|
156
|
-
editable, and the resolved local config is always authoritative.
|
|
157
|
-
|
|
158
|
-
### Guided template sync (`oats config diff | sync | adopt`)
|
|
159
|
-
|
|
160
|
-
Your config and a package's template drift as you edit locally and as the
|
|
161
|
-
package updates. Three commands manage that, and all three share one three-way
|
|
162
|
-
comparison — the recorded **adopted base**, your current local
|
|
163
|
-
`oats-config.yaml`, and the selected template read from the currently locked
|
|
164
|
-
package.
|
|
50
|
+
- **Bare version** (`v2.1.3`, `2.1.3`, `1.0.0-rc.1`): the id is looked up in
|
|
51
|
+
the official catalog — `package-catalog.json` in the `oats` repo, or the file
|
|
52
|
+
named by `OATS_PACKAGE_CATALOG` — which supplies the repo url, the tag
|
|
53
|
+
convention (`v2.1.3` or `oats-framework/v1.1.3`) and the payload path. An id
|
|
54
|
+
the catalog does not know is `E_PACKAGE_MISSING` ("use `git:<repo>@<ref>` for
|
|
55
|
+
a package outside the catalog"). The catalog is the reviewed marketplace
|
|
56
|
+
([official-marketplace.md](official-marketplace.md)) and the only way a
|
|
57
|
+
package becomes pinnable *by id*.
|
|
58
|
+
- **`git:<repo>@<ref>`**: `<repo>` is any repo ref the kernel understands
|
|
59
|
+
(`github.com/org/repo`, `https://…`, `git@host:…`, `/abs/bare.git`,
|
|
60
|
+
`file:///…`); `<ref>` is a tag name or a full 40-hex commit. The package is
|
|
61
|
+
read at `oats-package/`.
|
|
62
|
+
|
|
63
|
+
There is no third form; `lib/packages.mjs#classifyPackageValue` is the one
|
|
64
|
+
grammar, used by workspace validation and by `sync`. A `<ref>` (or catalog ref)
|
|
65
|
+
that resolves to a **branch** is refused: `E_PACKAGE_INTEGRITY { why: "branch" }`
|
|
66
|
+
— versions are immutable.
|
|
67
|
+
|
|
68
|
+
Souls never name versions. A soul says `acme-deploy: { from: package }`; which
|
|
69
|
+
package provides `acme-deploy`, and at which version, is the workspace's
|
|
70
|
+
decision recorded in the lock.
|
|
71
|
+
|
|
72
|
+
## `oats sync` — the one command for the common path
|
|
165
73
|
|
|
166
|
-
```
|
|
167
|
-
oats
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
74
|
+
```
|
|
75
|
+
$ oats sync
|
|
76
|
+
workspace acme (github.com/acme/agents @ 3f2a9c1e)
|
|
77
|
+
members agents ✓↔ (@ 3f2a9c1e) platform ✓↔ (@ 77c0a1b2) tools ✓↔ (@ 47f4b816) billing ✗ (no-backlink)
|
|
78
|
+
packages acme.tools 0.4.0 ✓ (approval needed) oats.framework 1.1.3 ✓ (approved) oats.okf 2.1.3 ✓ (approved)
|
|
79
|
+
changed acme.tools — → 0.4.0 (@ 47f4b816)
|
|
80
|
+
souls 7 discovered (6 members, 1 external, 0 disabled here) · 1 private (platform-reviewer, platform only)
|
|
81
|
+
teams engineering 4 souls, 3 capabilities · global 2 souls, 2 capabilities · unassigned 1 soul
|
|
82
|
+
|
|
83
|
+
acme.tools 0.4.0 @ 47f4b816 needs executable approval (2 executables, digest sha256-7923…):
|
|
84
|
+
acme-deploy: command apply → bin/acme-deploy.mjs
|
|
85
|
+
acme-deploy: command plan → bin/acme-deploy.mjs
|
|
86
|
+
approve acme.tools 0.4.0? [y/N]
|
|
173
87
|
```
|
|
174
88
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
At a config scope that declares `team:`, bare `oats install` reconciles the whole
|
|
200
|
-
workspace instead of only the ancestor chain:
|
|
201
|
-
|
|
202
|
-
1. prints the chosen boundary **before any network or host work**;
|
|
203
|
-
2. restores the boundary scope's locked graph;
|
|
204
|
-
3. discovers descendant scopes containing `oats-config.yaml` or `oats-lock.json`,
|
|
205
|
-
in deterministic path order, pruning `.git`, generated stores (`.agents/`),
|
|
206
|
-
dependency/vendor directories (`node_modules`, `vendor`, virtualenvs), agent
|
|
207
|
-
instances/worktrees, `local-agents/`, **package payload** (below), and
|
|
208
|
-
**nested team boundaries** (each is its own reconciliation unit);
|
|
209
|
-
4. restores each descendant scope once;
|
|
210
|
-
5. validates that every config-referenced installed capability is supplied by a
|
|
211
|
-
visible locked package (or capability lock); and
|
|
212
|
-
6. aggregates missing requirements and failures **by scope**.
|
|
213
|
-
|
|
214
|
-
**Package payload is never a scope.** A directory holding an `oats-package.json`
|
|
215
|
-
is a package root, and everything beneath it is content the package *exports* —
|
|
216
|
-
including the `configTemplates` files under `config-templates/`. Those templates
|
|
217
|
-
bind layers to capabilities the adopting deployment has not installed yet, so
|
|
218
|
-
reconciling one as a live scope would report phantom "supplied by no visible
|
|
219
|
-
locked package" failures for the whole team. Discovery therefore excludes any
|
|
220
|
-
candidate whose containing **ancestor** directory carries an `oats-package.json`,
|
|
221
|
-
whatever the payload root is named — templates are never reconciled, validated,
|
|
222
|
-
or acquired. The rule is the manifest, not the path: a repository that ships a
|
|
223
|
-
package *and* is itself a deployment scope (its own `oats-config.yaml` at the
|
|
224
|
-
root, with the manifest in a subdirectory) stays a scope exactly as before.
|
|
225
|
-
|
|
226
|
-
At a non-team scope, bare `oats install` keeps current-chain behavior. Pass
|
|
227
|
-
`--recursive` to request descendant reconciliation outside a team boundary — the
|
|
228
|
-
boundary is still printed first. OATS never scans downward from the laptop/home
|
|
229
|
-
config by default.
|
|
230
|
-
|
|
231
|
-
## Host requirements — a separate consent gate
|
|
232
|
-
|
|
233
|
-
A capability `requires` entry may declare structured, platform-aware install
|
|
234
|
-
methods (the legacy `install: "https://…"` docs URL still works):
|
|
89
|
+
`sync` (run from the deployment — where `oats-local.yaml` is, or `--dir`):
|
|
90
|
+
|
|
91
|
+
1. discovers the workspace over the remotes and confirms every member;
|
|
92
|
+
2. resolves each `packages:` entry to a commit (`observeRemote`), reads its
|
|
93
|
+
manifests, computes the **integrity** (content digest of the package tree)
|
|
94
|
+
and records `url`, `path`, `version`, `commit`, `integrity`, `capabilities`;
|
|
95
|
+
3. for an entry already locked at the same version/source/path: the commit must
|
|
96
|
+
be unchanged (else `E_PACKAGE_INTEGRITY` — "the tag moved; a version string
|
|
97
|
+
must change when its content does"), the integrity must match, and a
|
|
98
|
+
recorded approval must still describe the package's executables (else
|
|
99
|
+
`E_PACKAGE_UNAPPROVED` — approve again);
|
|
100
|
+
4. for every unapproved entry, prints the exact executables (every `commands.*`
|
|
101
|
+
target and every `hooks.*.command` target of every capability manifest —
|
|
102
|
+
hooks run unattended at spawn/retire) and asks **once** on a terminal;
|
|
103
|
+
5. writes `oats-lock.json` and reports the diff. Entries dropped from
|
|
104
|
+
`packages:` are dropped from the lock.
|
|
105
|
+
|
|
106
|
+
Exit status `2` means the lock is written but approvals are pending
|
|
107
|
+
(non-interactive, or declined). Spawns of souls using an unapproved package are
|
|
108
|
+
refused (`E_PACKAGE_UNAPPROVED`) until `oats sync` is run in a terminal and the
|
|
109
|
+
approval given. `--json` emits the `syncApi: 1` envelope documented in
|
|
110
|
+
[desktop-cli-api.md](desktop-cli-api.md#workspace-model-workspaceapi-2).
|
|
111
|
+
|
|
112
|
+
## `oats package add | remove`
|
|
235
113
|
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
"install": {
|
|
241
|
-
"docs": "https://example.invalid/install",
|
|
242
|
-
"methods": [
|
|
243
|
-
{ "platform": "darwin", "manager": "npm-global", "package": "@example/cli@1.2.3" }
|
|
244
|
-
]
|
|
245
|
-
}
|
|
246
|
-
}
|
|
114
|
+
```bash
|
|
115
|
+
oats package add oats.aweb v1.11.2 # a catalog version
|
|
116
|
+
oats package add acme.tools git:github.com/acme/tools@v0.4.0
|
|
117
|
+
oats package remove acme.tools
|
|
247
118
|
```
|
|
248
119
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
sequence. Nothing runs that the plan did not show.
|
|
262
|
-
- **Aggregation is scoped**: only capabilities *activated somewhere in the
|
|
263
|
-
reconciled scopes* are considered, deduplicated by required command, and the
|
|
264
|
-
report names which capabilities requested each command.
|
|
265
|
-
- **Noninteractive runs never install by default.** Automation names each
|
|
266
|
-
accepted requirement: `oats install --accept-requirement example-cli`.
|
|
267
|
-
`--no-requirements` restores packages only (CI). A **consented** install that
|
|
268
|
-
fails (manager error, or the command still absent from PATH) makes
|
|
269
|
-
`oats install` exit nonzero so automation can detect it. Unaccepted or skipped
|
|
270
|
-
requirements stay non-fatal.
|
|
271
|
-
- **PATH verification** runs after each install. A tool that does not land on
|
|
272
|
-
PATH is reported honestly.
|
|
273
|
-
- **Skipping is safe**: `oats doctor` keeps an actionable warning (the consent
|
|
274
|
-
command to run) until the command is on PATH.
|
|
275
|
-
- **Trust and requirement consent are distinct gates.** Installing a binary
|
|
276
|
-
neither activates nor approves any capability, and capability trust never
|
|
277
|
-
authorizes host installs.
|
|
278
|
-
|
|
279
|
-
When no safe recipe matches the host, OATS prints the documented install URL.
|
|
280
|
-
|
|
281
|
-
## Lock, trust, and restore
|
|
282
|
-
|
|
283
|
-
The scope's `oats-lock.json` uses `lockfileVersion: 2` and records both levels of
|
|
284
|
-
the model in separate top-level maps:
|
|
120
|
+
Both edit `packages:` in `oats-workspace.yaml` **when the file is tracked by
|
|
121
|
+
the Git checkout the command runs in** (the workspace host repo); the edit is
|
|
122
|
+
validated against the full workspace schema before it is written, and the
|
|
123
|
+
receipt tells you to commit and `oats sync`. Anywhere else — a deployment folder,
|
|
124
|
+
a member clone — the command prints the line to add (`--json`: `edited: false`,
|
|
125
|
+
`line`) because the workspace file is shared through Git, not through this
|
|
126
|
+
machine. Nothing network-bound happens in `package add`; `sync` resolves.
|
|
127
|
+
|
|
128
|
+
## Lock v3
|
|
129
|
+
|
|
130
|
+
`oats-lock.json` lives beside `oats-local.yaml`. Two operators who synced the
|
|
131
|
+
same workspace commit and approved the same versions hold identical locks.
|
|
285
132
|
|
|
286
133
|
```json
|
|
287
134
|
{
|
|
288
|
-
"lockfileVersion":
|
|
135
|
+
"lockfileVersion": 3,
|
|
289
136
|
"packages": {
|
|
290
|
-
"
|
|
291
|
-
"source": "
|
|
292
|
-
"
|
|
293
|
-
"commit": "0123456789abcdef0123456789abcdef01234567",
|
|
137
|
+
"oats.okf": {
|
|
138
|
+
"source": "catalog:oats.okf",
|
|
139
|
+
"url": "https://github.com/awebai/oats-okf.git",
|
|
294
140
|
"path": "oats-package",
|
|
295
|
-
"
|
|
296
|
-
"
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
"
|
|
303
|
-
"
|
|
304
|
-
"
|
|
305
|
-
"
|
|
141
|
+
"version": "2.1.3",
|
|
142
|
+
"commit": "b2e16f2ea1555be519db76fda30cd0bea06f8609",
|
|
143
|
+
"integrity": "sha256-1c34dbe9c1cc3826dbe6ecbafbd9a1e189ed36a74bfb2ba8fb6f46a382e95c2d",
|
|
144
|
+
"capabilities": ["oats.okf"],
|
|
145
|
+
"approved": { "executables": "sha256-0d7615fa…", "at": "2026-09-24T09:02:11.000Z" }
|
|
146
|
+
},
|
|
147
|
+
"acme.tools": {
|
|
148
|
+
"source": "git:github.com/acme/tools@v0.4.0",
|
|
149
|
+
"url": "https://github.com/acme/tools.git",
|
|
150
|
+
"path": "oats-package",
|
|
151
|
+
"version": "0.4.0",
|
|
152
|
+
"commit": "47f4b81660e4cc9701d373088de52462762585a3",
|
|
153
|
+
"integrity": "sha256-4cd126a7…",
|
|
154
|
+
"capabilities": ["acme-deploy", "acme-lint"],
|
|
155
|
+
"approved": null
|
|
306
156
|
}
|
|
307
157
|
}
|
|
308
158
|
}
|
|
309
159
|
```
|
|
310
160
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
##
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
161
|
+
| field | meaning |
|
|
162
|
+
|---|---|
|
|
163
|
+
| `source` | `catalog:<id>` or `git:<repo key>@<ref>` — how the workspace asked for it |
|
|
164
|
+
| `url` | the repo url the package was read from; travels in the lock so spawn needs no catalog |
|
|
165
|
+
| `path` | the package root inside the repo |
|
|
166
|
+
| `version` | the version string without a leading `v` (a `git:…@<OID>` pin records the OID) |
|
|
167
|
+
| `commit` | full 40-hex OID the version resolved to |
|
|
168
|
+
| `integrity` | `sha256-<hex>` content digest of the package tree at `path` |
|
|
169
|
+
| `capabilities` | the capability names the package provides (sorted) — what `from: package` looks up |
|
|
170
|
+
| `approved` | `{ executables: "sha256-<hex>", at }` — the digest of the approved executables — or `null` |
|
|
171
|
+
|
|
172
|
+
A capability provided by **two** locked packages is ambiguous and fails
|
|
173
|
+
closed (`E_PACKAGE_MISSING { ambiguous: [ids] }`): keep one of them in
|
|
174
|
+
`packages:`. A lock that is not v3 (a 0.24 lock, an unreadable file) is
|
|
175
|
+
`E_LOCK_SCHEMA`; it is never auto-repaired — delete it and `oats sync`. Agents
|
|
176
|
+
never hand-edit the lock.
|
|
177
|
+
|
|
178
|
+
## Approval
|
|
179
|
+
|
|
180
|
+
Member capabilities are trusted by membership; **package executables are
|
|
181
|
+
approved once per version**, and every instance that materializes that version
|
|
182
|
+
inherits the approval. What is approved is a digest over the bytes of every
|
|
183
|
+
executable a manifest can make the kernel run — `commands.*` targets and
|
|
184
|
+
`hooks.*.command` targets — in canonical order; a hook object without
|
|
185
|
+
`command` is `E_PACKAGE_MANIFEST`, never an invisible no-op. Skills, injects
|
|
186
|
+
and other files are covered by `integrity`, not by the approval.
|
|
187
|
+
|
|
188
|
+
The approval lives next to the commit it approved. A new version starts
|
|
189
|
+
unapproved; a moved tag fails integrity and asks again; an approval whose digest
|
|
190
|
+
no longer matches the tree is refused. `oats spawn` re-checks `approved` on the
|
|
191
|
+
way to `from: package`: reaching materialization means approved.
|
|
192
|
+
|
|
193
|
+
## Materialization from a package
|
|
194
|
+
|
|
195
|
+
At spawn a `from: package` module is fetched at the lock's commit from the
|
|
196
|
+
lock's `url`, at the manifest-listed directory (`oats-package.json#capabilities[]`
|
|
197
|
+
entry), into `<home>/.oats/modules/<cap>/`; the copy's digest is verified
|
|
198
|
+
against what the fetch reported; skills are copied to
|
|
199
|
+
`<home>/.agents/skills/<cap>/<skill>/`. `instance.json.modules.<cap>.from` is
|
|
200
|
+
`{ kind: "package", package, version, commit, integrity, repoKey }`. Bumping
|
|
201
|
+
`packages:` and syncing affects **only new spawns**; `oats status` shows a
|
|
202
|
+
running instance's package module as `moved` once the lock points elsewhere.
|
|
203
|
+
|
|
204
|
+
## Compatibility floors
|
|
205
|
+
|
|
206
|
+
A soul may state floors on package versions — constraints, not sources:
|
|
207
|
+
|
|
208
|
+
```yaml
|
|
209
|
+
compatibility:
|
|
210
|
+
oats.okf: ">=2.1"
|
|
342
211
|
```
|
|
343
212
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
(truthfully reported) result, and the aggregate exit is nonzero.
|
|
375
|
-
- **Trust is re-earned, never transferred.** A capability's materialized
|
|
376
|
-
integrity is not its v1 artifact's integrity, so approvals do not carry over.
|
|
377
|
-
The run prints the exact `oats trust <capability> --dir <scope>` commands, then
|
|
378
|
-
the bare `oats install --dir <scope>` pass (already-installed host requirements
|
|
379
|
-
verify and are not reinstalled; anything missing gets its
|
|
380
|
-
`oats install --accept-requirement <cmd>` consent command).
|
|
381
|
-
|
|
382
|
-
Rerunning the command after a successful migration changes nothing.
|
|
383
|
-
|
|
384
|
-
### The transitional v2 lock is not migrated
|
|
385
|
-
|
|
386
|
-
An earlier, unreleased shape of `lockfileVersion: 2` stored capability lists and
|
|
387
|
-
trust on the package rows and used a persistent `.agents/packages/installed/`
|
|
388
|
-
store. That transitional shape receives no product migration path. The reader
|
|
389
|
-
rejects it centrally as `invalid-lock` with actionable guidance. It is recreated
|
|
390
|
-
by a fresh acquisition, never converted or partially interpreted. There is no
|
|
391
|
-
`lockfileVersion: 3`. Because the transitional contract had no external
|
|
392
|
-
adoption, the founder chose to replace it in place rather than carry a migration
|
|
393
|
-
for it.
|
|
394
|
-
|
|
395
|
-
### Catalog shape
|
|
396
|
-
|
|
397
|
-
The official catalog is data (`package-catalog.json`, or the file named by
|
|
398
|
-
`OATS_PACKAGE_CATALOG`). The v0.23.1 integration selects these already-published
|
|
399
|
-
sources; installing a kernel does not advance existing package locks:
|
|
213
|
+
Checked at resolution against the locked version (`E_COMPATIBILITY`,
|
|
214
|
+
naming capability, package, version and range). A package pinned by OID has no
|
|
215
|
+
version to check (`why: "unversioned"`): pin a tagged version.
|
|
216
|
+
|
|
217
|
+
## Publishing a package from a member repo
|
|
218
|
+
|
|
219
|
+
A repo can be a **member** of the workspace **and** publish a package; the two
|
|
220
|
+
roles never collapse (see [workspaces.md](workspaces.md#member-tier-vs-package-tier-the-non-collapse-rule)):
|
|
221
|
+
|
|
222
|
+
1. Put the package under `oats-package/` with its `oats-package.json` and
|
|
223
|
+
capability directories. Everything under `capabilities/` at the repo root
|
|
224
|
+
stays member-tier (latest state, for people working *on* the package —
|
|
225
|
+
typically a `<name>-dev` capability); everything under `oats-package/` is
|
|
226
|
+
package-tier.
|
|
227
|
+
2. Add a member soul that is the expert in the package (`souls/<name>-expert/`),
|
|
228
|
+
ordinary and discoverable, the natural owner of the package's PRs. It eats
|
|
229
|
+
its own published food: `acme-lint: { from: package }` at the pinned version,
|
|
230
|
+
plus `acme-tools-dev: { from: here }`.
|
|
231
|
+
3. Tag a release (`v0.4.0`). Tags are immutable: a new content needs a new tag.
|
|
232
|
+
4. Consumers pin it: `oats package add acme.tools git:github.com/acme/tools@v0.4.0`
|
|
233
|
+
→ commit → `oats sync` → approve once. Discovery shows the member row with
|
|
234
|
+
`publishes: { package: "acme.tools", version: "0.4.0" }`.
|
|
235
|
+
5. To become pinnable by id, open a PR adding the package to
|
|
236
|
+
`package-catalog.json` in the `oats` repo ([official-marketplace.md](official-marketplace.md)).
|
|
237
|
+
|
|
238
|
+
A soul that names one of the package's capabilities with
|
|
239
|
+
`from: github.com/acme/tools` fails: `E_CAPABILITY_MISSING` with the hint
|
|
240
|
+
`provided by package acme.tools; use from: package`.
|
|
241
|
+
|
|
242
|
+
## Catalog shape
|
|
400
243
|
|
|
401
244
|
```json
|
|
402
245
|
{
|
|
246
|
+
"policy": "docs/official-marketplace.md",
|
|
403
247
|
"packages": {
|
|
404
|
-
"oats.okf":
|
|
405
|
-
"oats.framework": { "url": "https://github.com/awebai/oats.git", "ref": "oats-framework/v1.1.3", "path": "oats-package" }
|
|
406
|
-
|
|
407
|
-
},
|
|
408
|
-
"capabilities": { "oats.review": "oats.dev" }
|
|
248
|
+
"oats.okf": { "url": "https://github.com/awebai/oats-okf.git", "ref": "v2.1.3", "path": "oats-package" },
|
|
249
|
+
"oats.framework": { "url": "https://github.com/awebai/oats.git", "ref": "oats-framework/v1.1.3", "path": "oats-package" }
|
|
250
|
+
}
|
|
409
251
|
}
|
|
410
252
|
```
|
|
411
253
|
|
|
412
|
-
`
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
`
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
npm drops the source worker soul's `CLAUDE.md -> AGENTS.md`. It must not be
|
|
427
|
-
advertised as a complete local package or repaired after acquisition to evade
|
|
428
|
-
integrity checks. Git transport preserves the canonical source alias.
|
|
429
|
-
|
|
430
|
-
The `oats.framework` distribution package is a separate Git payload in this
|
|
431
|
-
repository's `oats-package/`, excluded from the kernel npm tarball. The catalog
|
|
432
|
-
entry selects the published `oats-framework/v1.1.3` tag, which exports three
|
|
433
|
-
capabilities: `oats.core` (day-to-day operation: `oats-operate`, `oats-souls`
|
|
434
|
-
and the "you run on OATS" briefing — declared explicitly on every soul by
|
|
435
|
-
default at creation and removable), `oats.setup` (OATS Soul Setup: `oats-config`,
|
|
436
|
-
`oats-packages`, `oats-workspace-setup`) and the optional `oats.knowledge-theory`
|
|
437
|
-
(authoring skill and `knowledge-theory-expert`). Acquire it with
|
|
438
|
-
`oats install oats.framework`; the capability ids also resolve through the
|
|
439
|
-
catalog aliases. Acquiring it does not activate anything, bind a knowledge
|
|
440
|
-
layer or add a runtime judge.
|
|
441
|
-
|
|
442
|
-
Updating OKF v1 to v2 is a breaking capability change. Preserve existing
|
|
443
|
-
knowledge and source state/cursors, explicitly bind/provision external owners,
|
|
444
|
-
accept provider delivery and perform deliberate cutover. Kernel package/lock
|
|
445
|
-
migration does none of this. See [knowledge migration](knowledge-migration.md).
|
|
446
|
-
|
|
447
|
-
## Doctor
|
|
448
|
-
|
|
449
|
-
`oats doctor` reports, in addition to its capability diagnostics:
|
|
450
|
-
|
|
451
|
-
- **Distribution packages** visible in the lock (`packages:` in
|
|
452
|
-
`oats-lock.json`), with source and the capabilities each supplies;
|
|
453
|
-
- **adopted config templates** in the chain — the package and template each
|
|
454
|
-
scope adopted, its recorded base, and whether local changes have drifted from
|
|
455
|
-
it;
|
|
456
|
-
- **available-but-unadopted templates** — a locked, installed package exporting
|
|
457
|
-
config templates that no scope has adopted;
|
|
458
|
-
- **missing host commands** for active capabilities, with the exact consent
|
|
459
|
-
command when a safe installer exists;
|
|
460
|
-
- **official capability migration** (`officialMigration` in `--json`) when the
|
|
461
|
-
chain still holds legacy `marketplace:` locks: each capability with the
|
|
462
|
-
package that supplies it, and either `ready` with the exact
|
|
463
|
-
`oats migrate --official --recursive --dir <boundary>` command, or `unavailable`
|
|
464
|
-
with the reason — the catalog has no mapping yet and the legacy capabilities
|
|
465
|
-
remain supported.
|
|
466
|
-
|
|
467
|
-
## Engine integration
|
|
468
|
-
|
|
469
|
-
The package engine (acquisition, capability materialization, revised v2 lock,
|
|
470
|
-
exact restore, capability indexing, per-capability trust — see
|
|
471
|
-
[`design/package-engine-contract.md`](design/package-engine-contract.md) and
|
|
472
|
-
[`design/package-runtime-api.md`](design/package-runtime-api.md)) is merged.
|
|
473
|
-
`oats init --package` acquires and exact-locks the full closure through the
|
|
474
|
-
engine's `acquirePackage` for every source kind (git, catalog, local path), then
|
|
475
|
-
adopts exactly one template. The team-boundary reconciliation above wraps the
|
|
476
|
-
engine's exact-restore primitive (integrity, capability, and runtime-closure
|
|
477
|
-
verification) per scope. Legacy v1 capability locks keep restoring via the
|
|
478
|
-
capability path and are reported as LEGACY with the `oats migrate` pointer.
|
|
254
|
+
`ref` carries the tag convention: a workspace's `oats.framework: v1.2.0`
|
|
255
|
+
resolves to tag `oats-framework/v1.2.0`. Resolving through the catalog never
|
|
256
|
+
grants approval and never advances a lock by itself — `oats sync` does, and
|
|
257
|
+
says so.
|
|
258
|
+
|
|
259
|
+
## Removed verbs
|
|
260
|
+
|
|
261
|
+
`oats install`, `restore`, `init`, `use`, `trust`, `list`, `catalog`, `remove`,
|
|
262
|
+
`migrate`, `config` are gone; each answers `E_UNKNOWN_COMMAND` naming its
|
|
263
|
+
replacement (`details.removed` / `details.replacement` in `--json`). There is
|
|
264
|
+
no installed-capability directory, no config template adoption, no host
|
|
265
|
+
requirement installer. A manifest's `requires` still describes what must exist
|
|
266
|
+
on the host (runtime packages are verified at spawn; host commands are the
|
|
267
|
+
operator's to install). See [rebuild-to-v2.md](rebuild-to-v2.md).
|