@awebai/oats 0.24.13 → 0.25.1

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 (58) hide show
  1. package/bin/oats.mjs +994 -2837
  2. package/docs/capabilities.md +136 -323
  3. package/docs/configuration.md +68 -533
  4. package/docs/conventions.md +51 -24
  5. package/docs/design/2026-09-16-fresh-operator-walkthrough.md +19 -14
  6. package/docs/design/2026-09-16-portable-migration-evidence.md +2 -0
  7. package/docs/design/2026-09-16-portable-onboarding.md +4 -2
  8. package/docs/design/2026-09-20-redesign-program-board.md +1 -1
  9. package/docs/design/2026-09-20-workspace-and-portable-adoption-plan.md +2 -0
  10. package/docs/design/2026-09-23-simplified-workspace-model.md +711 -0
  11. package/docs/design/2026-09-23-workspace-module-contracts.md +460 -0
  12. package/docs/design/2026-09-23-workspace-v2-implementation-plan.md +65 -0
  13. package/docs/design/README.md +20 -8
  14. package/docs/design/operations-contract.md +1 -0
  15. package/docs/design/package-engine-contract.md +1 -1
  16. package/docs/design/package-runtime-api.md +1 -1
  17. package/docs/desktop-cli-api.md +356 -5
  18. package/docs/desktop-succession.md +12 -6
  19. package/docs/desktop.md +9 -4
  20. package/docs/execution-targets.md +16 -4
  21. package/docs/first-team.md +107 -224
  22. package/docs/implementation.md +41 -11
  23. package/docs/integrations.md +50 -47
  24. package/docs/knowledge-capability-authoring.md +10 -4
  25. package/docs/knowledge-migration.md +21 -12
  26. package/docs/knowledge-reference/package-craft.md +11 -3
  27. package/docs/knowledge.md +60 -18
  28. package/docs/layers.md +3 -3
  29. package/docs/migration-from-oas.md +20 -9
  30. package/docs/oats-local.schema.json +50 -0
  31. package/docs/oats-membership.schema.json +23 -0
  32. package/docs/oats-workspace.schema.json +133 -48
  33. package/docs/official-marketplace.md +9 -6
  34. package/docs/packages.md +229 -440
  35. package/docs/rebuild-to-v2.md +347 -0
  36. package/docs/release-notes/v0.25.0.md +99 -0
  37. package/docs/release-notes/v0.25.1.md +94 -0
  38. package/docs/schedules.md +12 -6
  39. package/docs/soul.schema.json +41 -68
  40. package/docs/souls-and-instances.md +175 -108
  41. package/docs/workspace-adoption.md +70 -345
  42. package/docs/workspaces.md +436 -119
  43. package/lib/core.mjs +462 -61
  44. package/lib/instance-resolution.mjs +387 -0
  45. package/lib/materialize.mjs +580 -0
  46. package/lib/operator-dispatch.mjs +117 -0
  47. package/lib/packages.mjs +558 -1269
  48. package/lib/remote.mjs +718 -0
  49. package/lib/resolve.mjs +638 -0
  50. package/lib/schedule.mjs +90 -16
  51. package/lib/workspace.mjs +654 -0
  52. package/package.json +1 -1
  53. package/lib/portable-migration-artifacts.mjs +0 -135
  54. package/lib/portable-migration-evidence.mjs +0 -305
  55. package/lib/portable-migration-store.mjs +0 -199
  56. package/lib/portable-migration.mjs +0 -104
  57. package/lib/portable-onboarding-acceptance.mjs +0 -66
  58. package/lib/setup-expert-source.mjs +0 -100
@@ -25,10 +25,11 @@ knowledge layer. V2 uses external accepted bases and independent workers, not
25
25
  The required v2 spawn hook refuses a legacy `soul/knowledge/`; it never silently
26
26
  substitutes an empty bundle.
27
27
 
