@awebai/oats 0.24.13 → 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 +930 -2820
- 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 +324 -5
- 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.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 +90 -16
- 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/desktop-cli-api.md
CHANGED
|
@@ -18,7 +18,7 @@ prints exactly one JSON object on stdout:
|
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
`version` is the installed package's exact semver (e.g. `0.20.0`).
|
|
21
|
-
Desktop 0.
|
|
21
|
+
Desktop 0.25 accepts `desktopApi === 1` and semver `>=0.22.0 <0.26.0`
|
|
22
22
|
(the earlier Desktop 0.23 band was `>=0.22.0 <0.24.0`). This admits the paired
|
|
23
23
|
0.24 CLI without changing Desktop API v1. It does not establish complete captured
|
|
24
24
|
UI, backend, plugin, retirement or recovery parity; capability checks and explicit
|
|
@@ -58,8 +58,10 @@ infers a field that is not there:
|
|
|
58
58
|
since 0.24.8: `{spawn: boolean}`, see readiness policy).
|
|
59
59
|
- `provenance: { kind, source, revision, path, workspaceRevision } | null` —
|
|
60
60
|
where this soul copy came from, as recorded by the kernel when it created
|
|
61
|
-
it (
|
|
62
|
-
`exported-edition-copy
|
|
61
|
+
it (the 0.24 bootstrap recorded `packaged-definition` or
|
|
62
|
+
`exported-edition-copy`; the 0.25 `oats onboard` creates no soul and records
|
|
63
|
+
nothing here — see [`oats onboard`](#oats-onboard-onboardapi-2)).
|
|
64
|
+
Souls created before 0.24.7 or authored by hand
|
|
63
65
|
read `null`; render that as *unrecorded*, not as local or as anything else.
|
|
64
66
|
- `readiness` — the soul's **declared sources**, joined against
|
|
65
67
|
`result.capabilities[]` from the same payload. Distinct from launchability
|
|
@@ -483,6 +485,9 @@ is the first-run readiness view (frame 09) and the Capabilities readiness rows
|
|
|
483
485
|
deployment (no `workspace:` in `oats.yaml`), `unknown` until admission is
|
|
484
486
|
verified against the workspace observation, `pass`/`fail` when it is. Never
|
|
485
487
|
login, never team registration; "Skip" leaves it not-applicable, never pass.
|
|
488
|
+
*(The readiness producer still reads the 0.24 `oats.yaml` backlink; under the
|
|
489
|
+
workspace model membership is `oats-membership.yaml` observed by
|
|
490
|
+
`oats workspace status` — re-basing this item is an open thread.)*
|
|
486
491
|
- Subject: `--soul <name>` scopes required items to the soul's declared
|
|
487
492
|
requirements; without it, to the scope's active capabilities.
|
|
488
493
|
|
|
@@ -680,14 +685,328 @@ location. The receipt says so:
|
|
|
680
685
|
|
|
681
686
|
### Feature advertisement — gate every new command on the probe
|
|
682
687
|
|
|
683
|
-
`oats version --json` `features` now lists: `
|
|
688
|
+
`oats version --json` `features` now lists: `instance-git`,
|
|
684
689
|
`instance-git-remote`, `souls-declarations`, `lifecycle-plans`,
|
|
685
690
|
`retire-retention`, `readiness`, `spawn-preview`, `instance-events`,
|
|
686
691
|
`schedule-history`, and carries the API integers (`instanceGitApi`, `soulsApi`,
|
|
687
692
|
`lifecycleApi`, `readinessApi`, `spawnPreviewApi`, `eventsApi`,
|
|
688
693
|
`scheduleHistoryApi`). **Gate on these, never on a version string and never by
|
|
689
694
|
optimistic invocation**: an older CLI ignores an unknown `--plan` on `retire`
|
|
690
|
-
and *retires*. Absent feature → the view is unavailable.
|
|
695
|
+
and *retires*. Absent feature → the view is unavailable. (`catalog` was the
|
|
696
|
+
0.24 `oats catalog` verb's flag; the verb is removed under the workspace model
|
|
697
|
+
and the flag is no longer advertised — the official catalog is reached through
|
|
698
|
+
`packages:` + `oats sync`, not a command.)
|
|
699
|
+
|
|
700
|
+
## Workspace model (`workspaceApi: 2`)
|
|
701
|
+
|
|
702
|
+
Features: **`workspace-v2`** (the declaration files, `sync`, `package`,
|
|
703
|
+
`workspace status`, `capabilities`, `souls`; `init`/`use`/`install`/`restore`
|
|
704
|
+
removed), **`instance-modules`** (`instance.json.modules` / `providers` /
|
|
705
|
+
`workspace`; `status --json` module drift; preview `modules[]`),
|
|
706
|
+
**`spawn-provider-payload`** (`oats spawn … --provider <cap> k=v`). The probe
|
|
707
|
+
carries `workspaceApi: 2`. Model: [workspaces.md](workspaces.md).
|
|
708
|
+
|
|
709
|
+
Every command below needs a deployment with `oats-local.yaml` (walked up from
|
|
710
|
+
`--dir`/cwd) — else `E_LOCAL_MISSING { dir, searched[] }` — and reads the
|
|
711
|
+
workspace over Git remotes with the operator's credentials, never prompting
|
|
712
|
+
(`E_REMOTE_UNREADABLE { url, reason: "auth"|"not-found"|"network"|"timeout" }`).
|
|
713
|
+
Every `commit` is a full 40-hex OID; every digest is `sha256-<hex>`; every
|
|
714
|
+
`at`/`observedAt` is ISO-8601 UTC. Repo keys are canonical
|
|
715
|
+
(`github.com/org/repo`; `local/<abs-path>` for file remotes).
|
|
716
|
+
|
|
717
|
+
### Removed verbs answer `E_UNKNOWN_COMMAND` with a replacement
|
|
718
|
+
|
|
719
|
+
`install`, `restore`, `init`, `use`, `trust`, `list`, `catalog`, `remove`,
|
|
720
|
+
`migrate`, `config` — checked before capability dispatch, both modes:
|
|
721
|
+
|
|
722
|
+
```json
|
|
723
|
+
{"schemaVersion":1,"ok":false,"error":{"code":"E_UNKNOWN_COMMAND","message":"unknown command \"install\" — removed by the workspace model v2; use oats sync","details":{"removed":"install","replacement":"oats sync"}}}
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
### oats onboard (onboardApi 2)
|
|
727
|
+
|
|
728
|
+
`oats onboard [<dir>] --workspace <repo ref> [--json]`
|
|
729
|
+
|
|
730
|
+
The **bootstrap** of a deployment (decision 9): realizes a workspace on this
|
|
731
|
+
machine in the taught `<name>-workspace/` layout. It writes
|
|
732
|
+
`<dir>/oats-local.yaml` (`{ schemaVersion: 2, workspace: <ref> }`), creates
|
|
733
|
+
`<dir>/agents/` (the instance homes), then runs exactly the `oats sync` body
|
|
734
|
+
over the directory just written — discover over the remotes, confirm
|
|
735
|
+
membership, resolve `packages:`, approve (TTY) or list what needs approval,
|
|
736
|
+
write `oats-lock.json`. It installs nothing, creates no soul, spawns nothing
|
|
737
|
+
and writes no `oats-config.yaml`; the member clones and the setup-expert spawn
|
|
738
|
+
are printed as next steps. `<dir>` defaults to cwd; `--dir <d>` is the same
|
|
739
|
+
argument (give it once). `--workspace` is required and must be a ref
|
|
740
|
+
`lib/remote.mjs` parses (`E_REPO_REF`) — checked **before** anything is
|
|
741
|
+
written. Captured selectors are refused (`E_BAD_ARGS`).
|
|
742
|
+
|
|
743
|
+
```json
|
|
744
|
+
{"onboardApi":2,
|
|
745
|
+
"local":"/abs/acme-workspace/oats-local.yaml","dir":"/abs/acme-workspace","agents":"/abs/acme-workspace/agents",
|
|
746
|
+
"lock":"/abs/acme-workspace/oats-lock.json",
|
|
747
|
+
"sync":{"syncApi":1,"…":"the full sync report (next section)"},
|
|
748
|
+
"hosting":{"host":"github.com/acme/agents","hostIsMember":true,
|
|
749
|
+
"rule":"If any member is private, host oats-workspace.yaml in a private repo that is not a public member (a dedicated <org>/workspace repo); public contributors then use the standalone case (from: here capabilities + oats.core)."},
|
|
750
|
+
"next":{"clone":[{"key":"github.com/acme/agents","name":"agents","url":"https://github.com/acme/agents.git","dir":"/abs/acme-workspace/agents-repo"},
|
|
751
|
+
{"key":"github.com/acme/platform","name":"platform","url":"https://github.com/acme/platform.git","dir":"/abs/acme-workspace/platform"}],
|
|
752
|
+
"spawn":"oats spawn oats-setup-expert --dir /abs/acme-workspace"}}
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
- `sync` is the `syncApi: 1` report of the first sync (members, packages,
|
|
756
|
+
changes, `approvalNeeded`, `problems`); `lock` is the lock it wrote.
|
|
757
|
+
- **Exit `2` with `ok: true`** when `sync.approvalNeeded` is non-empty (approval
|
|
758
|
+
is interactive-only; tell the operator to run `oats sync --dir <dir>` in a
|
|
759
|
+
terminal). Exit `0` otherwise.
|
|
760
|
+
- `hosting` states decision 26 (the kernel cannot see forge visibility, so it
|
|
761
|
+
reports `hostIsMember` and the rule rather than judging).
|
|
762
|
+
- `next.clone[]` is one row per **confirmed** member (`url` = what the
|
|
763
|
+
workspace's `members:` ref resolves to; `dir` = `<dir>/<name>`, or
|
|
764
|
+
`<dir>/agents-repo` for a member called `agents`, since `agents/` is the
|
|
765
|
+
instance homes). `next.spawn` is the setup-expert spawn command string.
|
|
766
|
+
- Errors (all `E_*`): `E_BAD_ARGS` (usage; missing `--workspace`; dir given
|
|
767
|
+
twice), `E_REPO_REF`, `E_ALREADY_ONBOARDED { local, dir }` — **this**
|
|
768
|
+
directory already has `oats-local.yaml` (an enclosing deployment's file does
|
|
769
|
+
not count; run `oats sync` there instead), `E_ONBOARD_FAILED { dir }`
|
|
770
|
+
(cannot inspect/write the directory; `<dir>` exists and is not a directory).
|
|
771
|
+
Failures while **discovering** — `E_REMOTE_UNREADABLE`, `E_WORKSPACE_SCHEMA`
|
|
772
|
+
(not a workspace host), `E_LOCAL_MISSING`, plus `E_PACKAGE_MISSING` /
|
|
773
|
+
`E_PACKAGE_INTEGRITY` / `E_LOCK_SCHEMA` and the other `sync` errors raised
|
|
774
|
+
before the workspace was read — roll back the files onboarding created and
|
|
775
|
+
carry `details.rolledBack: true` and `details.dir`; a typo'd ref never
|
|
776
|
+
leaves a half-onboarded directory that looks finished. Once the workspace
|
|
777
|
+
has been read, a later failure keeps the files (a lock may exist) and
|
|
778
|
+
carries `details.dir` + `details.local` instead.
|
|
779
|
+
|
|
780
|
+
### `oats sync [--dir <d>] --json` → `syncApi: 1`
|
|
781
|
+
|
|
782
|
+
Discovers, confirms membership, resolves `packages:` to commits, writes
|
|
783
|
+
`oats-lock.json` (lockfileVersion 3), reports. **Exit `2` with `ok: true`** when
|
|
784
|
+
the lock was written but approvals are pending (`approvalNeeded` non-empty);
|
|
785
|
+
approval is interactive-only, so a Desktop must tell the operator to run
|
|
786
|
+
`oats sync` in a terminal. Exit `0` otherwise.
|
|
787
|
+
|
|
788
|
+
```json
|
|
789
|
+
{"syncApi":1,
|
|
790
|
+
"workspace":{"name":"acme","key":"github.com/acme/agents","url":"https://github.com/acme/agents.git","commit":"<oid>","observedAt":"<iso>",
|
|
791
|
+
"local":"/abs/acme-workspace/oats-local.yaml","lock":"/abs/acme-workspace/oats-lock.json"},
|
|
792
|
+
"members":[{"key":"github.com/acme/agents","name":"agents","commit":"<oid>","confirmed":true,"status":"confirmed","detail":null,"team":"global",
|
|
793
|
+
"souls":["release-manager"],"capabilities":["acme-house-style"],"publishes":null},
|
|
794
|
+
{"key":"github.com/acme/tools","name":"tools","commit":"<oid>","confirmed":true,"status":"confirmed","detail":null,"team":"engineering",
|
|
795
|
+
"souls":["tools-expert"],"capabilities":["acme-tools-dev"],"publishes":{"package":"acme.tools","version":"0.4.0"}},
|
|
796
|
+
{"key":"github.com/acme/billing","name":"billing","commit":"<oid>","confirmed":false,"status":"no-backlink","detail":"github.com/acme/billing@… has no oats-membership.yaml","team":null,
|
|
797
|
+
"souls":[],"capabilities":[],"publishes":null}],
|
|
798
|
+
"packages":[{"id":"oats.okf","version":"2.1.3","source":"catalog:oats.okf","commit":"<oid>","integrity":"sha256-…","capabilities":["oats.okf"],
|
|
799
|
+
"approved":{"executables":"sha256-…","at":"<iso>"}},
|
|
800
|
+
{"id":"acme.tools","version":"0.4.0","source":"git:github.com/acme/tools@v0.4.0","commit":"<oid>","integrity":"sha256-…","capabilities":["acme-deploy","acme-lint"],"approved":null}],
|
|
801
|
+
"changes":[{"id":"acme.tools","from":null,"to":"0.4.0","commit":"<oid>","approvalNeeded":true}],
|
|
802
|
+
"approvalNeeded":[{"id":"acme.tools","version":"0.4.0","commit":"<oid>","executables":"sha256-…",
|
|
803
|
+
"targets":["acme-deploy: command apply → bin/acme-deploy.mjs","acme-deploy: hook spawn → bin/acme-deploy.mjs"]}],
|
|
804
|
+
"problems":[]}
|
|
805
|
+
```
|
|
806
|
+
|
|
807
|
+
- `members[].status`: `confirmed` | `not-listed` | `no-backlink` |
|
|
808
|
+
`backlink-elsewhere` | `cannot-read`; `detail` explains an unconfirmed row.
|
|
809
|
+
`publishes` reports a member's `oats-package/` (informational — its
|
|
810
|
+
capabilities are **not** in `capabilities[]`; the non-collapse rule).
|
|
811
|
+
- `changes[]`: `from` = previously locked version or `null`; `to` = `null` when
|
|
812
|
+
the package was dropped from `packages:` and from the lock.
|
|
813
|
+
- `approvalNeeded[].targets` are human-readable lines
|
|
814
|
+
(`<cap>: command|hook <name> → <relpath>`); `executables` is the digest an
|
|
815
|
+
approval would record.
|
|
816
|
+
- `problems[]`: `{ code, path, message, repoKey? }` — per-item discovery
|
|
817
|
+
problems (`E_WORKSPACE_SCHEMA`, `E_TEAM_UNKNOWN`, `E_REMOTE_*`, …). Never an
|
|
818
|
+
abort: an unreadable member directory is a problem of that member.
|
|
819
|
+
- Errors: `E_LOCAL_MISSING`, `E_WORKSPACE_SCHEMA { path, problems[] }`,
|
|
820
|
+
`E_REMOTE_UNREADABLE`, `E_LOCK_SCHEMA`, `E_PACKAGE_MISSING` (catalog has no
|
|
821
|
+
such id), `E_PACKAGE_INTEGRITY { why: "branch" | locked/observed }`,
|
|
822
|
+
`E_PACKAGE_UNAPPROVED` (approval digest no longer matches),
|
|
823
|
+
`E_PACKAGE_MANIFEST`, `E_REPO_REF`.
|
|
824
|
+
|
|
825
|
+
### `oats package add <id> <version|git:<repo>@<ref>> | remove <id> [--dir] --json`
|
|
826
|
+
|
|
827
|
+
Edits `packages:` **only** when `oats-workspace.yaml` is tracked by the Git
|
|
828
|
+
checkout walked up from `--dir`; otherwise reports the line to add.
|
|
829
|
+
|
|
830
|
+
```json
|
|
831
|
+
{"action":"add","id":"oats.aweb","value":"v1.11.2","previous":null,"edited":true,"file":"/abs/agents/oats-workspace.yaml"}
|
|
832
|
+
{"action":"add","id":"oats.aweb","value":"v1.11.2","edited":false,"file":null,"line":"packages:\n oats.aweb: v1.11.2","hint":"oats-workspace.yaml is not in this checkout; commit the change in the workspace repo, then `oats sync`"}
|
|
833
|
+
```
|
|
834
|
+
|
|
835
|
+
`remove` → `{ action: "remove", id, value: null, previous: "<old value>", edited: true, file }`
|
|
836
|
+
on the tracked branch. On the untracked branch the shape is
|
|
837
|
+
`{ action: "remove", id, value: null, edited: false, file: null, line: null, hint }`
|
|
838
|
+
— **no `previous`** (nothing was read), `line: null` (there is no line to add
|
|
839
|
+
for a removal). **Both branches** answer `E_PACKAGE_MISSING { id, path? }` when
|
|
840
|
+
`<id>` is not declared in `packages:` — the untracked branch reads the file it
|
|
841
|
+
found to check the declaration even though it does not edit it. `E_USAGE`,
|
|
842
|
+
`E_WORKSPACE_SCHEMA` (bad id/value, or the edit would make the file invalid),
|
|
843
|
+
`E_REPO_REF`. No network.
|
|
844
|
+
|
|
845
|
+
### `oats workspace status [--dir] --json` → `workspaceStatusApi: 1`
|
|
846
|
+
|
|
847
|
+
```json
|
|
848
|
+
{"workspaceStatusApi":1,
|
|
849
|
+
"workspace":{"name":"acme","key":"github.com/acme/agents","url":"…","commit":"<oid>","observedAt":"<iso>","local":"/abs/…/oats-local.yaml","teams":["global","engineering"]},
|
|
850
|
+
"members":[ … same rows as sync … ],
|
|
851
|
+
"packages":[ … same rows as sync (from the lock) … ],
|
|
852
|
+
"declaredPackages":["acme.tools","oats.okf"],
|
|
853
|
+
"unsynced":[],
|
|
854
|
+
"stale":[],
|
|
855
|
+
"approval":{"approved":["oats.okf"],"needed":["acme.tools"]},
|
|
856
|
+
"external":[{"source":"git:github.com/oss-collective/experts@<oid>","soul":"security-reviewer","team":"unassigned"}],
|
|
857
|
+
"problems":[]}
|
|
858
|
+
```
|
|
859
|
+
|
|
860
|
+
`unsynced` = declared in `packages:` but not in the lock (run `sync`);
|
|
861
|
+
`stale` = locked but no longer declared. Read-only: does not write the lock.
|
|
862
|
+
|
|
863
|
+
### `oats capabilities [--dir] --json` → `capabilitiesApi: 1` · `oats souls [--dir] --json` → `soulsApi: 1`
|
|
864
|
+
|
|
865
|
+
Every **non-private** item of every confirmed member, external souls, and
|
|
866
|
+
locked package capabilities, sorted by name then origin. `origin` is the
|
|
867
|
+
human string (`member <key> @ <8-char commit>` | `package <id> v<version>` |
|
|
868
|
+
`external <key> @ <commit>`); `kind` is the machine field. `team` is the label
|
|
869
|
+
or `"unassigned"`.
|
|
870
|
+
|
|
871
|
+
```json
|
|
872
|
+
{"capabilitiesApi":1,"workspace":{"name":"acme","key":"github.com/acme/agents","commit":"<oid>"},
|
|
873
|
+
"capabilities":[
|
|
874
|
+
{"name":"acme-house-style","origin":"member github.com/acme/agents @ 3f2a9c1e","kind":"member","repoKey":"github.com/acme/agents","commit":"<oid>",
|
|
875
|
+
"team":"global","private":false,"path":"capabilities/acme-house-style","layer":null,"version":"0.0.0-workspace"},
|
|
876
|
+
{"name":"oats.okf","origin":"package oats.okf v2.1.3","kind":"package","package":"oats.okf","version":"2.1.3","commit":"<oid>",
|
|
877
|
+
"team":"unassigned","private":false,"approved":true}],
|
|
878
|
+
"problems":[]}
|
|
879
|
+
```
|
|
880
|
+
|
|
881
|
+
```json
|
|
882
|
+
{"soulsApi":1,"workspace":{…},
|
|
883
|
+
"souls":[
|
|
884
|
+
{"name":"release-manager","origin":"member github.com/acme/agents @ 3f2a9c1e","kind":"member","repoKey":"github.com/acme/agents","commit":"<oid>",
|
|
885
|
+
"team":"engineering","private":false,"path":"souls/release-manager","work":"worktree","description":"Cuts, verifies and announces releases."},
|
|
886
|
+
{"name":"security-reviewer","origin":"external github.com/oss-collective/experts @ 9c4e1f2a","kind":"external",…}],
|
|
887
|
+
"problems":[]}
|
|
888
|
+
```
|
|
889
|
+
|
|
890
|
+
Package capabilities of declared-but-unsynced packages are absent until `sync`.
|
|
891
|
+
(`soulsApi: 1` is also the integer of the existing `oats inspect --json`
|
|
892
|
+
declarations block; the two payloads are distinguished by their command.)
|
|
893
|
+
|
|
894
|
+
### `oats spawn <soul> … --preview --json` — additions (Preview API 2 unchanged)
|
|
895
|
+
|
|
896
|
+
On a workspace deployment the preview carries four extra top-level fields, and
|
|
897
|
+
`decision.resolution` binds the resolution revision (so a member that moved
|
|
898
|
+
between preview and apply is `E_DECISION_STALE`):
|
|
899
|
+
|
|
900
|
+
```json
|
|
901
|
+
{"modules":[
|
|
902
|
+
{"name":"acme-release-tooling","from":{"kind":"member","repoKey":"github.com/acme/agents","commit":"<oid>"},"layer":null,"private":false,
|
|
903
|
+
"changedSince":{"instance":"release-manager-v2","was":"<old oid>"}},
|
|
904
|
+
{"name":"oats.okf","from":{"kind":"package","package":"oats.okf","version":"2.1.3","commit":"<oid>","integrity":"sha256-…","repoKey":"github.com/awebai/oats-okf"},
|
|
905
|
+
"layer":"knowledge","private":false,"changedSince":false}],
|
|
906
|
+
"team":"engineering",
|
|
907
|
+
"resolution":"6e3050c0d005879441ab017d",
|
|
908
|
+
"workspace":"github.com/acme/agents",
|
|
909
|
+
"spawnPreviewApi":2,"preview":true,"agent":"release-manager","instance":"release-manager-cut","home":"/abs/…",
|
|
910
|
+
"decision":{"instance":"…","home":"…","branch":"…","base":{…},"effective":{…},"resolution":"6e3050c0d005879441ab017d","revision":"<24 hex>"},
|
|
911
|
+
"…":"every Preview API 2 field as before"}
|
|
912
|
+
```
|
|
913
|
+
|
|
914
|
+
- `modules[].from` is exactly the `from` recorded in `instance.json` on apply.
|
|
915
|
+
- `changedSince`: `null` (no previous instance of this soul), `false`
|
|
916
|
+
(unchanged since the newest previous instance), or
|
|
917
|
+
`{ instance, was }` (`was` = the previous commit, or `null` when the previous
|
|
918
|
+
instance had no such module).
|
|
919
|
+
- `capabilities[]` / `skills[]` keep their Preview-1 meaning; on a workspace
|
|
920
|
+
spawn the authoritative module set is `modules[]` (`capabilities[]` may be
|
|
921
|
+
empty there, since capability rows are filled after materialization).
|
|
922
|
+
- `workspace` is the workspace host's canonical key, `team` the soul's label
|
|
923
|
+
(or `null`), `resolution` the 24-hex revision `decision.resolution` binds.
|
|
924
|
+
- `--provider <cap> <key>=<value>` (repeatable; `a.b=c` nests) is accepted by
|
|
925
|
+
preview and apply. `E_BAD_ARGS` for a malformed pair or when the deployment
|
|
926
|
+
has no `oats-local.yaml`; `E_CAPABILITY_MISSING { capability, soul, modules[] }`
|
|
927
|
+
when the soul does not resolve that capability. `byTeam` is a **reserved
|
|
928
|
+
key**: legal only at the top level of the workspace file's `messaging:`;
|
|
929
|
+
anywhere else in any payload layer (soul, `oats-local.yaml` `settings`,
|
|
930
|
+
`--provider`, at any depth) it is `E_WORKSPACE_SCHEMA { reason: "reserved-key", path, key }`.
|
|
931
|
+
- Soul lookup: `E_SOUL_UNKNOWN { name, members[] }` (not among confirmed
|
|
932
|
+
members or externals), `E_SOUL_AMBIGUOUS { name, repos[] }` (name it
|
|
933
|
+
`<repo>/<soul>`). Resolution errors keep their codes (`E_NOT_A_MEMBER`,
|
|
934
|
+
`E_MEMBERSHIP_UNCONFIRMED { repoKey, reason }`, `E_CAPABILITY_MISSING { hint? }`,
|
|
935
|
+
`E_CAPABILITY_PRIVATE`, `E_PACKAGE_MISSING`, `E_PACKAGE_UNAPPROVED { id, version, commit }`,
|
|
936
|
+
`E_SLOT_CONFLICT { slot, modules[], reason? }`, `E_SKILL_DUPLICATE { name, modules[] }`,
|
|
937
|
+
`E_COMPATIBILITY { capability, package, version, range, why? }`).
|
|
938
|
+
|
|
939
|
+
The apply result (`oats spawn … --json`) is unchanged in shape; the new facts
|
|
940
|
+
live in the home's `instance.json`.
|
|
941
|
+
|
|
942
|
+
### `instance.json` — `modules`, `providers`, `workspace` (feature `instance-modules`)
|
|
943
|
+
|
|
944
|
+
Written by materialization inside the spawn transaction; read back by
|
|
945
|
+
`oats status --json` and the roster.
|
|
946
|
+
|
|
947
|
+
```json
|
|
948
|
+
{"modules":{
|
|
949
|
+
"acme-release-tooling":{"from":{"kind":"member","repoKey":"github.com/acme/agents","commit":"<oid>"},
|
|
950
|
+
"commit":"<oid>","digest":"sha256-…","materializedAt":"<iso>"},
|
|
951
|
+
"oats.okf":{"from":{"kind":"package","package":"oats.okf","version":"2.1.3","commit":"<oid>","integrity":"sha256-…","repoKey":"github.com/awebai/oats-okf"},
|
|
952
|
+
"commit":"<oid>","digest":"sha256-…","materializedAt":"<iso>"}},
|
|
953
|
+
"providers":{"acme-release-tooling":{},"oats.okf":{"owns":"release-manager","reads":["platform-engineer"],"state-dir":"/Users/ana/.oats/okf"}},
|
|
954
|
+
"workspace":{"key":"github.com/acme/agents","commit":"<oid>","resolution":"<24 hex>","standalone":false,
|
|
955
|
+
"soul":{"repoKey":"github.com/acme/agents","commit":"<oid>","team":"engineering"}},
|
|
956
|
+
"capabilities":[{"id":"oats.okf","capability":"oats.okf","origin":"package:oats.okf@2.1.3","…":"one row per module"}]}
|
|
957
|
+
```
|
|
958
|
+
|
|
959
|
+
`workspace.standalone` is `true` when the instance was spawned from the
|
|
960
|
+
**standalone view** (decisions 10/25: a *member* whose workspace could not be
|
|
961
|
+
read — `workspace.key` is then the member repo's key, and `modules` holds the
|
|
962
|
+
soul's `from: here` capabilities plus `oats.core`); `false` for a workspace
|
|
963
|
+
spawn. The same view is marked `standalone: true` in `oats sync --json` (with
|
|
964
|
+
`workspace.name` = `standalone:<repo>`) and in the roster. `capabilities[]` is
|
|
965
|
+
the per-module row set (`toCapabilityRows`) that `oats inspect`/`status` read.
|
|
966
|
+
|
|
967
|
+
`digest` is the sha256 of the copied module tree (`<home>/.oats/modules/<cap>/`);
|
|
968
|
+
`providers.<cap>` is the merged payload (soul ⊕ `oats-local.yaml`
|
|
969
|
+
`settings.<cap>` ⊕ `--provider`), `{}` for a capability with none. Copies live at
|
|
970
|
+
`<home>/.oats/modules/<cap>/` and `<home>/.agents/skills/<cap>/<skill>/`.
|
|
971
|
+
|
|
972
|
+
### `oats status [--dir] --json` — module drift
|
|
973
|
+
|
|
974
|
+
On a workspace deployment the roster does one discovery and rewrites each
|
|
975
|
+
instance's `modules` from the recorded map into **drift rows**, and adds a
|
|
976
|
+
top-level `workspace` reachability field:
|
|
977
|
+
|
|
978
|
+
```json
|
|
979
|
+
{"root":"/abs/acme-workspace/agents",
|
|
980
|
+
"agents":[{"name":"release-manager",…,"instances":[{"instance":"release-manager-cut",…,
|
|
981
|
+
"modules":[
|
|
982
|
+
{"name":"acme-release-tooling","from":{"kind":"member","repoKey":"github.com/acme/agents","commit":"<oid>"},"commit":"<oid>",
|
|
983
|
+
"current":{"commit":"<new oid>"},"status":"moved"},
|
|
984
|
+
{"name":"acme-house-style","from":{…},"commit":"<oid>","current":{"commit":"<oid>"},"status":"missing","reason":"capability-absent"},
|
|
985
|
+
{"name":"oats.okf","from":{"kind":"package",…},"commit":"<oid>","current":{"commit":"<oid>","version":"2.1.3"},"status":"current"}]}]}],
|
|
986
|
+
"workspace":{"reachable":true}}
|
|
987
|
+
```
|
|
988
|
+
|
|
989
|
+
- `status`: `current` | `moved` (member or locked package now at another
|
|
990
|
+
commit) | `missing` with `reason`: `capability-absent` (gone from the member /
|
|
991
|
+
package), `package-absent` (no longer locked), or the member's unconfirmed
|
|
992
|
+
reason (`no-backlink`, `cannot-read`, `unconfirmed`, …; `current: null`).
|
|
993
|
+
- Package modules without a lock are reported `current`.
|
|
994
|
+
- Offline: `"workspace":{"reachable":false,"code":"E_REMOTE_UNREADABLE","reason":"E_REMOTE_UNREADABLE: network","message":"…"}`
|
|
995
|
+
and `modules` stays the recorded map (no drift rows). A deployment without
|
|
996
|
+
`oats-local.yaml` has no `workspace` field and `modules` as recorded.
|
|
997
|
+
- Text mode prints `modules: <cap> from <member|package …> @ <7-char>` lines
|
|
998
|
+
for non-current modules (`--verbose` for all).
|
|
999
|
+
|
|
1000
|
+
### Probe
|
|
1001
|
+
|
|
1002
|
+
```json
|
|
1003
|
+
{"…":"…","features":["…","workspace-v2","instance-modules","spawn-provider-payload"],"workspaceApi":2}
|
|
1004
|
+
```
|
|
1005
|
+
|
|
1006
|
+
A feature is listed only once the binary implements it. Gate `sync`/`package`/
|
|
1007
|
+
`workspace status`/`capabilities`/`souls` on `workspace-v2`; gate reading
|
|
1008
|
+
`instance.json.modules` and preview `modules[]` on `instance-modules`; gate
|
|
1009
|
+
`--provider` on `spawn-provider-payload`.
|
|
691
1010
|
|
|
692
1011
|
## Instruction refresh (`oats session recompose`, feature `session-recompose`, OATS 0.24.8+)
|
|
693
1012
|
|
|
@@ -23,10 +23,9 @@ The CLI diagnoses stale references instead of failing opaquely:
|
|
|
23
23
|
|
|
24
24
|
- `oats doctor` warns when an `oats-lock.json` still pins `oats.web`, with the
|
|
25
25
|
fix spelled out.
|
|
26
|
-
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
message naming the successor and the exact cleanup steps.
|
|
26
|
+
- A soul or workspace default naming `oats.web` fails at resolution with a
|
|
27
|
+
message naming the successor and the exact cleanup steps (remove it from
|
|
28
|
+
`packages:` / the soul's `capabilities:`).
|
|
30
29
|
|
|
31
30
|
## Migrating `oats pane` usage
|
|
32
31
|
|