@awebai/oats 0.25.1 → 0.25.3
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 +151 -35
- package/docs/configuration.md +3 -3
- package/docs/design/2026-09-20-redesign-program-board.md +1 -1
- package/docs/design/2026-09-20-workspace-and-portable-adoption-plan.md +1 -1
- package/docs/design/2026-09-23-simplified-workspace-model.md +4 -4
- package/docs/design/2026-09-23-workspace-module-contracts.md +128 -2
- package/docs/design/2026-09-23-workspace-v2-implementation-plan.md +3 -3
- package/docs/desktop-cli-api.md +1 -1
- package/docs/desktop.md +1 -1
- package/docs/first-team.md +3 -3
- package/docs/knowledge.md +14 -7
- package/docs/rebuild-to-v2.md +182 -26
- package/docs/release-notes/v0.25.2.md +80 -0
- package/docs/release-notes/v0.25.3.md +19 -0
- package/docs/souls-and-instances.md +34 -16
- package/docs/workspaces.md +65 -26
- package/lib/core.mjs +71 -11
- package/lib/instance-resolution.mjs +132 -2
- package/lib/materialize.mjs +29 -0
- package/package.json +1 -1
|
@@ -28,9 +28,9 @@ Each is one PR (or two small ones), reviewed by me, on `main`, as canonical code
|
|
|
28
28
|
| **W7** | **CLI switch-over** | `oats sync`, `oats spawn` (preview/apply unchanged in shape, now fed by W4/W6), `oats capabilities` / `oats souls` with origin + team, `oats workspace status`; `oats status` shows `modules … @ commit` + `member moved since`; `oats version --json` advertises `workspaceApi: 2` + feature `workspace-v2`; **remove the v1 readers** (`oats.yaml`, per-soul `source:`, `oats-config.yaml` activation) — a v1 file at a v2 path errors naming the schema | lead | M |
|
|
29
29
|
| **W8** | **Delete v1** | Remove `portable-*`, `source-spec`, `capability-provenance` (v1 parts), `prepared-resources`, migration stores/evidence, the installed tier in `packages.mjs`, classic config activation, their tests and docs; `core.mjs` loses everything that only served v1 | lead | L (mostly deletion) |
|
|
30
30
|
| **W9** | **Framework repos as the first workspace (decisions 18–21)** | `oats-workspace.yaml` v2 in `oats` (drop the six imports; `packages:` pins oats.framework/okf/aweb/jira/linear/authoring/dev **as packages**; `teams:` global/engineering; `defaults`); `oats-membership.yaml` in ALL seven repos; the six soul editions rewritten (`oats.okf: {from: package}` etc. even though the repos are members); **a new expert soul in every package repo** — `okf-expert`, `aweb-expert`, `jira-expert`, `linear-expert`, `authoring-expert`, `dev-expert` (v2 `souls/<name>/`, team global, knows and evolves that capability); `package-catalog.json` kept as the official marketplace (bare-version `packages:` entries resolve through it) | lead (member-repo PRs to their owners; the expert souls' AGENTS.md drafted by me, reviewed by the package owner) | L |
|
|
31
|
-
| **W9b** | **`oats.core` and `oats.setup` rewritten for the new architecture (human, 2026-09-23)** | The two official capabilities' skills and injects are rewritten to teach the *new* model, not patched: **`oats.core`** (`oats-operate`, `oats-souls`, the "you run on OATS" inject) — how an agent works inside an instance under this architecture: its home layout (`.oats/modules/`, `.agents/skills/`, `instance.json` modules/providers), the verbs it will actually use (`status`, `spawn --preview/--provider`, `retire`, `session`, `instance events`, `capabilities`, `souls`, `workspace status`), what a workspace/member/package/team is *from the agent's seat*, drift ("member moved since"), how to find and read other souls. **`oats.setup`** (`oats-config`/`oats-packages` → renamed to what they now are: `oats-workspace`, `oats-packages`, `oats-onboarding`) — the whole architecture and its best practices: workspace ↔ repo handshake and why, `oats-workspace.yaml` / `oats-membership.yaml` / `soul.yaml` v2 / `oats-local.yaml` field by field, teams as labels, member-tier vs package-tier and the non-collapse rule, `packages:` + lock v3 + per-version approval, the official catalog vs `git:` refs, `sync`/`package add`, the
|
|
32
|
-
| **W10** | **Docs** | **`docs/rebuild-to-v2.md` — the rebuild guide (ships with the schemas; states that 0.24.x keeps spawning 0.24.x deployments)**; `docs/workspaces.md` rewritten around v2; `souls-and-instances.md`, `packages.md`, `configuration.md` (mostly deleted), `first-team.md` → the
|
|
33
|
-
| **W11** | **Onboarding skill** | `oats-setup-expert` / `oats.setup`:
|
|
31
|
+
| **W9b** | **`oats.core` and `oats.setup` rewritten for the new architecture (human, 2026-09-23)** | The two official capabilities' skills and injects are rewritten to teach the *new* model, not patched: **`oats.core`** (`oats-operate`, `oats-souls`, the "you run on OATS" inject) — how an agent works inside an instance under this architecture: its home layout (`.oats/modules/`, `.agents/skills/`, `instance.json` modules/providers), the verbs it will actually use (`status`, `spawn --preview/--provider`, `retire`, `session`, `instance events`, `capabilities`, `souls`, `workspace status`), what a workspace/member/package/team is *from the agent's seat*, drift ("member moved since"), how to find and read other souls. **`oats.setup`** (`oats-config`/`oats-packages` → renamed to what they now are: `oats-workspace`, `oats-packages`, `oats-onboarding`) — the whole architecture and its best practices: workspace ↔ repo handshake and why, `oats-workspace.yaml` / `oats-membership.yaml` / `soul.yaml` v2 / `oats-local.yaml` field by field, teams as labels, member-tier vs package-tier and the non-collapse rule, `packages:` + lock v3 + per-version approval, the official catalog vs `git:` refs, `sync`/`package add`, the deployment directory (the operator's; no naming convention) and clone-then-spawn, private items, external souls, the standalone case, provider payload homes (soul/machine/spawn), what is deliberately NOT versioned and why. Every skill is validated against the shipped CLI (`oats <verb> --help` snapshot test) so they cannot drift from the commands. | lead (swarm + review) | M |
|
|
32
|
+
| **W10** | **Docs** | **`docs/rebuild-to-v2.md` — the rebuild guide (ships with the schemas; states that 0.24.x keeps spawning 0.24.x deployments)**; `docs/workspaces.md` rewritten around v2; `souls-and-instances.md`, `packages.md`, `configuration.md` (mostly deleted), `first-team.md` → the operator's deployment directory; DTO doc § Workspace v2; release notes | lead | M |
|
|
33
|
+
| **W11** | **Onboarding skill** | `oats-setup-expert` / `oats.setup`: ASK for the deployment directory (an existing folder with the operator's clones is the usual case — no named convention, decision 9), `oats sync`, clone-then-spawn; **the hosting rule for mixed public/private organisations (decision 26): ask up front whether any member is private; if so the workspace file is hosted in a private repo that is NOT a public member (a dedicated private `workspace` repo is the honest shape), public contributors get the standalone case with `oats.core` by default (decision 25); `oats onboard` prints the same rule in its next-steps**; the `oats-operate` skill updated for the new verbs | lead | S |
|
|
34
34
|
| **W12** | **Desktop follow-through** | New kernel DTOs (from W7) consumed the usual way — engineer reads the merged head, files pins, wires: Capabilities/Souls origin + team columns; "installed" removed as a state; spawn preview shows modules (from/commit/hash) + team; Workspaces surface shows membership status | Desktop engineer, after W7 | M |
|
|
35
35
|
|
|
36
36
|
**Team review (Antares, 2026-09-23) folded in:** rebuild guide (W10), **second review (two aweb teams, stores, soul layout, standalone, public/private hosting → decisions 23–26: `messaging.byTeam`, stores = repo + provider `root`, `souls/` only, `oats.core` standalone default, private host rule taught by onboarding),** `--provider` instance payload (W6/W7), drift display (W7), duplicate-name rule (W6), 0.24.x-keeps-working stated everywhere.
|
package/docs/desktop-cli-api.md
CHANGED
|
@@ -748,7 +748,7 @@ Every `commit` is a full 40-hex OID; every digest is `sha256-<hex>`; every
|
|
|
748
748
|
`oats onboard [<dir>] --workspace <repo ref> [--json]`
|
|
749
749
|
|
|
750
750
|
The **bootstrap** of a deployment (decision 9): realizes a workspace on this
|
|
751
|
-
machine in the
|
|
751
|
+
machine in the directory the operator chooses (any existing folder). It writes
|
|
752
752
|
`<dir>/oats-local.yaml` (`{ schemaVersion: 2, workspace: <ref> }`), creates
|
|
753
753
|
`<dir>/agents/` (the instance homes), then runs exactly the `oats sync` body
|
|
754
754
|
over the directory just written — discover over the remotes, confirm
|
package/docs/desktop.md
CHANGED
|
@@ -86,7 +86,7 @@ The app starts on the directory it was launched with (its own folder by
|
|
|
86
86
|
default). To view a deployment, open the workspace switcher in the sidebar
|
|
87
87
|
and choose **Add workspace → Browse**, then point it at an OATS deployment —
|
|
88
88
|
a directory containing `agents/` (under the 0.25 workspace model that is the
|
|
89
|
-
|
|
89
|
+
deployment directory (the operator's choice) holding `oats-local.yaml` and `agents/`;
|
|
90
90
|
under 0.24, an `agents/` root, a `local-agents/` root for machine-local souls,
|
|
91
91
|
or a team scope whose `oats-config.yaml` declares `team:`). *The Desktop's own
|
|
92
92
|
multi-repo roster ("team scopes show every member repo's agents under one
|
package/docs/first-team.md
CHANGED
|
@@ -56,15 +56,15 @@ one soul and, optionally, one capability. Every soul gets `oats.core` from the
|
|
|
56
56
|
the resulting layout).
|
|
57
57
|
|
|
58
58
|
```bash
|
|
59
|
-
oats onboard ~/acme
|
|
59
|
+
oats onboard ~/acme --workspace git:github.com/acme/agents # any directory — an existing one with your clones is fine
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
```
|
|
63
|
-
~/acme
|
|
63
|
+
~/acme/ # the directory you chose; these three entries are what the kernel needs
|
|
64
64
|
├── oats-local.yaml # { schemaVersion: 2, workspace: git:github.com/acme/agents }
|
|
65
65
|
├── oats-lock.json # lockfileVersion 3: commit + integrity + approval per package
|
|
66
66
|
├── agents/ # instance homes
|
|
67
|
-
└── <member>/ # clones of the members you work IN
|
|
67
|
+
└── <member>/ # clones of the members you work IN — here or anywhere named in oats-local.yaml clones:
|
|
68
68
|
```
|
|
69
69
|
|
|
70
70
|
Read the report it prints: every member row must be `✓↔` (confirmed) — fix
|
package/docs/knowledge.md
CHANGED
|
@@ -66,9 +66,11 @@ packages:
|
|
|
66
66
|
defaults:
|
|
67
67
|
knowledge: { oats.okf: { from: package } }
|
|
68
68
|
|
|
69
|
-
# souls/domain-expert/soul.yaml
|
|
69
|
+
# souls/domain-expert/soul.yaml — nothing under knowledge: for oats.okf; the default fills the slot.
|
|
70
|
+
# What the soul owns/reads is souls/domain-expert/okf.json (below), not a soul.yaml payload.
|
|
71
|
+
# A soul-true binding setting is the one thing the payload may carry, e.g.:
|
|
70
72
|
knowledge:
|
|
71
|
-
|
|
73
|
+
harvest-runtime: claude
|
|
72
74
|
|
|
73
75
|
# oats-local.yaml (this machine)
|
|
74
76
|
settings:
|
|
@@ -79,11 +81,14 @@ settings:
|
|
|
79
81
|
|
|
80
82
|
```bash
|
|
81
83
|
oats sync # resolves v2.1.3 to a commit, asks executable approval once
|
|
82
|
-
oats spawn domain-expert --preview --json # the exact oats.okf module (package, version, commit)
|
|
84
|
+
oats spawn domain-expert --preview --json # the exact oats.okf module (package, version, commit) + settings.oats.okf (the merged payload)
|
|
83
85
|
```
|
|
84
86
|
|
|
85
|
-
Pinning activates nothing by itself: the soul's `
|
|
86
|
-
|
|
87
|
+
Pinning activates nothing by itself: the soul's `okf.json` must exist and the
|
|
88
|
+
merged payload (soul `knowledge:` ⊕ `settings.oats.okf` ⊕ `--provider`) must be
|
|
89
|
+
bindable — it may carry **only** the four settings below (`bindings-file`,
|
|
90
|
+
`state-dir`, `harvest-runtime`, `harvest-model`); `owns`/`reads`/`root` on the
|
|
91
|
+
soul payload are refused by 2.1.3, not read. The lock stays exact until the
|
|
87
92
|
workspace bumps `packages.oats.okf`; v1 operators must plan migration before
|
|
88
93
|
that bump. Executable changes come with a new version and a new approval. A
|
|
89
94
|
service worker need not itself fill the knowledge slot (`knowledge: none`).
|
|
@@ -129,8 +134,10 @@ directory, not the current working directory:
|
|
|
129
134
|
source homes/worktrees; keep the bindings file outside state and bases. Local
|
|
130
135
|
Git locators must not be disposable linked worktrees. Directory lock/journal
|
|
131
136
|
artifacts also must not overlap state, sources or another base.
|
|
132
|
-
- Settings are `bindings-file`, `
|
|
133
|
-
|
|
137
|
+
- Settings are `bindings-file`, `state-dir` (both required, absolute host
|
|
138
|
+
paths), `harvest-runtime` (`pi`, `claude`, `codex`, default `pi`), and
|
|
139
|
+
optional `harvest-model` — the complete list a 2.1.3 payload may carry.
|
|
140
|
+
Choose an installed, authenticated
|
|
134
141
|
worker runtime independently of the source; omitted models use that runtime's
|
|
135
142
|
configured default. V1 record-window settings are not v2 settings.
|
|
136
143
|
|
package/docs/rebuild-to-v2.md
CHANGED
|
@@ -48,6 +48,8 @@ capabilities plus `oats.core`), so a public soul stays usable.
|
|
|
48
48
|
Two teams that need two different messaging identities (an open-source team
|
|
49
49
|
and a hosted-operations team, say) stay in ONE workspace: `team:` is a label,
|
|
50
50
|
and the provider payload is addressed by label under `messaging.byTeam` (§2).
|
|
51
|
+
Read §8b before relying on it: the kernel merges `byTeam`, but oats.aweb 1.11.2
|
|
52
|
+
does not yet read the `team` it delivers.
|
|
51
53
|
|
|
52
54
|
## 2. Write `oats-workspace.yaml` v2 in the host repo
|
|
53
55
|
|
|
@@ -141,7 +143,7 @@ they enumerate `souls/*/soul.yaml`. A soul left under `agents/` is invisible to
|
|
|
141
143
|
| `stores.inherit` | delete (stores are declared once in the workspace) |
|
|
142
144
|
| `imports` | delete |
|
|
143
145
|
| `kind`, `type`, `repo`, `runtime`, `model`, `launch-config` | delete — model/runtime/launch config are spawn-time choices; `team:` replaces `type:` as the grouping |
|
|
144
|
-
| `knowledge:` / `messaging:` payload | keep as is (opaque provider payload); `none` empties the slot |
|
|
146
|
+
| `knowledge:` / `messaging:` payload | keep as is (opaque provider payload); `none` empties the slot. **For `oats.okf` see the box below: the payload is the binding's SETTINGS keys only; what the soul owns/reads stays in `okf.json`** |
|
|
145
147
|
| — | `compatibility: { <cap>: ">=x.y" }` if you want a floor |
|
|
146
148
|
|
|
147
149
|
```yaml
|
|
@@ -152,9 +154,8 @@ work: worktree
|
|
|
152
154
|
team: engineering
|
|
153
155
|
capabilities:
|
|
154
156
|
acme-release-tooling: { from: here }
|
|
155
|
-
knowledge:
|
|
156
|
-
|
|
157
|
-
reads: [platform-engineer]
|
|
157
|
+
# knowledge: — nothing here for oats.okf: the workspace default fills the slot and
|
|
158
|
+
# souls/release-manager/okf.json (below) says what this soul owns and reads.
|
|
158
159
|
messaging:
|
|
159
160
|
channels: [acme-eng]
|
|
160
161
|
```
|
|
@@ -164,6 +165,48 @@ are required. Capabilities the repo exports live at
|
|
|
164
165
|
`capabilities/<name>/oats.json` — the manifest is unchanged; you may add
|
|
165
166
|
`private: true` / `team:`.
|
|
166
167
|
|
|
168
|
+
**`oats.okf` 2.1.3 reads `souls/<name>/okf.json`, not a `knowledge:` payload.**
|
|
169
|
+
Earlier drafts of this guide showed `knowledge: { owns: …, reads: … }` or
|
|
170
|
+
`knowledge: { store, root }` on the soul; **no shipped provider consumes those
|
|
171
|
+
keys**. What OKF 2.1.3 actually reads at spawn is two things:
|
|
172
|
+
|
|
173
|
+
1. **`<soul>/okf.json`** (travels with the soul, fetched into the per-commit
|
|
174
|
+
soul cache like `AGENTS.md`) — the soul's knowledge declaration, exactly
|
|
175
|
+
these keys and no others:
|
|
176
|
+
|
|
177
|
+
```json
|
|
178
|
+
{ "version": 1,
|
|
179
|
+
"owner": "release-manager",
|
|
180
|
+
"owns": ["org/release-manager"],
|
|
181
|
+
"reads": ["org/platform-engineer"] }
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
`owner` is the stable owner id (what `owners.json` pins, §7b); `owns` /
|
|
185
|
+
`reads` are `<base alias>/<node>` references into the bases the machine's
|
|
186
|
+
bindings file declares (`oats okf init` / `oats okf migrate` write it;
|
|
187
|
+
`capabilities/oats-okf/lib/config.mjs#validateDeclaration` is the
|
|
188
|
+
authority). Keep the file where 0.24 had it — it moves with the soul in
|
|
189
|
+
§3b. A soul without `okf.json` whose slot resolves to `oats.okf` fails the
|
|
190
|
+
required spawn hook (`soul has no okf.json`), by design.
|
|
191
|
+
2. **The merged payload, as `OATS_SETTINGS`** — the binding's **settings
|
|
192
|
+
keys only**, the list in `capabilities/oats-okf/oats.json#settings`:
|
|
193
|
+
`bindings-file`, `state-dir` (both required, absolute host paths →
|
|
194
|
+
`oats-local.yaml`, §5), `harvest-runtime`, `harvest-model` (optional). Any
|
|
195
|
+
other key — `owns`, `reads`, `store`, `root`, `stores` — is refused
|
|
196
|
+
(`unknown OATS_SETTINGS property`). So for `oats.okf` the soul's
|
|
197
|
+
`knowledge:` payload is normally **absent** (the workspace default
|
|
198
|
+
`defaults.knowledge: { oats.okf: { from: package } }` fills the slot) or
|
|
199
|
+
carries a soul-true binding setting such as `harvest-runtime: claude`;
|
|
200
|
+
`knowledge: none` opts the soul out.
|
|
201
|
+
|
|
202
|
+
`stores:` in the workspace file names repositories for the **workspace**; where
|
|
203
|
+
OKF's bases live inside them is a **bindings-file** concern today (`bases.<alias>`
|
|
204
|
+
with `repository` + `root`), not a soul payload key. A soul payload grammar for
|
|
205
|
+
OKF (`owns`/`reads`/`root` on `soul.yaml`) is an OKF follow-up (it lands with an
|
|
206
|
+
`oats.okf` release that declares it in its binding, and this guide will say so);
|
|
207
|
+
until then the kernel forwards the payload opaquely and OKF refuses what it does
|
|
208
|
+
not know.
|
|
209
|
+
|
|
167
210
|
**Carry `team:` on every soul, or on its repo's membership.** A soul's team is
|
|
168
211
|
`soul.yaml#team`, else `oats-membership.yaml#team`, else *unassigned*
|
|
169
212
|
(`null`). Labels never gate anything, but the kernel addresses provider payload
|
|
@@ -175,25 +218,27 @@ outside every team-addressed payload; nothing refuses it. Label the membership
|
|
|
175
218
|
when a whole repo belongs to one team, and the soul when it does not.
|
|
176
219
|
|
|
177
220
|
**Per-soul memory-harvest opt-out:** not available in OKF 2.1.3 — an OKF 2.1.4
|
|
178
|
-
item.
|
|
179
|
-
|
|
180
|
-
keeps a soul registered for reads while excluding it from harvest. A
|
|
181
|
-
must not be harvested today says `knowledge: none` (no OKF at all for
|
|
182
|
-
soul) or `oats.okf: off`; do not invent a key —
|
|
183
|
-
|
|
221
|
+
item. Neither `okf.json` (`version`, `owner`, `owns`, `reads`) nor the settings
|
|
222
|
+
payload (`bindings-file`, `state-dir`, `harvest-runtime`, `harvest-model`) has a
|
|
223
|
+
key that keeps a soul registered for reads while excluding it from harvest. A
|
|
224
|
+
soul that must not be harvested today says `knowledge: none` (no OKF at all for
|
|
225
|
+
that soul) or `oats.okf: off`; do not invent a key — both readers refuse unknown
|
|
226
|
+
keys.
|
|
184
227
|
|
|
185
228
|
## 5. Write `oats-local.yaml` on each machine
|
|
186
229
|
|
|
187
230
|
```
|
|
188
|
-
~/acme
|
|
231
|
+
~/acme/ # the directory YOU choose — an existing folder with your clones is the usual case
|
|
189
232
|
├── oats-local.yaml
|
|
190
|
-
├── agents/ # instance homes
|
|
191
|
-
└── platform/ # member clones,
|
|
233
|
+
├── agents/ # instance homes — created by `oats sync` if absent (0.25.2)
|
|
234
|
+
└── platform/ # member clones, wherever you keep them (here, or named in clones:)
|
|
192
235
|
```
|
|
193
236
|
|
|
194
237
|
```yaml
|
|
195
238
|
schemaVersion: 2
|
|
196
239
|
workspace: git:github.com/acme/agents
|
|
240
|
+
clones: # optional: member clones that are NOT at <deployment>/<member name>
|
|
241
|
+
github.com/acme/platform: /Users/ana/src/acme-platform
|
|
197
242
|
settings: # what used to be `settings:` under capabilities.layers.* in oats-config.yaml
|
|
198
243
|
oats.okf:
|
|
199
244
|
bindings-file: /Users/ana/.oats/okf-bindings.json # required by the OKF binding: absolute host path
|
|
@@ -205,6 +250,27 @@ souls:
|
|
|
205
250
|
disabled: [data-analyst]
|
|
206
251
|
```
|
|
207
252
|
|
|
253
|
+
**Where the kernel looks for a member clone** (a `work: worktree | checkout`
|
|
254
|
+
soul needs one; nothing else does). In this order, first hit wins:
|
|
255
|
+
|
|
256
|
+
1. `oats spawn … --repo <abs path>` — this spawn only.
|
|
257
|
+
2. `oats-local.yaml` `clones: { <repo key>: <abs path> }` — the key is the
|
|
258
|
+
member's **canonical key** (`github.com/acme/platform`; any ref spelling you
|
|
259
|
+
write is normalised through `parseRepoRef`, so `git:github.com/acme/platform`
|
|
260
|
+
and `https://github.com/acme/platform.git` address the same entry).
|
|
261
|
+
3. The convention: `<deployment>/<member name>` — the last path segment of the
|
|
262
|
+
repo key (`platform` for `github.com/acme/platform`). One exception: a member
|
|
263
|
+
whose name is `agents` is looked for at `<deployment>/agents-repo`, because
|
|
264
|
+
`<deployment>/agents/` is the instance root (above).
|
|
265
|
+
4. None found → `E_CLONE_MISSING`, naming the three remedies. A directory that
|
|
266
|
+
*is* found but whose `origin` remote is a **different repo** →
|
|
267
|
+
`E_CLONE_MISMATCH` (the clone is not the member; nothing is spawned into it).
|
|
268
|
+
|
|
269
|
+
This order was documented before 0.25.2 but the kernel did not honour it (a
|
|
270
|
+
clone had to be `--repo`'d or sit at the convention); 0.25.2 implements it as
|
|
271
|
+
written here. If your host repo is named `agents`, clone it as
|
|
272
|
+
`<deployment>/agents-repo` or name it in `clones:`.
|
|
273
|
+
|
|
208
274
|
`settings.<cap>` is merged into that capability's payload after the soul's
|
|
209
275
|
slot payload and before `spawn --provider` (decision 14); the keys are the
|
|
210
276
|
capability's own (`oats.json#settings`). For **`oats.okf` 2.1.3** the binding
|
|
@@ -220,8 +286,12 @@ here but see §8 for why it belongs at spawn.
|
|
|
220
286
|
Move host paths from `oats-config.yaml` `settings:` here; the `souls:` blocks of
|
|
221
287
|
`oats-config.yaml` become `--provider` flags at spawn (step 8). Delete
|
|
222
288
|
`oats-config.yaml`; it is not read. Do not commit `oats-local.yaml`.
|
|
223
|
-
(`oats onboard <dir> --workspace <repo ref>` writes a minimal `oats-local.yaml
|
|
224
|
-
and runs the first `sync` for you; add `settings:` afterwards.
|
|
289
|
+
(`oats onboard <dir> --workspace <repo ref>` writes a minimal `oats-local.yaml`,
|
|
290
|
+
creates `agents/` and runs the first `sync` for you; add `settings:` afterwards.
|
|
291
|
+
Its `next.clone` list names **every** member that lacks a clone at the
|
|
292
|
+
convention — the host included: the host is a member like any other, and a
|
|
293
|
+
soul that lives in it and says `work: worktree` needs its clone too. Under an
|
|
294
|
+
explicit `standalone:` header the list says so and names only that repo.)
|
|
225
295
|
|
|
226
296
|
## 6. `oats sync`
|
|
227
297
|
|
|
@@ -231,11 +301,17 @@ From the deployment directory:
|
|
|
231
301
|
oats sync
|
|
232
302
|
```
|
|
233
303
|
|
|
234
|
-
It
|
|
235
|
-
|
|
236
|
-
`
|
|
237
|
-
|
|
238
|
-
|
|
304
|
+
It creates `agents/` if it is absent (0.25.2; a hand-written `oats-local.yaml`
|
|
305
|
+
no longer needs a `mkdir`), confirms every member (fix any `no-backlink` /
|
|
306
|
+
`backlink-elsewhere` / `cannot-read` row before going on), resolves `packages:`
|
|
307
|
+
to commits, writes `oats-lock.json` (lockfileVersion 3) and asks for executable
|
|
308
|
+
approval once per package version. The 0.24 lock is not read; delete it
|
|
309
|
+
(`E_LOCK_SCHEMA` names it if you leave it in the way).
|
|
310
|
+
|
|
311
|
+
The legacy "You run on OATS" block is no longer composed into `AGENTS.md` when
|
|
312
|
+
`oats.core` resolves as a module (0.25.2): an instance gets **one** such block,
|
|
313
|
+
the one `oats.core`'s inject carries. If you see two, the soul resolved without
|
|
314
|
+
`oats.core` (check `oats spawn <soul> --preview`).
|
|
239
315
|
|
|
240
316
|
## 7. Approve packages
|
|
241
317
|
|
|
@@ -243,10 +319,23 @@ Approval is **per package version, once, in the lock** — no `oats trust`, no
|
|
|
243
319
|
per-capability approval, no per-operator trust list. `oats sync` on a terminal
|
|
244
320
|
prints every executable (`commands.*` and `hooks.*.command` targets of every
|
|
245
321
|
capability the package provides) and asks `approve <id> <version>? [y/N]`.
|
|
246
|
-
Declined or non-interactive → exit `2`, the lock
|
|
247
|
-
unapproved, and spawns of souls using it are refused
|
|
248
|
-
until you run `oats sync` in a terminal and say yes.
|
|
249
|
-
approval: membership is the trust.
|
|
322
|
+
Declined, **Ctrl+D at the prompt**, or non-interactive → exit `2`, the lock
|
|
323
|
+
records the entry unapproved, and spawns of souls using it are refused
|
|
324
|
+
(`E_PACKAGE_UNAPPROVED`) until you run `oats sync` in a terminal and say yes.
|
|
325
|
+
Member capabilities need no approval: membership is the trust.
|
|
326
|
+
|
|
327
|
+
**Non-interactive approval (CI, scripted rebuilds):**
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
oats sync --approve oats.okf@v2.1.3 --approve oats.aweb@v1.11.2
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
`--approve <id>@<version>` is repeatable and approves **exactly** the entry the
|
|
334
|
+
resolution contains for that id and version — the executables digest is always
|
|
335
|
+
computed by `sync` over the fetched tree and recorded in the lock; you never
|
|
336
|
+
type a digest. An `--approve` that names an id or version the resolution does
|
|
337
|
+
not contain is an error, not a silent skip; an entry the flags do not cover
|
|
338
|
+
stays unapproved (exit `2`, as above).
|
|
250
339
|
|
|
251
340
|
## 7b. OKF 2: start a FRESH `state-dir` — do not re-point the old one
|
|
252
341
|
|
|
@@ -309,16 +398,83 @@ machine-level setting would give the seat to EVERY instance of every messaging
|
|
|
309
398
|
soul on that machine, and a seat can be held once. The Desktop's
|
|
310
399
|
confirmed apply carries the same map.
|
|
311
400
|
|
|
401
|
+
## 8b. Where the team `.aw` lives now (oats.aweb 1.11.2), and what `byTeam` does today
|
|
402
|
+
|
|
403
|
+
A freshly minted identity (every spawn without `identity.source`) needs an
|
|
404
|
+
**initialised aweb root**: a directory holding `.aw` with a team membership to
|
|
405
|
+
mint into. oats.aweb 1.11.2's spawn hook looks for `.aw` among these, first hit
|
|
406
|
+
wins: the declared team scope (`OATS_TEAM_SCOPE`, from the removed
|
|
407
|
+
`oats-config.yaml` `team:` block — **empty under v2**), the instance home, the
|
|
408
|
+
git repo containing the home, the resolution context (the soul's work repo) and
|
|
409
|
+
the git repo containing it, and the workspace root (`OATS_WORKSPACE`, which
|
|
410
|
+
under v2 is the **deployment directory** — the one holding `oats-local.yaml`).
|
|
411
|
+
None of these is the 0.24 team root you initialised with `oats aweb setup`, so
|
|
412
|
+
a rebuilt deployment mints nothing until you put `.aw` where the hook looks:
|
|
413
|
+
|
|
414
|
+
- **at the deployment directory** — `<deployment>/.aw`: one team for every
|
|
415
|
+
messaging soul spawned here; or
|
|
416
|
+
- **inside a member clone** (gitignored — add `.aw/` to the clone's
|
|
417
|
+
`.gitignore`; never commit `signing.key`): `<clone>/.aw` is found through the
|
|
418
|
+
soul's work repo, so souls whose `work:` targets *that* member mint into
|
|
419
|
+
*that* team.
|
|
420
|
+
|
|
421
|
+
`cp -R <old team root>/.aw <deployment>/.aw` (or into the clone) carries the
|
|
422
|
+
existing memberships over; `aw team list` from that directory shows the active
|
|
423
|
+
team. A `.aw` at your user home or above the deployment is **not** found on
|
|
424
|
+
purpose (a `.aw` there would be a different team; minting into it would be a
|
|
425
|
+
silent cross-team leak).
|
|
426
|
+
|
|
427
|
+
**Two teams, two identities — what actually decides the team in 1.11.2.** The
|
|
428
|
+
hook resolves the target team as: `OATS_TEAM_ID` / `OATS_TEAM_NAME` from the
|
|
429
|
+
removed `oats-config.yaml` `team:` block (empty under v2), else **the active
|
|
430
|
+
team at the `.aw` root it found**. It **does not read a `team` key from its
|
|
431
|
+
payload** (`OATS_SETTINGS`): the only payload keys 1.11.2 acts on are
|
|
432
|
+
`delivery` and `identity.source`/`identity.takeOver`. Consequently
|
|
433
|
+
`messaging.byTeam.<label>: { team: aweb:… }` is **kernel-merged and
|
|
434
|
+
delivered, but a NO-OP for oats.aweb 1.11.2** — the kernel does its part
|
|
435
|
+
(`spawn --preview` shows the merged `settings.oats.aweb` with the label's
|
|
436
|
+
`team`, and `instance.json.providers.oats.aweb` records it); the provider
|
|
437
|
+
ignores it until an oats.aweb release reads `team` from the payload. Until then
|
|
438
|
+
the only way to get per-label minting is **per-repo placement**: give each
|
|
439
|
+
team's member clone its own `.aw` whose active team is that team’s, and make
|
|
440
|
+
sure the souls of that team say `work: worktree | checkout` **on that repo**.
|
|
441
|
+
A soul with `work: directory | workspace` has no member clone as context and
|
|
442
|
+
falls through to `<deployment>/.aw` — one team only. Keep `byTeam` in the
|
|
443
|
+
workspace file anyway: it is the declared intent, the kernel honours it, and
|
|
444
|
+
the next oats.aweb picks it up without a workspace edit.
|
|
445
|
+
|
|
312
446
|
## 9. Spawn, and check drift
|
|
313
447
|
|
|
314
448
|
```bash
|
|
315
449
|
oats souls # every non-private soul of every confirmed member, with origin and team
|
|
316
450
|
oats capabilities # every capability, member (origin: member <key> @ <commit>) or package (package <id> v<ver>)
|
|
317
|
-
oats spawn <soul> --preview # modules[] with from/commit/changedSince, team, resolution revision
|
|
451
|
+
oats spawn <soul> --preview # modules[] with from/commit/changedSince, team, resolution revision,
|
|
452
|
+
# providers (the --provider map as given) and settings.<cap> (the merged payload each provider receives)
|
|
318
453
|
oats spawn <soul> --purpose x
|
|
319
|
-
oats status # per instance:
|
|
454
|
+
oats status # per instance: soul: <name> from <member> @ <c7> [member moved since …]
|
|
455
|
+
# modules … [member moved since (now @ …)] / [capability no longer present]
|
|
320
456
|
```
|
|
321
457
|
|
|
458
|
+
`--preview` (0.25.2) prints `providers` — exactly the `--provider <cap> k=v`
|
|
459
|
+
map you gave — and `settings.<cap>` — the **merged** payload the provider's
|
|
460
|
+
binding will receive (`workspace.messaging` base ⊕ `byTeam[team]` ⊕ soul slot
|
|
461
|
+
payload ⊕ `oats-local.yaml settings.<cap>` ⊕ `--provider`), so you can see
|
|
462
|
+
before creating anything that `state-dir` is the fresh one (§7b) and that the
|
|
463
|
+
team block reached the payload (§8b). `oats status` (0.25.2) shows drift for
|
|
464
|
+
the **soul source** as well as for modules: `soul: <name> from <member> @ <c7>`
|
|
465
|
+
with `[member moved since …]` when the member's default branch has moved past
|
|
466
|
+
the commit the instance was spawned from; `--json` carries it as
|
|
467
|
+
`instances[].soul { repoKey, commit, current, status }`. A moved soul is
|
|
468
|
+
information, not a fault — the running instance keeps its own commit (§7b);
|
|
469
|
+
re-spawn when you want the new one.
|
|
470
|
+
|
|
471
|
+
**Work modes and clones.** `work: worktree | checkout` needs the member clone
|
|
472
|
+
(§5 order); `work: directory` needs nothing; `work: workspace` (a coordination
|
|
473
|
+
soul) links `./work` to the **deployment directory** — the one holding
|
|
474
|
+
`oats-local.yaml`, with `agents/` and whatever clones sit beside it — read-only
|
|
475
|
+
across members, no branch (0.25.1). Such a soul finds a member whose clone is
|
|
476
|
+
elsewhere through `oats-local.yaml` `clones:`.
|
|
477
|
+
|
|
322
478
|
## What disappears
|
|
323
479
|
|
|
324
480
|
| Gone | Replaced by |
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# OATS v0.25.2 — operator-rebuild round
|
|
2
|
+
|
|
3
|
+
Kernel/Pi **0.25.2**. Tag `v0.25.2` → the commit carrying these notes; the
|
|
4
|
+
version-bump commit lands after the tag. Consumers gate on `oats version --json`
|
|
5
|
+
`features[]` names and API integers — never on the version.
|
|
6
|
+
|
|
7
|
+
**No API change.** `workspaceApi: 2`, every other API integer and the
|
|
8
|
+
`features[]` list are exactly those of [0.25.1](v0.25.1.md). The only surface
|
|
9
|
+
additions are **additive fields**: `oats spawn --preview` gains `providers` and
|
|
10
|
+
`settings`, `oats status --json` gains `instances[].soul`; `oats sync` gains
|
|
11
|
+
the `--approve` flag. Every item below comes from an operator's first rebuild
|
|
12
|
+
of a real two-team deployment on 0.25.0, following `docs/rebuild-to-v2.md`
|
|
13
|
+
literally — the guide is a contract the kernel honours. Normative record:
|
|
14
|
+
"0.25.2 operator-rebuild round" in
|
|
15
|
+
`docs/design/2026-09-23-workspace-module-contracts.md` and the matching
|
|
16
|
+
clarifications in
|
|
17
|
+
`agents/oats-expert/soul/knowledge/decisions/workspace-model-v2.md`.
|
|
18
|
+
|
|
19
|
+
## Kernel
|
|
20
|
+
|
|
21
|
+
- **R1 — member clones are found as the guide says.** For a `work: worktree |
|
|
22
|
+
checkout` soul: `--repo`, then `oats-local.yaml` `clones:` (keys normalised
|
|
23
|
+
through `parseRepoRef`), then `<deployment>/<member name>` (a member named
|
|
24
|
+
`agents` → `agents-repo`); none → `E_CLONE_MISSING` naming the three
|
|
25
|
+
remedies; a directory whose remotes name another repo → `E_CLONE_MISMATCH`.
|
|
26
|
+
- **R2 — `oats sync` creates `<deployment>/agents/` when absent.**
|
|
27
|
+
- **R3 — one "You run on OATS" block.** With `oats.core` resolved as a module
|
|
28
|
+
the kernel's legacy block is suppressed; the module's inject is the briefing.
|
|
29
|
+
- **R4 — `oats status` shows soul-source drift.** `soul: <name> from <member>
|
|
30
|
+
@ <c7> [member moved since …]` beside the module rows; `--json`
|
|
31
|
+
`instances[].soul { repoKey, commit, current, status }`.
|
|
32
|
+
- **R5 — `spawn --preview` shows the payload.** `providers` (the `--provider`
|
|
33
|
+
map as given) and `settings.<cap>` (the merged payload each provider
|
|
34
|
+
receives).
|
|
35
|
+
- **R9 — non-interactive approval.** `oats sync --approve <id>@<version>`
|
|
36
|
+
(repeatable) approves exactly the locked entry at that version; the digest is
|
|
37
|
+
always computed, never typed; an id/version not in the resolution is
|
|
38
|
+
`E_BAD_ARGS`. Ctrl+D at the interactive prompt is a decline (exit `2`).
|
|
39
|
+
- **R10 — `oats onboard` lists the host** among the clones to make, like any
|
|
40
|
+
member; an explicit `standalone:` header is named as such in the next steps.
|
|
41
|
+
|
|
42
|
+
## Documentation
|
|
43
|
+
|
|
44
|
+
- **R6** — the rebuild guide's work-mode section states that a coordination
|
|
45
|
+
soul's (`work: workspace`) `./work` is the deployment directory (0.25.1 B2).
|
|
46
|
+
- **R7 — where the team `.aw` lives now.** Rebuild guide §8b: oats.aweb 1.11.2
|
|
47
|
+
finds `.aw` among the home, the home's git repo, the soul's work repo and the
|
|
48
|
+
deployment directory — never the 0.24 team root; place it inside the member
|
|
49
|
+
clone (gitignored) or at the deployment directory. **`messaging.byTeam` is
|
|
50
|
+
kernel-merged but a no-op for oats.aweb 1.11.2**, which does not read `team`
|
|
51
|
+
from its payload; per-repo `.aw` placement is the working alternative
|
|
52
|
+
(`workspaces.md` byTeam paragraph updated accordingly).
|
|
53
|
+
- **R8 — OKF 2.1.3 reads `okf.json`, not a soul payload.** The guide, `workspaces.md`,
|
|
54
|
+
`souls-and-instances.md` and `knowledge.md` no longer show `knowledge: { owns,
|
|
55
|
+
reads }` / `{ store, root }` on `soul.yaml`: the soul's declaration is
|
|
56
|
+
`souls/<name>/okf.json` (`version`, `owner`, `owns`, `reads`); the `knowledge:`
|
|
57
|
+
payload may carry only the binding's settings (`bindings-file`, `state-dir`,
|
|
58
|
+
`harvest-runtime`, `harvest-model`); a base's `root` is the bindings file's.
|
|
59
|
+
Decision 24's example is corrected. §7b (fresh `state-dir`) confirmed.
|
|
60
|
+
- `configuration.md` `clones` row states the R1 order; `workspaces.md` and
|
|
61
|
+
`souls-and-instances.md` describe the R4/R5 fields and the per-commit soul
|
|
62
|
+
cache paths.
|
|
63
|
+
|
|
64
|
+
## Provider follow-ups (not kernel)
|
|
65
|
+
|
|
66
|
+
- **oats.aweb follow-up:** read `team` from the spawn payload (so
|
|
67
|
+
`messaging.byTeam` yields per-label identities) and accept the deployment
|
|
68
|
+
directory as a first-class aweb root. Until that release, 1.11.2 behaves as
|
|
69
|
+
§8b describes.
|
|
70
|
+
- **oats.okf follow-up:** a soul-payload grammar (`owns`/`reads` on
|
|
71
|
+
`soul.yaml`), declared in the binding when it lands; owner pin re-based on
|
|
72
|
+
identity rather than path, and per-soul harvest opt-out (2.1.4 items, unchanged).
|
|
73
|
+
|
|
74
|
+
## Known follow-ups (unchanged from 0.25.1)
|
|
75
|
+
|
|
76
|
+
- The classic (no `oats-local.yaml`) spawn path still runs the pre-v2 compose.
|
|
77
|
+
- The readiness quartet (`readinessApi: 1`) is still produced by the 0.24 tier
|
|
78
|
+
observers.
|
|
79
|
+
- `oats-local.yaml` `transport:` needs a schema addition before it can be
|
|
80
|
+
written.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# OATS v0.25.3 — `OATS_SOUL_ID`
|
|
2
|
+
|
|
3
|
+
Kernel/Pi **0.25.3**. Tag `v0.25.3` → the commit carrying these notes. No API change;
|
|
4
|
+
`features[]` unchanged; one additive hook environment variable and one additive
|
|
5
|
+
`instance.json` field.
|
|
6
|
+
|
|
7
|
+
## Kernel
|
|
8
|
+
|
|
9
|
+
- **`OATS_SOUL_ID`** — a soul's stable identity for capability hooks (`spawn`,
|
|
10
|
+
`retire`, `launch`): `<repo key>#<soul name>` for a workspace soul, the realpath of
|
|
11
|
+
`agents/<name>/soul` for a classic soul. Recorded as `instance.json.workspace.soul.id`.
|
|
12
|
+
Fixes the consequence of 0.25.1's per-commit soul cache found by the first outsider
|
|
13
|
+
rebuild: OKF 2.1.3 pins a soul's owner to `realpath(home/soul)`, which now changes with
|
|
14
|
+
every member commit → the next spawn of the same soul was refused `E_OWNER`. The provider
|
|
15
|
+
half (owners keyed by `OATS_SOUL_ID`, one-time migration of path pins) ships in OKF 2.1.4.
|
|
16
|
+
- **`OATS_SOUL` is the content the home links** — for a workspace soul the per-commit
|
|
17
|
+
directory, never the swappable `agents/<name>/soul` pointer (spawn and retire hooks agree).
|
|
18
|
+
|
|
19
|
+
Contract: `docs/design/2026-09-23-workspace-module-contracts.md` § "0.25.3 — OATS_SOUL_ID".
|