28
- After publication, explicitly acquire/update the catalog **Git** package and
29
- review/re-trust its executable surfaces. An existing exact lock does not advance
30
- on bare `oats install`. Do not install the npm bundled mirror as a self-contained
31
- package: npm drops the source worker's canonical `CLAUDE.md` symlink.
28
+ After publication, bump `packages.oats.okf` in the workspace file and run
29
+ `oats sync`: the new version resolves to a commit and its executables are
30
+ approved once. An existing lock never advances by itself. Package content is
31
+ read from the catalog **Git** repository, never from an npm mirror (npm drops
32
+ the source worker's canonical `CLAUDE.md` symlink).
32
33
 
33
34
  ## 2. Bind and provision external destinations
34
35
 
@@ -38,17 +39,25 @@ Choose stable base IDs, stable owner IDs, nonoverlapping node paths and durable
38
39
  permissions. Confirm aliases and owners explicitly, rather than deriving them
39
40
  from an instance branch or name.
40
41
 
41
- Configure the absolute `bindings-file` for each source soul. Remove obsolete v1
42
- settings such as `record-window-turns` and `record-window-bytes`; v2 accepts only
43
- `bindings-file`, `harvest-runtime` and `harvest-model`. Provision **empty owned
44
- nodes** using `oats okf init`. Accept Git initialization through a reviewed PR
45
- before migration delivery; directory provisioning requires explicit confirmation
46
- and a genuinely non-Git location.
42
+ Configure the absolute `bindings-file` **and** `state-dir` for each source soul
43
+ — the oats.okf 2.1.x binding requires both as normalized absolute host paths
44
+ (`setting state-dir is required (absolute host path)` is a refusal, not a
45
+ default). Remove obsolete v1 settings such as `record-window-turns` and
46
+ `record-window-bytes`; v2 accepts exactly `bindings-file`, `state-dir`,
47
+ `harvest-runtime` and `harvest-model`. Under the 0.25 workspace model these live
48
+ in `oats-local.yaml` `settings.oats.okf` ([configuration.md](configuration.md));
49
+ a rebuilt deployment gets a **fresh** `state-dir`
50
+ ([rebuild-to-v2.md §7b](rebuild-to-v2.md#7b-okf-2-start-a-fresh-state-dir-do-not-re-point-the-old-one)).
51
+ Provision **empty owned nodes** using `oats okf init`. Accept Git initialization
52
+ through a reviewed PR before migration delivery; directory provisioning requires
53
+ explicit confirmation and a genuinely non-Git location.
47
54
 
48
55
  ## 3. Stage and deliver each legacy bundle
49
56
 
50
- From the durable deployment configuration context in an operator shell without
51
- inherited instance identity, selecting the source soul:
57
+ From the deployment directory (the one holding `oats-local.yaml`) in an operator
58
+ shell without inherited instance identity, selecting the source soul with
59
+ `--soul` — the kernel resolves the command exactly as `oats spawn --soul <x>`
60
+ would ([knowledge.md](knowledge.md#inspection-and-operator-commands)):
52
61
 
53
62
  ```bash
54
63
  oats okf migrate --legacy /absolute/soul/knowledge --base project --node expert --output /absolute/empty-migration-stage --soul domain-expert --json
@@ -104,11 +104,19 @@ not satisfy a skill's missing reference if it is outside the capability root.
104
104
 
105
105
  ## Acquisition, activation and trust
106
106
 
107
- At an explicitly chosen *test* scope, acquisition and activation are separate:
107
+ In a *test* workspace, pin the package by a direct ref and give it to a soul:
108
+
109
+ ```yaml
110
+ # test workspace's oats-workspace.yaml
111
+ packages:
112
+ example.knowledge-pkg: git:/abs/path/to/source-repo.git@v0.1.0 # a tag; branches are refused
113
+ defaults:
114
+ knowledge: { example.knowledge: { from: package } }
115
+ ```
108
116
 
109
117
  ```bash
110
- oats install /path/to/source/oats-package --dir /path/to/test-scope
111
- oats use example.knowledge --global --dir /path/to/test-scope
118
+ oats sync --dir /path/to/test-workspace # resolve, lock, approve once
119
+ oats spawn <soul> --preview --json # the module as it would be materialized
112
120
  ```
113
121
 
114
122
  These are illustrative user operations, not instructions to change a live
package/docs/knowledge.md CHANGED
@@ -51,23 +51,42 @@ artifact**: npm drops the source worker's `CLAUDE.md -> AGENTS.md` symlink.
51
51
  Acquire the catalog Git payload; do not install a copied npm mirror as a local
52
52
  package or repair missing aliases in installed artifacts.
53
53
 
54
- With a released OATS >=0.23.0 kernel, acquire published OKF 2.0.0 from the
55
- intended deployment configuration context in an operator shell without inherited
56
- instance identity (an explicit `--soul` does not override an invoking instance's
57
- saved settings). The explicit Git source works before and after the v0.23.1
58
- framework catalog integration:
54
+ Under the 0.25 workspace model OKF is a **package**: pin it once in the
55
+ workspace file, let `oats sync` lock and approve it, and let every soul that
56
+ fills the knowledge slot say (or inherit) `oats.okf: { from: package }`.
57
+ Operator-level `oats okf` commands run from the deployment directory with
58
+ `--soul <name>` (an explicit `--soul` does not override an invoking instance's
59
+ saved settings — use a clean shell). The pinned version resolves through the
60
+ official catalog:
61
+
62
+ ```yaml
63
+ # oats-workspace.yaml
64
+ packages:
65
+ oats.okf: v2.1.3
66
+ defaults:
67
+ knowledge: { oats.okf: { from: package } }
68
+
69
+ # souls/domain-expert/soul.yaml
70
+ knowledge:
71
+ owns: domain-expert
72
+
73
+ # oats-local.yaml (this machine)
74
+ settings:
75
+ oats.okf:
76
+ bindings-file: /absolute/config/okf-bindings.json
77
+ state-dir: /absolute/state/okf
78
+ ```
59
79
 
60
80
  ```bash
61
- oats install git:github.com/awebai/oats-okf@v2.0.0
62
- oats trust oats.okf
63
- oats use oats.okf --soul domain-expert --settings bindings-file=/absolute/config/okf-bindings.json
64
- oats doctor --soul domain-expert --json
81
+ 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)
65
83
  ```
66
84
 
67
- Acquisition activates nothing. An existing lock remains exact until an explicit
68
- `oats update oats.okf`; v1 operators must plan migration before that update.
69
- Executable changes need review and renewed trust. Target only configured source
70
- souls; the service worker need not itself receive the knowledge layer.
85
+ Pinning activates nothing by itself: the soul's `knowledge:` payload and the
86
+ machine's `settings.oats.okf` must be bindable. The lock stays exact until the
87
+ workspace bumps `packages.oats.okf`; v1 operators must plan migration before
88
+ that bump. Executable changes come with a new version and a new approval. A
89
+ service worker need not itself fill the knowledge slot (`knowledge: none`).
71
90
 
72
91
  ### Bindings document
73
92
 
@@ -141,7 +160,9 @@ bindings, owner declarations, base metadata or indexes fail required spawn rathe
141
160
  than silently bootstrapping empty knowledge.
142
161
 
143
162
  Provisioning is an explicit operator action. Prepare node-map files (the
144
- `nodes` object above, without its wrapper), then:
163
+ `nodes` object above, without its wrapper), then run from the **deployment
164
+ directory** (the one holding `oats-local.yaml`), naming the soul whose
165
+ `knowledge:` payload and `settings.oats.okf` the command should run with:
145
166
 
146
167
  ```bash
147
168
  # New directory base: refuses an existing destination.
@@ -150,6 +171,19 @@ oats okf init --base team --nodes /absolute/config/team-nodes.json --confirm --s
150
171
  oats okf init --base project --nodes /absolute/config/project-nodes.json --output /absolute/new-bundle-stage --soul domain-expert --json
151
172
  ```
152
173
 
174
+ These run **before any instance exists**. Outside an instance home the kernel
175
+ resolves `oats okf … --soul <name>` exactly as `oats spawn <name>` would
176
+ (discover → resolve → the soul's `oats.okf` module at its locked, approved
177
+ commit), fetches that module into the deployment's module store
178
+ (`<deployment>/.oats/modules/oats.okf@<commit12>/`) and dispatches to that copy
179
+ with the soul's merged payload as `OATS_SETTINGS`; `--soul` is required
180
+ (`E_BAD_ARGS` names it) unless the namespace's capability is a workspace
181
+ default. It never runs "the newest instance's copy" and never an unapproved
182
+ cache read (`E_PACKAGE_UNAPPROVED` until `oats sync` approves the version).
183
+ *0.25.0 still answers `E_CAPABILITY_INACTIVE` here (the operator-level dispatch
184
+ lands in 0.25.1); the interim is to run the module binary directly with
185
+ `OATS_SETTINGS` and `OATS_CLI_BIN` set, as the tarball smoke does.*
186
+
153
187
  Put the Git proposal at the configured root in an operator-owned checkout and
154
188
  review/merge it through a PR before spawning working sources. Existing ownership
155
189
  changes require an explicit reviewed operator change, not harvest. The standalone
@@ -173,7 +207,7 @@ Snapshots are immutable by protocol, not live mounts. For current accepted text:
173
207
  # From the source home:
174
208
  oats okf read --base project --path expert/index.md --json
175
209
  oats okf refresh --json
176
- # From the deployment context, even after source retirement:
210
+ # From the deployment directory (oats-local.yaml), even after source retirement — --soul selects the resolution:
177
211
  oats okf read --source /absolute/state/sources/UUID/source.json --base project --path expert/index.md --soul domain-expert --json
178
212
  oats okf refresh --source /absolute/state/sources/UUID/source.json --soul domain-expert --json
179
213
  ```
@@ -273,9 +307,17 @@ spawn and command exit alone are not successful learning.
273
307
 
274
308
  ## Inspection and operator commands
275
309
 
276
- Run home-local commands from that source home. For cross-source or retired-source
277
- commands, use the durable deployment context in a clean operator shell without
278
- another instance's `OATS_*`/`PI_*` identity; select the configured source soul.
310
+ Run home-local commands from that source home: inside an instance the
311
+ dispatcher resolves `okf` from the home's materialized module
312
+ (`instance.json.modules` → `<home>/.oats/modules/oats.okf/`). For cross-source
313
+ or retired-source commands, run from the **deployment directory** (the one
314
+ holding `oats-local.yaml`) in a clean operator shell without another instance's
315
+ `OATS_*`/`PI_*` identity, and select the source soul with `--soul <name>`: the
316
+ kernel resolves that soul as a spawn would and dispatches to the deployment's
317
+ copy of its `oats.okf` module with the soul's merged payload (see
318
+ [Acquire, bind and provision explicitly](#acquire-bind-and-provision-explicitly)).
319
+ No `oats-config.yaml` chain is consulted; a namespace no module of the soul
320
+ provides is `E_UNKNOWN_COMMAND`.
279
321
 
280
322
  ```bash
281
323
  # Read-only; no capture, refresh, scheduling or worker launch:
package/docs/layers.md CHANGED
@@ -34,8 +34,8 @@ Classic `kind`/`type`/`repo` declarations and config-targeted agent types are a
34
34
 
35
35
  ## Workspace, repository and adoption contracts
36
36
 
37
- - `oats-workspace.yaml` declares intended members, defaults, imports and optional provider-owned stores/team/catalog references.
38
- - `oats.yaml` advertises a repository's actual soul/package/knowledge exports and, for membership, a workspace backlink.
37
+ - `oats-workspace.yaml` (v2) declares members, the pinned `packages:`, team labels, defaults per slot and per team, stores, the messaging payload and pinned `external:` souls.
38
+ - `oats-membership.yaml` is a repository's half of the handshake: the workspace backlink plus an optional default team label. Everything under `souls/` and `capabilities/` is discoverable by convention (`private: true` opts out); there are no export lists.
39
39
  - Membership requires compatible observations on both sides; folder adjacency or a copied declaration is not admission.
40
40
  - External source import does not adopt the publisher's workspace. A framework repository may host its own development workspace without imposing it on consumers.
41
41
  - Operator choices and workspace defaults must respect source requirements. Git read access is not write permission, executable approval or messaging enrollment.
@@ -96,7 +96,7 @@ The work target is independent of source publication and knowledge placement. Pr
96
96
 
97
97
  ## Kernel briefings versus operational capabilities
98
98
 
99
- The kernel owns only what describes the layout it creates: the `instance-boundary` briefing (home versus `work/`), the selected work-mode briefing and config-declared injections. Knowing how to *operate* OATS (status, spawn, retire, soul discovery) and how to *configure* it (workspaces, packages, trust) is capability content — accepted as the official capabilities `oats.core` (explicit default on every soul, removable) and `oats.setup` (held by the onboarding-created `oats-setup-expert`). At the0.24 baseline those skills are still kernel-shipped; see the [workspace guide](workspaces.md#how-a-soul-knows-oats-accepted-direction-not-yet-shipped) and the adoption plan's distribution packages.
99
+ The kernel owns only what describes the layout it creates: the `instance-boundary` briefing (home versus `work/`), the selected work-mode briefing and config-declared injections. Knowing how to *operate* OATS (status, spawn, retire, soul discovery) and how to *configure* it (workspaces, packages, approval) is capability content — the official capabilities `oats.core` (a workspace default via `defaults.capabilities`, removable per soul with `off`) and `oats.setup` (held by an onboarding expert), both provided by the `oats.framework` package; see [souls and instances](souls-and-instances.md#oats-operational-knowledge-is-a-capability).
100
100
 
101
101
  ## Capture and knowledge are separate
102
102
 
@@ -1,5 +1,15 @@
1
1
  # Migrating from OAS to OATS
2
2
 
3
+ > **0.25 status — this is a 0.22–0.24 procedure.** `oats migrate` and
4
+ > `oats trust` are **removed verbs** in the 0.25 kernel (`E_UNKNOWN_COMMAND`
5
+ > naming the replacement), and 0.25 reads none of the files this page
6
+ > converts to (`oats-config.yaml`, `oats-lock.json` v2, the `installed/` tier).
7
+ > An OAS deployment reaches 0.25 in two steps: run this page's commands with a
8
+ > **0.24.x** kernel (`npm install -g @awebai/oats@0.24`), then rebuild for the
9
+ > workspace model with [rebuild-to-v2.md](rebuild-to-v2.md) — which is a rewrite
10
+ > of three shared files, not a conversion, so an operator comfortable with the
11
+ > v2 declarations may skip straight to it and let the old files go.
12
+
3
13
  OATS is the successor to OAS. **OATS 0.22.0 was published on 2026-09-03**:
4
14
  the kernel, Pi adapter, and Desktop assets are available. The published
5
15
  kernel acquired the official OKF, aweb, authoring, and development packages
@@ -17,15 +27,15 @@ while its knowledge and messaging configuration remains unmigrated.
17
27
  > before activation/spawn. The v2 integration is [prepared](release-notes/v0.23.1.md),
18
28
  > not a claim that those dependencies or any deployment have already changed.
19
29
 
20
- ## Upgrade one scope
30
+ ## Upgrade one scope (0.24.x kernel)
21
31
 
22
32
  Finish or preserve active work before changing a daily-use deployment.
23
- Install OATS alongside the old CLI, then inspect the plan for the exact
24
- scope you intend to convert:
33
+ Install OATS **0.24.x** alongside the old CLI (the 0.25 line has no `oats
34
+ migrate`), then inspect the plan for the exact scope you intend to convert:
25
35
 
26
36
  ```bash
27
- npm install -g @awebai/oats@latest
28
- pi install npm:@awebai/oats-pi@latest
37
+ npm install -g @awebai/oats@0.24
38
+ pi install npm:@awebai/oats-pi@0.24
29
39
  oats migrate --from-oas --dry-run --dir /path/to/scope
30
40
  ```
31
41
 
@@ -39,10 +49,11 @@ oats doctor /path/to/scope
39
49
  ```
40
50
 
41
51
  Run the exact `oats trust <capability> --dir <scope>` commands printed by
42
- migration for the executable capabilities you approve. Trust does not
43
- transfer automatically. Verify the team ID and messaging membership with
44
- `oats aweb setup --dir /path/to/scope`, then exercise a real task, harvest,
45
- and retirement as described in [Run your first team](first-team.md).
52
+ migration for the executable capabilities you approve (0.24: per-artifact
53
+ trust; under 0.25 approval is per package version through `oats sync`). Trust
54
+ does not transfer automatically. Verify the team ID and messaging membership
55
+ with `oats aweb setup --dir /path/to/scope`, then exercise a real task,
56
+ harvest, and retirement as described in [Run your first team](first-team.md).
46
57
 
47
58
  For a multi-repository deployment, start with one scope. The explicit
48
59
  `--recursive --dir /path/to/workspace` form converts every discovered OAS
@@ -0,0 +1,50 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://oats.dev/schemas/local-v2.json",
4
+ "title": "Deployment-local overrides v2 (oats-local.yaml)",
5
+ "description": "The operator's side of a workspace: which workspace this machine realizes, where member clones live when not at the taught convention, host-owned capability settings (absolute paths belong HERE, never in the workspace file), and souls disabled on this machine. Never shared through Git.",
6
+ "type": "object",
7
+ "required": ["schemaVersion", "workspace"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "schemaVersion": { "const": 2 },
11
+ "workspace": {
12
+ "type": "string",
13
+ "minLength": 1,
14
+ "pattern": "^(?:git@[^@\\s]+|[^@\\s]+)$",
15
+ "description": "Repo ref of the workspace host; observed over the remote, need not be cloned."
16
+ },
17
+ "standalone": {
18
+ "type": "string",
19
+ "minLength": 1,
20
+ "pattern": "^(?:git@[^@\\s]+|[^@\\s]+)$",
21
+ "description": "Repo ref to realize in the STANDALONE view (decision 10): its own souls and from: here capabilities plus oats.core (decision 25), no workspace lookup. Use when the repo's workspace cannot be read; `workspace:` still names the repo you point the kernel at."
22
+ },
23
+ "clones": {
24
+ "type": "object",
25
+ "propertyNames": { "type": "string", "pattern": "^[^\\s@/][^\\s@]*/[^\\s@]+$" },
26
+ "additionalProperties": { "type": "string", "minLength": 1 },
27
+ "description": "<repo key>: <path on this machine> for member clones outside the convention."
28
+ },
29
+ "settings": {
30
+ "type": "object",
31
+ "propertyNames": { "type": "string", "pattern": "^[a-z0-9][a-z0-9._-]*$" },
32
+ "additionalProperties": {
33
+ "type": "object",
34
+ "propertyNames": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_.-]*$" }
35
+ },
36
+ "description": "<capability>: { <key>: <value> } host-owned values the manifests ask for."
37
+ },
38
+ "souls": {
39
+ "type": "object",
40
+ "additionalProperties": false,
41
+ "properties": {
42
+ "disabled": {
43
+ "type": "array",
44
+ "uniqueItems": true,
45
+ "items": { "type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$" }
46
+ }
47
+ }
48
+ }
49
+ }
50
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://oats.dev/schemas/membership-v2.json",
4
+ "title": "Repository membership backlink v2 (oats-membership.yaml)",
5
+ "description": "The repo's half of the reciprocal handshake: it names the workspace it belongs to, plus an optional default team label for the repo's items. Nothing else. A backlink is consent, not admission — the workspace must list the repo too.",
6
+ "type": "object",
7
+ "required": ["schemaVersion", "workspace"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "schemaVersion": { "const": 2 },
11
+ "workspace": {
12
+ "type": "string",
13
+ "minLength": 1,
14
+ "pattern": "^(?:git@[^@\\s]+|[^@\\s]+)$",
15
+ "description": "Repo ref of the workspace host, without revision."
16
+ },
17
+ "team": {
18
+ "type": "string",
19
+ "pattern": "^[a-z0-9][a-z0-9._-]*$",
20
+ "description": "Default team label for souls and capabilities in this repo that carry no `team:` of their own."
21
+ }
22
+ }
23
+ }
@@ -1,68 +1,153 @@
1
1
  {
2
- "$schema": "http://json-schema.org/draft-07/schema#",
3
- "$id": "https://oats.dev/schemas/workspace-v1.json",
4
- "title": "Portable workspace definition v1",
5
- "description": "Data shape only; hosting identity, reciprocal membership and provider readiness are verified separately.",
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://oats.dev/schemas/workspace-v2.json",
4
+ "title": "Workspace declaration v2 (oats-workspace.yaml)",
5
+ "description": "Data shape only. Members carry NO revision (a member is always its latest state); `external` sources REQUIRE a full 40-hex commit; absolute filesystem paths are refused anywhere in this file (host paths belong in oats-local.yaml). Reciprocal membership is observed over Git remotes, not declared here.",
6
6
  "type": "object",
7
7
  "required": ["schemaVersion", "name"],
8
8
  "additionalProperties": false,
9
9
  "properties": {
10
- "schemaVersion": { "const": 1 },
11
- "name": { "type": "string", "minLength": 1 },
12
- "members": { "type": "array", "items": { "$ref": "#/$defs/repository" } },
13
- "defaults": { "$ref": "https://oats.dev/schemas/soul-v1.json#/$defs/defaults" },
14
- "knowledge": {
15
- "type": "object", "required": ["stores"], "additionalProperties": false,
16
- "properties": { "stores": { "type": "array", "items": { "$ref": "https://oats.dev/schemas/soul-v1.json#/properties/knowledge" } } }
10
+ "schemaVersion": { "const": 2 },
11
+ "name": { "$ref": "#/$defs/slug" },
12
+ "members": {
13
+ "type": "array",
14
+ "uniqueItems": true,
15
+ "items": { "$ref": "#/$defs/memberRef" },
16
+ "description": "Repo refs without revision. Each becomes a member only when its oats-membership.yaml names this workspace back."
17
+ },
18
+ "packages": {
19
+ "type": "object",
20
+ "propertyNames": { "$ref": "#/$defs/packageId" },
21
+ "additionalProperties": { "$ref": "#/$defs/packageVersion" },
22
+ "description": "The ONLY versioned things: <package-id>: <version | git ref with @revision>."
17
23
  },
18
24
  "teams": {
19
- "type": "object", "propertyNames": { "$ref": "#/$defs/alias" },
20
- "properties": { "private": { "const": "per-human" } },
21
- "additionalProperties": {
22
- "type": "object", "required": ["provider", "id"], "additionalProperties": false,
23
- "properties": { "provider": { "$ref": "https://oats.dev/schemas/soul-v1.json#/$defs/capability" }, "id": { "type": "string", "minLength": 1 } }
24
- }
25
+ "type": "object",
26
+ "propertyNames": { "$ref": "#/$defs/label" },
27
+ "additionalProperties": { "$ref": "#/$defs/team" },
28
+ "description": "Org team labels. A label never gates, restricts or partitions anything."
29
+ },
30
+ "defaults": { "$ref": "#/$defs/defaults" },
31
+ "stores": {
32
+ "type": "object",
33
+ "propertyNames": { "$ref": "#/$defs/slug" },
34
+ "additionalProperties": { "$ref": "#/$defs/memberRef" },
35
+ "description": "Knowledge stores, declared once: <name>: <repo ref>."
25
36
  },
26
- "catalogs": {
27
- "type": "array", "items": {
28
- "type": "object", "required": ["source"], "additionalProperties": false,
29
- "properties": { "source": { "$ref": "#/$defs/source" }, "revision": { "$ref": "#/$defs/revision" }, "path": { "$ref": "#/$defs/path" } }
37
+ "messaging": {
38
+ "type": "object",
39
+ "description": "Opaque provider payload consumed by the messaging-slot capability. May carry byTeam: { <team label>: <payload> } — the kernel merges base ⊕ byTeam[soul.team] and strips byTeam before the provider sees it (decision 23).",
40
+ "properties": {
41
+ "byTeam": {
42
+ "type": "object",
43
+ "propertyNames": { "type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$" },
44
+ "additionalProperties": { "type": "object" }
45
+ }
30
46
  }
31
47
  },
32
- "imports": { "type": "array", "items": { "$ref": "#/$defs/import" } }
48
+ "external": {
49
+ "type": "array",
50
+ "items": { "$ref": "#/$defs/external" },
51
+ "description": "Souls adopted by reference from repos that are NOT members; pinned to a full commit."
52
+ }
33
53
  },
34
54
  "$defs": {
35
- "source": { "type": "string", "pattern": "^git:.+$" },
36
- "revision": { "type": "string", "minLength": 1 },
37
- "path": { "type": "string", "minLength": 1, "description": "Canonical contained repository-relative path; the shared source codec enforces semantic path rules." },
38
- "alias": { "type": "string", "pattern": "^[a-zA-Z0-9][a-zA-Z0-9._-]*$" },
39
- "repository": {
40
- "type": "object", "required": ["source"], "additionalProperties": false,
41
- "properties": { "source": { "$ref": "#/$defs/source" }, "revision": { "$ref": "#/$defs/revision" } }
55
+ "slug": { "type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$" },
56
+ "label": { "type": "string", "pattern": "^[a-z0-9][a-z0-9._-]*$" },
57
+ "capabilityName": { "type": "string", "pattern": "^[a-z0-9][a-z0-9._-]*$" },
58
+ "packageId": { "type": "string", "pattern": "^[a-z0-9][a-z0-9._-]*$" },
59
+ "packageVersion": {
60
+ "type": "string",
61
+ "minLength": 1,
62
+ "pattern": "^(?:v?\\d+(?:\\.\\d+)*(?:[-+][0-9A-Za-z.-]+)?|git:(?:git@[^@\\s/:]+:)?[^@\\s]+@(?:[0-9a-f]{40}|(?!-)(?!.*(?:\\.\\.|@\\{|\\^|~|:|\\?|\\*|\\[|\\\\|\\.lock$|\\.$|/$|^/))[!-?A-~]+))$",
63
+ "description": "Exactly two forms: a bare version (v2.1.3) resolved through the catalog, or git:<repo>@<ref> (a direct package ref). lib/packages.mjs#classifyPackageValue is the full grammar."
64
+ },
65
+ "memberRef": {
66
+ "type": "string",
67
+ "minLength": 1,
68
+ "pattern": "^(?:git@[^@\\s]+|[^@\\s]+)$",
69
+ "description": "A repo ref (git:<host>/<path>, https://…, git@host:path.git, file:///…) with NO @revision."
70
+ },
71
+ "pinnedRef": {
72
+ "type": "string",
73
+ "pattern": "^(?:git@[^@\\s]+|[^@\\s]+)@[0-9a-f]{40}$",
74
+ "description": "<repo ref>@<full 40-hex commit OID>."
75
+ },
76
+ "repoKey": {
77
+ "type": "string",
78
+ "pattern": "^[^\\s@/][^\\s@]*/[^\\s@]+$",
79
+ "description": "Canonical repo identity <host>/<path> (or local/<abs-path> for file remotes), as produced by parseRepoRef(...).key."
42
80
  },
43
- "import": {
44
- "type": "object", "required": ["source", "soul", "revision", "alias"], "additionalProperties": false,
81
+ "fromLocation": {
82
+ "anyOf": [
83
+ { "const": "package" },
84
+ { "const": "here" },
85
+ { "$ref": "#/$defs/repoKey" }
86
+ ],
87
+ "description": "WHERE a capability comes from — a location, never a version."
88
+ },
89
+ "capabilityRef": {
90
+ "type": "object",
91
+ "required": ["from"],
92
+ "additionalProperties": false,
93
+ "properties": { "from": { "$ref": "#/$defs/fromLocation" } }
94
+ },
95
+ "capabilityChoice": { "anyOf": [{ "$ref": "#/$defs/capabilityRef" }, { "const": "off" }] },
96
+ "capabilityMap": {
97
+ "type": "object",
98
+ "propertyNames": { "$ref": "#/$defs/capabilityName" },
99
+ "additionalProperties": { "$ref": "#/$defs/capabilityChoice" }
100
+ },
101
+ "slotDefault": {
102
+ "anyOf": [
103
+ { "const": "none" },
104
+ {
105
+ "type": "object",
106
+ "maxProperties": 1,
107
+ "propertyNames": { "$ref": "#/$defs/capabilityName" },
108
+ "additionalProperties": { "$ref": "#/$defs/capabilityRef" }
109
+ }
110
+ ],
111
+ "description": "At most one capability fills a slot; `none` leaves it empty."
112
+ },
113
+ "team": {
114
+ "type": "object",
115
+ "additionalProperties": false,
116
+ "properties": { "description": { "type": "string" } }
117
+ },
118
+ "defaults": {
119
+ "type": "object",
120
+ "additionalProperties": false,
45
121
  "properties": {
46
- "source": { "$ref": "#/$defs/source" },
47
- "soul": { "$ref": "#/$defs/path" },
48
- "revision": { "$ref": "#/$defs/revision" },
49
- "alias": { "type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$" },
50
- "adoption": {
51
- "type": "object", "additionalProperties": false,
52
- "properties": {
53
- "teamAliases": { "type": "object", "propertyNames": { "$ref": "#/$defs/alias" }, "additionalProperties": { "$ref": "#/$defs/alias" } },
54
- "providers": {
55
- "type": "object", "additionalProperties": false,
56
- "properties": {
57
- "knowledge": { "$ref": "https://oats.dev/schemas/soul-v1.json#/$defs/defaultProvider" },
58
- "messaging": { "$ref": "https://oats.dev/schemas/soul-v1.json#/$defs/defaultProvider" },
59
- "tasks": { "$ref": "https://oats.dev/schemas/soul-v1.json#/$defs/defaultProvider" }
60
- }
61
- },
62
- "bindings": { "type": "object" }
122
+ "capabilities": { "$ref": "#/$defs/capabilityMap" },
123
+ "knowledge": { "$ref": "#/$defs/slotDefault" },
124
+ "messaging": { "$ref": "#/$defs/slotDefault" },
125
+ "tasks": { "$ref": "#/$defs/slotDefault" },
126
+ "byTeam": {
127
+ "type": "object",
128
+ "propertyNames": { "$ref": "#/$defs/label" },
129
+ "additionalProperties": {
130
+ "type": "object",
131
+ "additionalProperties": false,
132
+ "properties": { "capabilities": { "$ref": "#/$defs/capabilityMap" } }
63
133
  }
64
134
  }
65
135
  }
136
+ },
137
+ "external": {
138
+ "type": "object",
139
+ "required": ["source", "soul"],
140
+ "additionalProperties": false,
141
+ "properties": {
142
+ "source": { "$ref": "#/$defs/pinnedRef" },
143
+ "soul": {
144
+ "type": "string",
145
+ "minLength": 1,
146
+ "pattern": "^(?![A-Za-z]:)(?!/)(?!.*(?:^|/)\\.{1,2}(?:/|$))[^/\\\\\u0000]+(?:/[^/\\\\\u0000]+)*$",
147
+ "description": "Repository-relative directory holding the soul's soul.yaml."
148
+ },
149
+ "team": { "$ref": "#/$defs/label" }
150
+ }
66
151
  }
67
152
  }
68
153
  }
@@ -10,14 +10,17 @@ or workspace membership alone does not make a package official.
10
10
  - Browse the catalog for the kernel/source version you use. Each package entry
11
11
  identifies its repository, release ref and payload root; capability aliases
12
12
  can point to the package that supplies them.
13
- - Today, `oats install <capability-or-package-id>` resolves official short names
14
- through the CLI's catalog. For example, `oats install oats.okf --dir /absolute/scope`
15
- selects the listed package; it does not enroll a team or adopt
16
- the publisher's workspace. See [package operations](packages.md).
13
+ - A workspace pins an official package by **bare version** in its
14
+ `packages:` map (`oats.okf: v2.1.3`); `oats sync` resolves it through the
15
+ catalog to an exact commit, locks it and asks for executable approval once
16
+ per version. A package outside the catalog is written `git:<repo>@<ref>`.
17
+ Pinning does not enroll a team or adopt the publisher's workspace. See
18
+ [packages](packages.md).
17
19
  - The Desktop marketplace view/search is **planned for the parity phase**, not
18
20
  shipped by this policy or by OATS 0.24. There is no new marketplace CLI verb.
19
- - **Discoverable ≠ installed ≠ approved.** Acquisition and exact locking are
20
- separate from capability selection and per-capability executable approval.
21
+ - **Discoverable ≠ pinned ≠ approved.** A catalog listing grants nothing; a
22
+ `packages:` pin selects a version; the lock's per-version approval is what
23
+ lets its executables run. Nothing is installed.
21
24
  Official status never grants trust, credentials or permission to run code.
22
25
  - Listing also does not prove that every harness, provider combination or
23
26
  deployment profile is supported. Check the package's declared compatibility,