@awebai/oats 0.36.1 → 0.38.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 +71 -65
- package/docs/capabilities.md +64 -9
- package/docs/capability-manifest.schema.json +4 -0
- package/docs/configuration.md +16 -21
- package/docs/design/2026-09-27-team-model-v2.md +1 -1
- package/docs/design/2026-10-02-team-model-3.md +146 -0
- package/docs/design/README.md +5 -1
- package/docs/desktop-cli-api.md +159 -121
- package/docs/desktop.md +33 -0
- package/docs/first-team.md +14 -7
- package/docs/integrations.md +1 -1
- package/docs/oats-local.schema.json +2 -14
- package/docs/oats-workspace.schema.json +4 -4
- package/docs/official-catalog.md +2 -2
- package/docs/packages.md +10 -9
- package/docs/release-notes/v0.37.0.md +111 -0
- package/docs/release-notes/v0.38.0.md +128 -0
- package/docs/souls-and-instances.md +4 -3
- package/docs/workspaces.md +122 -77
- package/lib/core.mjs +123 -32
- package/lib/instance-inspect.mjs +18 -15
- package/lib/instance-resolution.mjs +9 -6
- package/lib/resolve.mjs +5 -4
- package/lib/schedule.mjs +1 -1
- package/lib/teams-verbs.mjs +44 -70
- package/lib/teams.mjs +151 -112
- package/lib/workspace.mjs +15 -5
- package/package-catalog.json +2 -2
- package/package.json +1 -1
- package/skills/oats-getting-started/SKILL.md +20 -9
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Team model 3: the teams a soul may join, and its default, are committed in the workspace
|
|
2
|
+
|
|
3
|
+
**Status:** decided and implemented (kernel 0.38.0, feature `team-model-3`; prepared in 0.36.1).
|
|
4
|
+
Specs: awebai/oats#484 and #485, agreed by both maintainers on 2026-10-02. This record supersedes the
|
|
5
|
+
membership and default-team parts of [team model v2](2026-09-27-team-model-v2.md); v2's shared teams,
|
|
6
|
+
unmapped ids, live teams and provider environment stand. The reference pages
|
|
7
|
+
([workspaces.md](../workspaces.md#teams), [capabilities.md](../capabilities.md#teams-in-the-provider-environment),
|
|
8
|
+
[desktop-cli-api.md](../desktop-cli-api.md#team-model-3-feature-team-model-3-oats-0370-replaces-feature-team-model-2))
|
|
9
|
+
win on operator-visible behaviour.
|
|
10
|
+
|
|
11
|
+
## Why
|
|
12
|
+
|
|
13
|
+
**The local bridge.** An instance that sits in two teams is a bridge between them: one process reads
|
|
14
|
+
both inboxes, holds both contexts in one session, and can relay anything from one to the other. Under
|
|
15
|
+
team model v2, one person's `oats-local.yaml` could put an organisation's instance into a team the
|
|
16
|
+
organisation never sees: a local extra team in `souls.teams`, or a local default team while its souls
|
|
17
|
+
joined the organisation's shared teams. Either way it never showed in the organisation's git, and it
|
|
18
|
+
differed per person and per machine. The organisation owns its teams' trust boundary, so the teams its
|
|
19
|
+
instances can be in are its decision, committed in its workspace, and closed by default.
|
|
20
|
+
|
|
21
|
+
**Scale.** With many souls and teams, per-deployment lists were repeated by every person on every
|
|
22
|
+
machine.
|
|
23
|
+
|
|
24
|
+
**Principle**, consistent with v2's "shared facts committed, personal choices local": everything
|
|
25
|
+
workspace-specific lives in the workspace file; souls stay team-free in their repositories, open source
|
|
26
|
+
included; an organisation says how souls behave in its teams in its own `oats-workspace.yaml`, and
|
|
27
|
+
someone running the souls standalone sees none of it.
|
|
28
|
+
|
|
29
|
+
## What it protects against, and what it does not
|
|
30
|
+
|
|
31
|
+
The workspace's eligibility rules (`souls:`, `localTeams` closed by default) **prevent accidental joins**
|
|
32
|
+
in a cooperative installation, and make the organisation's intended team set visible and reviewable in
|
|
33
|
+
its git. That is all they claim.
|
|
34
|
+
|
|
35
|
+
They are not anti-bridging enforcement, and neither is the messaging layer. Distinct keys do not prove
|
|
36
|
+
distinct processes: an operator controlling two identities can read under one and relay under the
|
|
37
|
+
other, or copy content outside the messaging layer. aweb admission controls who holds credentials for
|
|
38
|
+
a team (the team controller key signs memberships; hosted invites are mediated by the service), not
|
|
39
|
+
what a process does with what it reads. A deployment's authority comes from the credentials it holds,
|
|
40
|
+
not from its path or its name. Today's team certificates carry no soul, workspace or home-team claim,
|
|
41
|
+
and any such metadata would be self-asserted, so it would not be prevention. Enforcement on the
|
|
42
|
+
messaging side (admission per root, claims in certificates, a namespace policy, bridge visibility for a
|
|
43
|
+
team's owner) is a separate question for the aweb protocol owners.
|
|
44
|
+
|
|
45
|
+
## The model
|
|
46
|
+
|
|
47
|
+
### `oats-workspace.yaml`
|
|
48
|
+
|
|
49
|
+
```yaml
|
|
50
|
+
teams: # shared teams, as in v2
|
|
51
|
+
engineering: { team: "engineering:acme.aweb.ai" }
|
|
52
|
+
security: { team: "security:acme.aweb.ai" }
|
|
53
|
+
docs: { team: "docs:acme.aweb.ai" }
|
|
54
|
+
defaultTeam: engineering # the workspace's fallback default team (a shared label)
|
|
55
|
+
localTeams: false # may deployments declare their own teams? (absent: false)
|
|
56
|
+
souls: # per pattern: the default team and the other teams a soul may join
|
|
57
|
+
"*": { teams: [] }
|
|
58
|
+
security-souls/*: { default: security, teams: [engineering] }
|
|
59
|
+
security-souls/incident-responder: { default: security, teams: [engineering, docs] }
|
|
60
|
+
oats.engineering/*: { teams: any }
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
- **Keys are patterns:** `<member>/<soul>` or `<package>/<soul>`, `<member>/*` or `<package>/*`, and
|
|
64
|
+
`"*"`, with the names `souls.disabled` already uses. A soul's key is its qualified name. Bare names are
|
|
65
|
+
refused: a bare name is ambiguous across members, and the qualified form is what the workspace sees.
|
|
66
|
+
- **The most specific key wins outright for teams,** with no merging across levels; the default comes
|
|
67
|
+
from the most specific key that sets one. `a/*: {default: security}` and `a/x: {teams: [docs]}` give
|
|
68
|
+
`a/x` the default `security` and the teams `[docs]` only. Merging was rejected: an entry that adds to
|
|
69
|
+
a broader one hides what a soul can join behind two places, and the point of the model is that a
|
|
70
|
+
reviewer reads one entry.
|
|
71
|
+
- **`any`** is every shared team of the file.
|
|
72
|
+
- **A soul no key matches** (and no `"*"`) has its default only, member and package souls alike; a
|
|
73
|
+
workspace opens a package explicitly.
|
|
74
|
+
- **Every label is a shared team of the same file.** An unknown label, or a default that isn't one, is
|
|
75
|
+
`E_WORKSPACE_SCHEMA` when the file is read, never at a spawn on someone else's machine. A key that is
|
|
76
|
+
neither a pattern nor a discovered soul's qualified name is the warning `team-soul-unknown` (a typo
|
|
77
|
+
guard; not an error, because the file is validated without discovery and packages come and go).
|
|
78
|
+
|
|
79
|
+
### The default team, in order
|
|
80
|
+
|
|
81
|
+
1. the soul's `default` from `souls:` (`from: "soul"`);
|
|
82
|
+
2. else the deployment's `oats-local.yaml` `defaultTeam`, only when `localTeams: true`
|
|
83
|
+
(`from: "deployment"`);
|
|
84
|
+
3. else the workspace's `defaultTeam` (`from: "workspace"`);
|
|
85
|
+
4. else none (`E_TEAM_UNCONFIGURED` when a messaging layer is active).
|
|
86
|
+
|
|
87
|
+
The soul's own default comes first because it is the organisation's most specific statement; a
|
|
88
|
+
personal default, where allowed, comes before the workspace's fallback so a person can keep their own
|
|
89
|
+
default team (awebai/oats sets `localTeams: true` for this).
|
|
90
|
+
|
|
91
|
+
### The teams a soul may join
|
|
92
|
+
|
|
93
|
+
Its default, plus the `teams` of its most specific matching key, plus, with `localTeams: true`, every
|
|
94
|
+
local team the deployment declares (there is no per-soul local list: a deployment that is trusted with
|
|
95
|
+
local teams is trusted with them for every soul). Each row says why: `via` ⊂ `default`, `workspace`,
|
|
96
|
+
`local`. Unchanged from v2: an instance joins only its default at spawn; the others are offered and
|
|
97
|
+
joined on request, and the messaging provider decides admission from the eligible rows it receives in
|
|
98
|
+
`OATS_TEAMS`.
|
|
99
|
+
|
|
100
|
+
### `oats-local.yaml`
|
|
101
|
+
|
|
102
|
+
- `souls.teams` and `souls.default` are removed keys. The refusal names each key found and prints the
|
|
103
|
+
`souls:` that gives the same result (a v2 soul's teams were its default ∪ `"*"` ∪ its own list, so each
|
|
104
|
+
named soul's entry lists `"*"`'s teams too; a bare soul name is written `<member>/<soul>` for the
|
|
105
|
+
operator to qualify), so a deployment's migration is a copy, a qualification and a PR.
|
|
106
|
+
- `teams` and `defaultTeam` are allowed only when the workspace says `localTeams: true`. Otherwise every
|
|
107
|
+
spawn, preview and inspect refuses with `E_WORKSPACE_SCHEMA` (reason `local-teams-closed`), and `oats
|
|
108
|
+
teams`, readiness and doctor report it as a failure. The message names both fixes: allow local teams,
|
|
109
|
+
or commit them in the workspace and remove them locally. The rule can only be checked where the
|
|
110
|
+
workspace file has been read, so it is not part of `oats-local.yaml`'s own validation.
|
|
111
|
+
- The standalone view (explicit, or a fallback when the workspace can't be read) has no workspace rules:
|
|
112
|
+
it is an individual running souls outside any organisation, so local teams apply.
|
|
113
|
+
- Verbs: `oats teams add` and `oats teams default` refuse where local teams are closed; `oats teams
|
|
114
|
+
remove` runs there, since removing local teams is the last step of committing them in the workspace.
|
|
115
|
+
`oats soul teams` is read only; its edit flags were removed (a soul's teams are a PR to the workspace).
|
|
116
|
+
|
|
117
|
+
### `soul.yaml` and `oats-membership.yaml`
|
|
118
|
+
|
|
119
|
+
Unchanged: they say nothing about teams, so a soul in a public repository carries no organisation's
|
|
120
|
+
labels. Per-soul lists in `oats-membership.yaml` and teams in `soul.yaml` were rejected for the same
|
|
121
|
+
reason v2 rejected them: labels belong to a workspace, and there should be one central place.
|
|
122
|
+
|
|
123
|
+
## Reporting (contract)
|
|
124
|
+
|
|
125
|
+
- `defaultTeam.from` (spawn preview, `inspect`, `oats souls`, readiness, `OATS_DEFAULT_TEAM_FROM`):
|
|
126
|
+
`soul`, `deployment` or `workspace`. `soul` changed meaning: it was the local `souls.default`.
|
|
127
|
+
- Every `TeamRow` gains `via`.
|
|
128
|
+
- `oats teams --json` is `teamsApi: 2`: `localTeams`, a `DefaultTeam` for the deployment, and the
|
|
129
|
+
workspace's `souls:` in place of the local `souls` block. `oats soul teams --json` is
|
|
130
|
+
`soulTeamsApi: 2`: `match` and `defaultMatch` (the `souls:` keys that applied) in place of `local` and
|
|
131
|
+
`all`. Feature `team-model-3` replaces `team-model-2`.
|
|
132
|
+
- Readiness: local-teams-closed (failure) and `team-soul-unknown` (warning) join the team items;
|
|
133
|
+
`E_TEAM_NOT_ELIGIBLE` is no longer a kernel item (a soul's default is always one of its teams); it
|
|
134
|
+
remains the provider's join refusal.
|
|
135
|
+
|
|
136
|
+
## 0.36.x → 0.38.0
|
|
137
|
+
|
|
138
|
+
0.36.1 accepted and validated `defaultTeam`, `localTeams` and `souls:` without applying them, and warned
|
|
139
|
+
(`team-model-3-migration`) about what 0.38.0 refuses, so every workspace could commit its side first, as
|
|
140
|
+
0.29.4 did for 0.30. 0.38.0 applies the keys, refuses the old shape, and retires the warning. The steps
|
|
141
|
+
for each kind of deployment are in the [0.38.0 release notes](../release-notes/v0.38.0.md).
|
|
142
|
+
|
|
143
|
+
## Out of scope
|
|
144
|
+
|
|
145
|
+
Enforcement on the aweb side (above); nested teams; the Desktop's team-editing UI (its own spec:
|
|
146
|
+
anything that writes `souls.teams` or `souls.default` goes).
|
package/docs/design/README.md
CHANGED
|
@@ -17,7 +17,11 @@ successor, with a link to its full text.
|
|
|
17
17
|
- [OKF knowledge operations](2026-09-26-okf-knowledge-operations.md): package
|
|
18
18
|
souls, triggers and automations for harvest and maintenance.
|
|
19
19
|
- [Team model v2](2026-09-27-team-model-v2.md): shared teams in the workspace,
|
|
20
|
-
local teams, the
|
|
20
|
+
local teams, live teams and the provider environment (its membership and
|
|
21
|
+
default-team parts are superseded by team model 3).
|
|
22
|
+
- [Team model 3](2026-10-02-team-model-3.md): the teams a soul may join, and
|
|
23
|
+
its default, are committed in the workspace; local teams only where the
|
|
24
|
+
workspace allows them.
|
|
21
25
|
|
|
22
26
|
The Desktop's design brief for designers is in
|
|
23
27
|
[packages/desktop/docs](../../packages/desktop/docs/design-brief.md).
|
package/docs/desktop-cli-api.md
CHANGED
|
@@ -37,7 +37,7 @@ canonical (`github.com/<org>/<repo>`, or `local/<abs-path>`). Examples use
|
|
|
37
37
|
"instance-git-remote","souls-declarations","lifecycle-plans","retire-retention","readiness","spawn-preview","instance-events",
|
|
38
38
|
"instance-events-2","schedule-history","schedule-read-2","spawn-preview-2","spawn-idempotency","spawn-idempotency-2","spawn-apply-2",
|
|
39
39
|
"workspace-v2","instance-modules","spawn-provider-payload","served-identity","packages-no-approval","spawn-name","settings-origins",
|
|
40
|
-
"team-model-
|
|
40
|
+
"team-model-3","settings-declared","capabilities-private","layers-from","harness","package-souls","triggers","automations","desktop-facts","launch-preference",
|
|
41
41
|
"preview-composed-from","observe-max-age","spawn-preview-max-age","capability-show","capture-file","workspace-identity"],
|
|
42
42
|
"automationsApi":1,"workspaceApi":2,"instanceGitApi":1,"spawnApplyApi":1,"soulsApi":2,"lifecycleApi":1,
|
|
43
43
|
"readinessApi":2,"spawnPreviewApi":2,"eventsApi":2,"scheduleHistoryApi":3,"scheduleApi":2,"operationsApi":2,
|
|
@@ -88,7 +88,7 @@ canonical (`github.com/<org>/<repo>`, or `local/<abs-path>`). Examples use
|
|
|
88
88
|
| `settings-declared` | `declares` on inspect capabilities and preview modules | |
|
|
89
89
|
| `capabilities-private` | `private` on `oats capabilities` rows | |
|
|
90
90
|
| `layers-from` | `layers.<slot>.from` in inspect | |
|
|
91
|
-
| `team-model-
|
|
91
|
+
| `team-model-3` | every team field; `oats teams`, `oats soul teams` (0.38.0; replaces `team-model-2`) | `teamsApi: 2`, `soulTeamsApi: 2` (payload only) |
|
|
92
92
|
| `harness` | the harness names ([Harness input spellings](#the-harness-rename-feature-harness-oats-0270)) | |
|
|
93
93
|
| `package-souls` | package soul rows, `qualifiedName`, `packages[].souls` | |
|
|
94
94
|
| `triggers` | `oats trigger …` | `triggerApi: 1` (payload only) |
|
|
@@ -253,9 +253,11 @@ oats capabilities show <name> … --max-age <seconds> --json (feature capabilit
|
|
|
253
253
|
commit can no longer be fetched. Each is observed live, as without the flag.
|
|
254
254
|
A live observation that fails is the usual error, never an older head.
|
|
255
255
|
- **Refusals:** every other command, a spawn apply (with or without
|
|
256
|
-
`--expect-decision`; the form named is `spawn`), every edit form (`teams add|remove|default
|
|
257
|
-
|
|
258
|
-
invocation refuse the flag before reading or writing anything
|
|
256
|
+
`--expect-decision`; the form named is `spawn`), every edit form (`teams add|remove|default`)
|
|
257
|
+
and any `--server`
|
|
258
|
+
invocation refuse the flag before reading or writing anything (the removed
|
|
259
|
+
`soul teams --add|--remove|--default|--clear-default` answer their own
|
|
260
|
+
`E_BAD_ARGS` first), with
|
|
259
261
|
`E_BAD_ARGS` "--max-age is not accepted by \`oats <form>\`: only the read
|
|
260
262
|
verbs reuse observations (status, workspace status, souls, capabilities,
|
|
261
263
|
capabilities show, inspect --soul|--home, spawn --preview, and the read
|
|
@@ -397,7 +399,8 @@ message}`.
|
|
|
397
399
|
A soul whose resolution is refused is an inspect error with the resolver's
|
|
398
400
|
code and details (`E_PACKAGE_MISSING`, `E_PACKAGE_INTEGRITY`,
|
|
399
401
|
`E_CAPABILITY_MISSING`, `E_LOCK_SCHEMA`, `E_REQUIREMENT_INACTIVE`,
|
|
400
|
-
`E_TEAM_UNKNOWN`, `
|
|
402
|
+
`E_TEAM_UNKNOWN`, and `E_WORKSPACE_SCHEMA` reason `local-teams-closed`);
|
|
403
|
+
readiness reports the same condition
|
|
401
404
|
as an item. Soul lookup errors are those of [spawn](#spawn-errors).
|
|
402
405
|
|
|
403
406
|
<a id="oats-readiness---home-----soul----dir----policy---json--readinessapi-2"></a>
|
|
@@ -595,6 +598,7 @@ A removed verb answers, before any namespace can claim it:
|
|
|
595
598
|
| `status --team` | `E_BAD_ARGS` | `oats status` in the deployment |
|
|
596
599
|
| `spawn --instance` | `E_BAD_ARGS` | `--purpose` or `--name` |
|
|
597
600
|
| `spawn --ephemeral`, `--instructions-file`, `--def-file` | `E_BAD_ARGS` | a soul in a member repository |
|
|
601
|
+
| `soul teams --add`, `--remove`, `--default`, `--clear-default` (0.38.0) | `E_BAD_ARGS` (`details: {flag, replacement}`) | `souls:` in `oats-workspace.yaml` |
|
|
598
602
|
| `session … --native-record` | `E_BAD_ARGS` | none |
|
|
599
603
|
|
|
600
604
|
`details.replacement` is the kernel's prose (shortened above): show it, do not
|
|
@@ -750,7 +754,7 @@ Read-only (it writes no lock):
|
|
|
750
754
|
- `declaredPackages`: the ids in `packages:` (standalone: the kernel's
|
|
751
755
|
default). `unsynced`: declared, not locked. `stale`: locked, no longer
|
|
752
756
|
declared. `external[]`: `{source, soul}`.
|
|
753
|
-
- `workspace.teams` (feature `team-model-
|
|
757
|
+
- `workspace.teams` (feature `team-model-3`): the shared teams `{label, team,
|
|
754
758
|
description}` by label; `[]` standalone.
|
|
755
759
|
- `problems`, `warnings`: as in sync.
|
|
756
760
|
- `automations` (feature `automations`): `{host, snapshot: {takenAt,
|
|
@@ -788,7 +792,7 @@ packages' capabilities and souls, sorted by name, then origin. Both carry
|
|
|
788
792
|
"version":"4.1.1","repoKey":"github.com/awebai/oats-okf","commit":"e1d604f7…","teams":null,"defaultTeam":null,"private":false,
|
|
789
793
|
"path":"oats-package/souls/knowledge-maintainer","work":"directory","description":"Reviews harvested knowledge.","harness":"pi","model":null,
|
|
790
794
|
"harnessFrom":"kernel-default","file":{"path":"oats-package/souls/knowledge-maintainer/soul.yaml","url":null},
|
|
791
|
-
"spawnable":false,"problem":{"code":"E_TEAM_UNKNOWN","message":"team \"reviewers\" is not declared (oats-local.yaml#/
|
|
795
|
+
"spawnable":false,"problem":{"code":"E_TEAM_UNKNOWN","message":"team \"reviewers\" is not declared (oats-local.yaml#/defaultTeam): …"}}],
|
|
792
796
|
"problems":[]}
|
|
793
797
|
```
|
|
794
798
|
|
|
@@ -804,13 +808,13 @@ are absent until `sync`.
|
|
|
804
808
|
commit, teams, defaultTeam, private (always false), path, work, description`,
|
|
805
809
|
plus the Desktop facts `harness, model, harnessFrom, file, spawnable,
|
|
806
810
|
problem`, and (feature `launch-preference`) `key` and `launch`.
|
|
807
|
-
- `key` is the soul key that `souls.
|
|
808
|
-
|
|
811
|
+
- `key` is the soul key that `souls.launch` uses, and that
|
|
812
|
+
`oats soul teams <key>` takes: `qualifiedName` for a package
|
|
809
813
|
soul, the bare `name` for a member or external soul. Two member souls that
|
|
810
814
|
share a bare name share one entry (spawning that name is
|
|
811
815
|
`E_SOUL_AMBIGUOUS`).
|
|
812
816
|
- `launch` is a [Launch](#the-launch-report-launch).
|
|
813
|
-
- `teams` and `defaultTeam` (feature `team-model-
|
|
817
|
+
- `teams` and `defaultTeam` (feature `team-model-3`) are a
|
|
814
818
|
[TeamRow](#the-team-row-teamrow) list and a
|
|
815
819
|
[DefaultTeam](#the-default-defaultteam); both `null` when the soul's teams
|
|
816
820
|
do not resolve (`problem` names the `E_TEAM_*` code).
|
|
@@ -1012,7 +1016,7 @@ them. Gate each field below on it.
|
|
|
1012
1016
|
v2 soul.yaml cannot). `spawnable`/`problem`: whether a spawn here would
|
|
1013
1017
|
refuse, resolved without spawning, writing or reaching past the sync cache;
|
|
1014
1018
|
`problem` is `{code, message}` or `null` (`E_SOUL_DISABLED`,
|
|
1015
|
-
`E_TEAM_UNKNOWN`, `
|
|
1019
|
+
`E_TEAM_UNKNOWN`, `E_WORKSPACE_SCHEMA` (local-teams-closed), `E_CAPABILITY_*`, `E_PACKAGE_*`,
|
|
1016
1020
|
`E_LOCK_SCHEMA`, `E_REMOTE_*`, …). `file`: `{path, url}` of soul.yaml.
|
|
1017
1021
|
- **Capabilities.** `layer` on every row, `null` outside the slots.
|
|
1018
1022
|
`description` or `null`. `skills`, `commands`, `hooks`: names, sorted
|
|
@@ -1039,61 +1043,91 @@ them. Gate each field below on it.
|
|
|
1039
1043
|
`…/tree/<commit>`); any other host gives `url: null` with `path` set.
|
|
1040
1044
|
`path` is repository-relative.
|
|
1041
1045
|
|
|
1046
|
+
<a id="team-model-3-feature-team-model-3-oats-0370-replaces-feature-team-model-2"></a>
|
|
1042
1047
|
<a id="team-model-v2-feature-team-model-2-oats-0300-replaces-feature-teams"></a>
|
|
1043
1048
|
## Teams
|
|
1044
1049
|
|
|
1045
|
-
Feature `team-model-
|
|
1046
|
-
[team model
|
|
1047
|
-
[workspaces.md](workspaces.md).
|
|
1048
|
-
|
|
1049
|
-
- **
|
|
1050
|
-
`teams.<label> = {description?, team?}
|
|
1051
|
-
provider id
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1050
|
+
Feature `team-model-3` (OATS 0.38.0; it replaces `team-model-2`): gate every
|
|
1051
|
+
team field and verb on it. Design: [team model 3](design/2026-10-02-team-model-3.md);
|
|
1052
|
+
operator guide: [workspaces.md](workspaces.md#teams).
|
|
1053
|
+
|
|
1054
|
+
- **The workspace file** (`oats-workspace.yaml`, committed) holds the shared
|
|
1055
|
+
teams `teams.<label> = {description?, team?}` (a shared team without `team`,
|
|
1056
|
+
the provider id, is **unmapped**), `defaultTeam: <label>` (the workspace's
|
|
1057
|
+
fallback default), `localTeams: true|false` (absent: false) and `souls:`
|
|
1058
|
+
(per pattern, `{default?, teams?: [labels] | "any"}`). Every label there is
|
|
1059
|
+
a shared label of that file; anything else is `E_WORKSPACE_SCHEMA` when the
|
|
1060
|
+
file is read.
|
|
1061
|
+
- **`oats-local.yaml`** may declare local teams `teams.<label> = {team,
|
|
1062
|
+
description?}` and `defaultTeam: <label>` only where the workspace says
|
|
1063
|
+
`localTeams: true`, or in the standalone view (no workspace file is read).
|
|
1064
|
+
Elsewhere they are refused: `E_WORKSPACE_SCHEMA` with details `{reason:
|
|
1065
|
+
"local-teams-closed", path: "oats-local.yaml", keys}`, the message naming
|
|
1066
|
+
both fixes. `souls.teams` and `souls.default` are removed keys
|
|
1067
|
+
(`E_WORKSPACE_SCHEMA`, reason `removed-key`): the refusal names each key
|
|
1068
|
+
found, and `details.replacement` is the `souls:` YAML to commit instead (a
|
|
1069
|
+
bare soul name written `<member>/<soul>` for the operator to qualify), also
|
|
1070
|
+
printed at the end of the message. Every command that reads the file
|
|
1071
|
+
refuses, an instance home's messaging commands, operations, `inspect --home`
|
|
1072
|
+
and `readiness --home` included: they never fall back to the home's
|
|
1073
|
+
recorded teams for it. A home's other capability commands read only the
|
|
1074
|
+
home's own record, as always.
|
|
1075
|
+
- **A soul's key** is its qualified name: `<package>/<soul>`, or
|
|
1076
|
+
`<member>/<soul>` with the member repository's name (as `souls.disabled`
|
|
1077
|
+
names it). A label matches `[a-z0-9][a-z0-9._-]*`.
|
|
1057
1078
|
- **Team ids.** A `team` value (in either file, and `oats teams add --team`)
|
|
1058
1079
|
matches `^[A-Za-z0-9][A-Za-z0-9._:@/+-]{0,255}$`: the kernel's safety rule
|
|
1059
1080
|
(never `-`-led, no whitespace or control characters, bounded). Otherwise
|
|
1060
1081
|
`E_WORKSPACE_SCHEMA` (a file) or `E_BAD_ARGS` (the verb). The messaging
|
|
1061
1082
|
provider validates its own id shape (oats.aweb: `<name>:<namespace>`).
|
|
1062
|
-
- **Resolution.** The
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
`
|
|
1067
|
-
`
|
|
1083
|
+
- **Resolution.** The `souls:` patterns for a soul are its key, then
|
|
1084
|
+
`<member|package>/*`, then `"*"`. The most specific one that exists gives
|
|
1085
|
+
the soul's teams outright (lists never merge); the most specific one that
|
|
1086
|
+
sets `default` gives its default. So `a/*: {default: security}` and
|
|
1087
|
+
`a/x: {teams: [docs]}` give `a/x` the default `security` and the teams
|
|
1088
|
+
`[docs]` only. The default is that `default`; else the local `defaultTeam`
|
|
1089
|
+
where local teams are allowed; else the workspace's `defaultTeam`; else
|
|
1090
|
+
none. A soul's teams are its default, its pattern's `teams` (`any`: every
|
|
1091
|
+
shared team) and, where local teams are allowed, every local team. A soul
|
|
1092
|
+
no pattern matches has its default only. A label in both files is a
|
|
1093
|
+
`team-label-collision` warning, and the shared definition wins. A local
|
|
1094
|
+
default no file declares is `E_TEAM_UNKNOWN`.
|
|
1068
1095
|
- **Removed keys** are `E_WORKSPACE_SCHEMA` with `reason: "removed-key"`:
|
|
1096
|
+
`oats-local.yaml` `souls.teams` and `souls.default` (0.38.0);
|
|
1069
1097
|
`messaging.byTeam`, `defaults.byTeam`, a soul.yaml `team`, an
|
|
1070
|
-
oats-membership.yaml `team`, and `byTeam` in any provider payload layer
|
|
1071
|
-
Other payload keys are opaque (a `team` setting passes through).
|
|
1098
|
+
oats-membership.yaml `team`, and `byTeam` in any provider payload layer
|
|
1099
|
+
(0.30). Other payload keys are opaque (a `team` setting passes through).
|
|
1072
1100
|
|
|
1073
1101
|
### The team row (`TeamRow`)
|
|
1074
1102
|
|
|
1075
|
-
Exactly `{label, team, default, from}`:
|
|
1103
|
+
Exactly `{label, team, default, from, via}`:
|
|
1076
1104
|
|
|
1077
1105
|
```json
|
|
1078
|
-
[{"label":"
|
|
1079
|
-
{"label":"
|
|
1080
|
-
{"label":"
|
|
1106
|
+
[{"label":"security","team":"security:acme.aweb.ai","default":true,"from":"shared","via":["default"]},
|
|
1107
|
+
{"label":"docs","team":null,"default":false,"from":"shared","via":["workspace"]},
|
|
1108
|
+
{"label":"mine","team":"mine:ana.aweb.ai","default":false,"from":"local","via":["local"]}]
|
|
1081
1109
|
```
|
|
1082
1110
|
|
|
1083
1111
|
`team` is `null` for an unmapped team. `default` is true on exactly the
|
|
1084
1112
|
soul's default row; the others are teams an instance may join (offered, never
|
|
1085
|
-
joined automatically). `from` is `"shared"` or
|
|
1086
|
-
|
|
1087
|
-
|
|
1113
|
+
joined automatically). `from` is where the label is defined: `"shared"` or
|
|
1114
|
+
`"local"`. `via` is why the soul may join it, an ordered non-empty subset of
|
|
1115
|
+
`"default"`, `"workspace"` (its `souls:` pattern) and `"local"` (a local team
|
|
1116
|
+
where local teams are allowed). The default row comes first, then the rest by
|
|
1117
|
+
label (codepoint order). Reports include unmapped rows; `OATS_TEAMS` and
|
|
1118
|
+
`instance.json.teams` carry mapped rows only. A home spawned before 0.38.0
|
|
1119
|
+
recorded rows without `via`, and they are reported as recorded.
|
|
1088
1120
|
|
|
1089
1121
|
### The default (`DefaultTeam`)
|
|
1090
1122
|
|
|
1091
1123
|
```json
|
|
1092
|
-
{"label":"
|
|
1124
|
+
{"label":"security","team":"security:acme.aweb.ai","from":"soul"}
|
|
1093
1125
|
```
|
|
1094
1126
|
|
|
1095
|
-
`from` is `"
|
|
1096
|
-
|
|
1127
|
+
`from` is `"soul"` (the soul's `souls:` default in the workspace file; before
|
|
1128
|
+
0.38.0 it meant `oats-local.yaml` `souls.default`), `"deployment"` (the local
|
|
1129
|
+
`defaultTeam`) or `"workspace"` (the workspace's `defaultTeam`). It is `null`
|
|
1130
|
+
only when no default is configured (with messaging active, that is
|
|
1097
1131
|
`E_TEAM_UNCONFIGURED`). An unmapped default is `{label, team: null, from}`,
|
|
1098
1132
|
the blocking problem `team-unmapped`.
|
|
1099
1133
|
|
|
@@ -1119,9 +1153,12 @@ its spawn-time default until respawned (readiness says so with
|
|
|
1119
1153
|
the teams in `OATS_DEFAULT_TEAM`, `OATS_DEFAULT_TEAM_ID`,
|
|
1120
1154
|
`OATS_DEFAULT_TEAM_FROM`, `OATS_TEAMS` and `OATS_TEAMS_SOURCE`:
|
|
1121
1155
|
[capabilities.md](capabilities.md#teams-in-the-provider-environment).
|
|
1122
|
-
`
|
|
1123
|
-
|
|
1156
|
+
`OATS_TEAMS` is exactly the soul's eligible mapped rows, so a provider that
|
|
1157
|
+
admits joins from it refuses any other team. `OATS_WORKSPACE_NAME` is the
|
|
1158
|
+
recorded workspace name (the discovered one for a soul subject), `""` when
|
|
1159
|
+
unknown.
|
|
1124
1160
|
|
|
1161
|
+
<a id="oats-teams"></a>
|
|
1125
1162
|
### `oats teams`
|
|
1126
1163
|
|
|
1127
1164
|
```text
|
|
@@ -1132,66 +1169,75 @@ oats teams default <label> --json
|
|
|
1132
1169
|
```
|
|
1133
1170
|
|
|
1134
1171
|
```json
|
|
1135
|
-
{"teamsApi":
|
|
1136
|
-
"teams":[{"label":"
|
|
1137
|
-
{"label":"
|
|
1138
|
-
"souls":{"
|
|
1139
|
-
"problems":[{"code":"team-unmapped","label":"
|
|
1140
|
-
"message":"shared team
|
|
1172
|
+
{"teamsApi":2,"deployment":"/w","localTeams":true,"defaultTeam":{"label":"mine","team":"mine:ana.aweb.ai","from":"deployment"},
|
|
1173
|
+
"teams":[{"label":"mine","team":"mine:ana.aweb.ai","description":null,"from":"local","default":true,"at":"oats-local.yaml#/teams/mine"},
|
|
1174
|
+
{"label":"docs","team":null,"description":null,"from":"shared","default":false,"at":"github.com/acme/agents:oats-workspace.yaml#/teams/docs"}],
|
|
1175
|
+
"souls":{"*":{"teams":["docs"]},"security-souls/*":{"default":"security","teams":["engineering"]}},
|
|
1176
|
+
"problems":[{"code":"team-unmapped","label":"docs","default":false,"severity":"warning","at":"github.com/acme/agents:oats-workspace.yaml#/teams/docs",
|
|
1177
|
+
"message":"shared team docs has no provider id yet","fix":"its owner runs `oats aweb setup`, then commits the id"}]}
|
|
1141
1178
|
```
|
|
1142
1179
|
|
|
1143
|
-
- `
|
|
1180
|
+
- `localTeams`: the workspace's answer (`true`/`false`), `null` in the
|
|
1181
|
+
standalone view. `defaultTeam` is the `DefaultTeam` a soul without a
|
|
1182
|
+
`souls:` default gets here (`from` `"deployment"` or `"workspace"`), or
|
|
1183
|
+
`null`.
|
|
1144
1184
|
- `teams[]`: every declared team by label, `{label, team, description, from,
|
|
1145
|
-
default, at}`; `at` is a pointer into
|
|
1146
|
-
`<workspace key>:oats-workspace.yaml#/teams/<label>`.
|
|
1147
|
-
shared definition.
|
|
1148
|
-
- `souls`:
|
|
1149
|
-
deployment's [team readiness items](#team-readiness-items).
|
|
1185
|
+
default, at}`; `default` marks that `defaultTeam`; `at` is a pointer into
|
|
1186
|
+
`oats-local.yaml` or `<workspace key>:oats-workspace.yaml#/teams/<label>`.
|
|
1187
|
+
A collision shows the shared definition.
|
|
1188
|
+
- `souls`: the workspace's `souls:` as committed (`{}` when none).
|
|
1189
|
+
`problems`: the deployment's [team readiness items](#team-readiness-items).
|
|
1190
|
+
The command discovers the workspace (every member's souls), for the
|
|
1191
|
+
`team-soul-unknown` check.
|
|
1150
1192
|
- The verbs never call a provider. They validate, rewrite `oats-local.yaml` in
|
|
1151
1193
|
place, and answer the document plus `changed: bool`.
|
|
1152
|
-
-
|
|
1153
|
-
|
|
1154
|
-
`
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1194
|
+
- **Where local teams are not allowed**, `add` and `default` are refused
|
|
1195
|
+
before anything is written: `E_WORKSPACE_SCHEMA {reason:
|
|
1196
|
+
"local-teams-closed", path, keys}` (`keys` what the verb writes). `remove`
|
|
1197
|
+
still runs there: taking local teams away is the last step of committing
|
|
1198
|
+
them in the workspace.
|
|
1199
|
+
- **`add`**: the first team added also becomes the local `defaultTeam`. A
|
|
1200
|
+
label already declared is `E_TEAM_EXISTS {label, from}`; a bad label or no
|
|
1201
|
+
`--team` is `E_BAD_ARGS`.
|
|
1202
|
+
- **`remove`**: a label the local `defaultTeam` names is `E_TEAM_IN_USE
|
|
1203
|
+
{label, usedBy: ["defaultTeam"]}`; a shared label is `E_TEAM_SHARED {label,
|
|
1204
|
+
at}` (a label in both files can be removed locally); unknown is
|
|
1205
|
+
`E_TEAM_UNKNOWN {label}`.
|
|
1159
1206
|
- **`default`**: any declared label, else `E_TEAM_UNKNOWN`.
|
|
1160
|
-
- A write that would introduce an unknown
|
|
1161
|
-
|
|
1207
|
+
- A write that would introduce an unknown reference is refused with that
|
|
1208
|
+
code; an invalid result is `E_WORKSPACE_SCHEMA`.
|
|
1209
|
+
- **Writes** edit `oats-local.yaml` in place and touch only the entries that
|
|
1210
|
+
change: comments and styles elsewhere, including inline comments on sibling
|
|
1211
|
+
entries, are kept. Each verb re-reads the file and judges its refusals on it
|
|
1212
|
+
as it is now, and writes only if the file did not change meanwhile (else it
|
|
1213
|
+
redoes the edit on the new content). A file that keeps changing is
|
|
1214
|
+
`E_LOCAL_CHANGED {path}`; nothing was written.
|
|
1162
1215
|
|
|
1216
|
+
<a id="oats-soul-teams"></a>
|
|
1163
1217
|
### `oats soul teams`
|
|
1164
1218
|
|
|
1165
1219
|
```text
|
|
1166
|
-
oats soul teams <soul>|'*' [--
|
|
1167
|
-
oats soul teams <soul>|'*' [--dir <d>] [--max-age <s>] --json (the read form only)
|
|
1220
|
+
oats soul teams <soul>|'*' [--dir <d>] [--max-age <s>] --json
|
|
1168
1221
|
```
|
|
1169
1222
|
|
|
1170
1223
|
```json
|
|
1171
|
-
{"soulTeamsApi":
|
|
1172
|
-
"
|
|
1173
|
-
|
|
1174
|
-
"
|
|
1224
|
+
{"soulTeamsApi":2,"soul":"incident-responder","key":"security-souls/incident-responder",
|
|
1225
|
+
"match":"security-souls/incident-responder","defaultMatch":"security-souls/*",
|
|
1226
|
+
"defaultTeam":{"label":"security","team":"security:acme.aweb.ai","from":"soul"},
|
|
1227
|
+
"teams":[{"label":"security","team":"security:acme.aweb.ai","default":true,"from":"shared","via":["default"]},
|
|
1228
|
+
{"label":"docs","team":null,"default":false,"from":"shared","via":["workspace"]},
|
|
1229
|
+
{"label":"engineering","team":"engineering:acme.aweb.ai","default":false,"from":"shared","via":["workspace"]}]}
|
|
1175
1230
|
```
|
|
1176
1231
|
|
|
1177
|
-
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
`'*'`, or both together: `E_BAD_ARGS`. Soul lookup: `E_SOUL_UNKNOWN`,
|
|
1187
|
-
`E_SOUL_AMBIGUOUS`.
|
|
1188
|
-
- **Writes** (`oats teams add|remove|default`, `oats soul teams`) edit
|
|
1189
|
-
`oats-local.yaml` in place and touch only the entries that change: comments
|
|
1190
|
-
and styles elsewhere, including inline comments on sibling entries and flow
|
|
1191
|
-
lists, are kept. Each verb re-reads the file and judges its refusals on it
|
|
1192
|
-
as it is now, and writes only if the file did not change meanwhile (else it
|
|
1193
|
-
redoes the edit on the new content). A file that keeps changing is
|
|
1194
|
-
`E_LOCAL_CHANGED {path}`; nothing was written.
|
|
1232
|
+
- Read only. `key` is the soul's key; `match` the `souls:` key its teams come
|
|
1233
|
+
from and `defaultMatch` the one its default comes from (`null`: none
|
|
1234
|
+
matches, or none sets a default). For `'*'`, `soul`, `key` and the only
|
|
1235
|
+
pattern tried are `"*"`. Soul lookup: `E_SOUL_UNKNOWN`, `E_SOUL_AMBIGUOUS`;
|
|
1236
|
+
the soul's teams: `E_WORKSPACE_SCHEMA` (local-teams-closed), `E_TEAM_UNKNOWN`.
|
|
1237
|
+
- The edit flags `--add`, `--remove`, `--default` and `--clear-default` were
|
|
1238
|
+
removed in 0.38.0: `E_BAD_ARGS` with details `{flag, replacement: "souls: in
|
|
1239
|
+
oats-workspace.yaml (a PR to the workspace file)"}`, before anything else
|
|
1240
|
+
is judged.
|
|
1195
1241
|
|
|
1196
1242
|
### The messaging provider's teams document
|
|
1197
1243
|
|
|
@@ -1218,8 +1264,9 @@ no `primary` and no `unmapped`: unmapped teams are kernel readiness items.
|
|
|
1218
1264
|
`oats teams` lists them under `problems[]` as `{code, severity: "failure" |
|
|
1219
1265
|
"warning", message, fix, …}`. `oats readiness` lists the soul's under
|
|
1220
1266
|
`checks.configured` with `subject` `"team <label>"` (or `"teams"`), `producer:
|
|
1221
|
-
"team model"`, `code`, `reason
|
|
1222
|
-
for a failure and `false` for a warning, plus the
|
|
1267
|
+
"team model"`, `code`, `reason` (the message), `remedy` (the fix), `status:
|
|
1268
|
+
"fail"`, `required: true` for a failure and `false` for a warning, plus the
|
|
1269
|
+
problem's own keys.
|
|
1223
1270
|
|
|
1224
1271
|
| Code | Severity | Keys | When |
|
|
1225
1272
|
|---|---|---|---|
|
|
@@ -1227,40 +1274,31 @@ for a failure and `false` for a warning, plus the problem's own keys.
|
|
|
1227
1274
|
| `team-unmapped` | failure if `default`, else warning | `label`, `default`, `at` | a shared team without `team` |
|
|
1228
1275
|
| `team-label-collision` | warning | `label`, `shared`, `local` (each `{team, description, at}`) | a label in both files |
|
|
1229
1276
|
| `default-team-changed` | warning | `recorded`, `current` | `--home` with live teams: the default changed since the spawn |
|
|
1230
|
-
| `E_TEAM_UNKNOWN` | failure | `label`, `at` | a
|
|
1231
|
-
| `
|
|
1232
|
-
| `team-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
`team-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
- `local-soul-teams`: `oats-local.yaml` has `souls.teams` and/or
|
|
1241
|
-
`souls.default` (`keys`: `["souls.teams", "souls.default"]` as found). They
|
|
1242
|
-
move to `souls:` in `oats-workspace.yaml`.
|
|
1243
|
-
- `local-teams-closed`: `oats-local.yaml` declares `teams` and/or
|
|
1244
|
-
`defaultTeam` (`keys`: `["teams", "defaultTeam"]` as found) and the
|
|
1245
|
-
workspace file does not say `localTeams: true`. The `fix` names both
|
|
1246
|
-
remedies: add `localTeams: true` to the workspace file, or commit the teams
|
|
1247
|
-
and `defaultTeam` there and remove them locally. Never raised in the
|
|
1248
|
-
standalone view, which has no workspace rules.
|
|
1277
|
+
| `E_TEAM_UNKNOWN` | failure | `label`, `at` | a local default no file declares |
|
|
1278
|
+
| `E_WORKSPACE_SCHEMA` | failure | `condition: "local-teams-closed"`, `path`, `keys` | `oats-local.yaml` declares `teams` / `defaultTeam` and the workspace does not allow local teams |
|
|
1279
|
+
| `team-soul-unknown` | warning | `key`, `at` | a `souls:` key that is neither `"*"` nor `<name>/*` nor a discovered soul's key (a typo guard) |
|
|
1280
|
+
|
|
1281
|
+
`E_TEAM_UNKNOWN` and local-teams-closed are also spawn, preview and inspect
|
|
1282
|
+
refusals (local-teams-closed as `E_WORKSPACE_SCHEMA` with details `{reason,
|
|
1283
|
+
path, keys}`). While local teams are closed, that one item is the soul's only
|
|
1284
|
+
team item. `team-soul-unknown` is reported where the souls are discovered
|
|
1285
|
+
(`oats teams`, readiness).
|
|
1249
1286
|
|
|
1250
1287
|
```json
|
|
1251
|
-
{"code":"
|
|
1252
|
-
"message":"oats-local.yaml declares teams, defaultTeam, but oats-workspace.yaml does not
|
|
1288
|
+
{"code":"E_WORKSPACE_SCHEMA","severity":"failure","condition":"local-teams-closed","path":"oats-local.yaml","keys":["teams","defaultTeam"],
|
|
1289
|
+
"message":"oats-local.yaml declares teams, defaultTeam, but oats-workspace.yaml does not allow local teams (localTeams: true): either (a) add `localTeams: true` to oats-workspace.yaml, or (b) commit the teams and defaultTeam in oats-workspace.yaml, then remove them from oats-local.yaml",
|
|
1253
1290
|
"fix":"either (a) add `localTeams: true` to oats-workspace.yaml, or (b) commit the teams and defaultTeam in oats-workspace.yaml, then remove them from oats-local.yaml"}
|
|
1254
1291
|
```
|
|
1255
1292
|
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1293
|
+
`oats doctor --json` lists local-teams-closed under `problems[]` (text: `!
|
|
1294
|
+
E_WORKSPACE_SCHEMA (local-teams-closed): …`). Doctor stays offline: it reads
|
|
1295
|
+
only the workspace file this machine's parsed cache holds; when there is
|
|
1296
|
+
none, it adds no problem and says so in `information[]`:
|
|
1297
|
+
`"local-teams-closed: whether oats-workspace.yaml allows oats-local.yaml
|
|
1298
|
+
teams/defaultTeam (localTeams: true) couldn't be checked: this deployment
|
|
1299
|
+
hasn't observed its workspace yet; run oats sync"`. A removed key in
|
|
1300
|
+
`oats-local.yaml` makes doctor answer that refusal, as for any unreadable
|
|
1301
|
+
local file.
|
|
1264
1302
|
|
|
1265
1303
|
<a id="soul-launch-preferences-feature-launch-preference-oats-0300"></a>
|
|
1266
1304
|
## Launch preferences
|
|
@@ -1613,7 +1651,7 @@ Feature `spawn-name`. `--name <slug>` is the exact name, with no prefix.
|
|
|
1613
1651
|
| `E_SOUL_AMBIGUOUS` | `{name, repos, qualified}` | several souls answer the bare name; use one of `qualified` |
|
|
1614
1652
|
| `E_SOUL_DISABLED` | `{name, qualifiedName, entry}` | listed in `souls.disabled` |
|
|
1615
1653
|
| `E_UNKNOWN_AGENT` | | the resolved soul is not under the deployment's agents root |
|
|
1616
|
-
| `E_TEAM_UNKNOWN`, `
|
|
1654
|
+
| `E_TEAM_UNKNOWN`, `E_WORKSPACE_SCHEMA` (local-teams-closed) | `{label, at}`, `{reason, path, keys}` | the soul's teams do not resolve |
|
|
1617
1655
|
| `E_NOT_A_MEMBER`, `E_MEMBERSHIP_UNCONFIRMED` | | the soul's repository is not a confirmed member |
|
|
1618
1656
|
| `E_CAPABILITY_MISSING`, `E_CAPABILITY_PRIVATE`, `E_CAPABILITY_INCOMPATIBLE`, `E_COMPATIBILITY` | | a capability cannot be resolved |
|
|
1619
1657
|
| `E_PACKAGE_MISSING`, `E_PACKAGE_INTEGRITY`, `E_LOCK_SCHEMA` | | the lock does not provide it (standalone: `{…, standalone: true, reason: "no-catalog", catalog}`) |
|