@awebai/oats 0.29.2 → 0.29.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/capabilities/oats-aweb/bin/oats-aweb.mjs +19 -18
- package/capabilities/oats-aweb/injects/aweb.md +4 -4
- package/capabilities/oats-aweb/lib/binding-wire.mjs +1 -3
- package/capabilities/oats-aweb/lib/wake-receive.mjs +1 -1
- package/capabilities/oats-aweb/oats.json +3 -3
- package/capabilities/oats-aweb/skills/VENDORED.md +1 -1
- package/capabilities/oats-aweb/skills/aweb-team-membership/SKILL.md +9 -9
- package/capabilities/oats-aweb/skills/aweb-team-membership/references/team-membership-reference.md +1 -1
- package/capabilities/oats-aweb/skills/oats-aweb/SKILL.md +13 -14
- package/docs/capabilities.md +3 -4
- package/docs/design/2026-09-24-desktop-phase-f-boundary.md +2 -0
- package/docs/design/2026-09-24-phase-d-plan.md +2 -0
- package/docs/design/2026-09-25-teams-contract.md +36 -4
- package/docs/design/2026-09-26-desktop-design-brief-architecture.md +4 -4
- package/docs/official-catalog.md +1 -1
- package/docs/packages.md +4 -4
- package/docs/release-notes/v0.29.3.md +53 -0
- package/docs/workspaces.md +3 -3
- package/lib/core.mjs +3 -3
- package/lib/resolve.mjs +2 -2
- package/lib/workspace.mjs +3 -3
- package/package-catalog.json +2 -2
- package/package.json +1 -1
- package/capabilities/oats-aweb/lib/personal-team.mjs +0 -19
|
@@ -45,7 +45,6 @@ import { assessCapturedSessionReadiness, querySelectedKernel } from "../lib/sess
|
|
|
45
45
|
import { runCapturedNative } from "../lib/captured-native.mjs";
|
|
46
46
|
import { CUSTODY_ATTACH_MIN, grantYamlCustodySocket, parseBindingJson } from "../lib/binding-wire.mjs";
|
|
47
47
|
import { custodyPreflight } from "../lib/grant-custody.mjs";
|
|
48
|
-
import { PERSONAL_ROOT_DEFERRED_WARNING, personalRootDeclared } from "../lib/personal-team.mjs";
|
|
49
48
|
import { runtimeDeliveryFor, wakeRegistration } from "../lib/wake-receive.mjs";
|
|
50
49
|
|
|
51
50
|
/** Run a command as ARGV — never a shell string. Team ids, aliases, instance
|
|
@@ -498,7 +497,7 @@ function globalGrantSpawn() {
|
|
|
498
497
|
const teamWarnings = [];
|
|
499
498
|
const unmappedPrimary = !team ? unmappedPrimaryRow() : undefined;
|
|
500
499
|
if (!team) team = activeTeamAt(custody);
|
|
501
|
-
if (unmappedPrimary && team) teamWarnings.push(`oats-aweb: team-unmapped — workspace label ${unmappedPrimary.label} is not mapped; using
|
|
500
|
+
if (unmappedPrimary && team) teamWarnings.push(`oats-aweb: team-unmapped — workspace label ${unmappedPrimary.label} is not mapped; using the default team ${team}`);
|
|
502
501
|
if (!team) fatal("identity.mode \"global\" requires settings.oats.aweb.team or an active team at the resident custody root before minting a grant");
|
|
503
502
|
const grantHome = join(home, ".aweb-identity");
|
|
504
503
|
if (existsSync(grantHome)) fatal(`${grantHome} already exists; refusing to overwrite an existing aweb session grant home`);
|
|
@@ -758,9 +757,9 @@ function validateJoinLabels(labels, { action = "join" } = {}) {
|
|
|
758
757
|
const eligible = eligibleTeams();
|
|
759
758
|
const byLabel = new Map(eligible.map((t) => [t.label, t]));
|
|
760
759
|
for (const label of labels) {
|
|
761
|
-
if (action === "leave" && label === "
|
|
762
|
-
const error = new Error(`
|
|
763
|
-
error.code = "
|
|
760
|
+
if (action === "leave" && label === "default") {
|
|
761
|
+
const error = new Error(`E_TEAM_DEFAULT: ${label} is the workspace's default team and cannot be left`);
|
|
762
|
+
error.code = "E_TEAM_DEFAULT";
|
|
764
763
|
throw error;
|
|
765
764
|
}
|
|
766
765
|
if (!LABEL_RE.test(label) || !byLabel.has(label)) {
|
|
@@ -801,14 +800,19 @@ function readCapabilityMeta() {
|
|
|
801
800
|
if (process.env.OATS_META) { try { return withProviderTeams(JSON.parse(process.env.OATS_META || "{}")); } catch { return withProviderTeams({}); } }
|
|
802
801
|
try { return withProviderTeams(JSON.parse(readFileSync(join(home, "instance.json"), "utf8")).capabilityMeta?.["oats.aweb"] || {}); } catch { return withProviderTeams({}); }
|
|
803
802
|
}
|
|
803
|
+
function defaultTeamSource(meta = {}) {
|
|
804
|
+
const recorded = meta.defaultTeam?.source;
|
|
805
|
+
if (recorded === "setting" || recorded === "root") return recorded;
|
|
806
|
+
return payloadTeam().team ? "setting" : "root";
|
|
807
|
+
}
|
|
804
808
|
function teamsDocument(meta = readCapabilityMeta()) {
|
|
805
809
|
const teams = parseOatsTeams();
|
|
806
810
|
const joined = joinedTeamsOf(meta);
|
|
807
811
|
const joinedLabels = new Set(joined.map((j) => j.label));
|
|
808
812
|
const primary = primaryTeamLabel();
|
|
809
|
-
const
|
|
813
|
+
const defaultTeam = meta.defaultTeam?.team || meta.team || meta.identity?.team || payloadTeam().team || null;
|
|
810
814
|
return {
|
|
811
|
-
|
|
815
|
+
defaultTeam: { team: defaultTeam, source: defaultTeamSource(meta) },
|
|
812
816
|
primary,
|
|
813
817
|
eligible: teams.filter((t) => t.mapped && t.team).map((t) => ({ label: t.label, team: t.team, joined: joinedLabels.has(t.label) })),
|
|
814
818
|
joined: joined.map((j) => ({ label: j.label, team: j.team, identityHome: j.identityHome, receive: j.receive || "poll", since: j.since })),
|
|
@@ -888,7 +892,7 @@ function parseHomeCommandArgs(argv = process.argv.slice(3)) {
|
|
|
888
892
|
}
|
|
889
893
|
function outputTeamsDocument(doc, json) {
|
|
890
894
|
if (json) { console.log(JSON.stringify(doc)); return; }
|
|
891
|
-
console.log(`
|
|
895
|
+
console.log(`default team: ${doc.defaultTeam.team || "unknown"}`);
|
|
892
896
|
for (const row of doc.eligible) console.log(`${row.joined ? "joined" : "eligible"}: ${row.label} (${row.team})`);
|
|
893
897
|
for (const label of doc.unmapped) console.log(`unmapped: ${label}`);
|
|
894
898
|
}
|
|
@@ -934,9 +938,7 @@ function runTeamsCommand(kind) {
|
|
|
934
938
|
|
|
935
939
|
/** The primary identity's team and the root that mints it, exactly as 1.14.2:
|
|
936
940
|
* the config's `team:` (id, then name) wins, else the root's active team.
|
|
937
|
-
*
|
|
938
|
-
* `aw auth` or `aw team ensure` call and a declared roots.personal is ignored
|
|
939
|
-
* with a warning. Exits through fatal() on refusal. */
|
|
941
|
+
* Exits through fatal() on refusal. */
|
|
940
942
|
function resolvePrimaryTeam() {
|
|
941
943
|
const warnings = [];
|
|
942
944
|
const root = awebRoot();
|
|
@@ -945,7 +947,7 @@ function resolvePrimaryTeam() {
|
|
|
945
947
|
const source = team ? "setting" : "root";
|
|
946
948
|
const unmappedPrimary = !team ? unmappedPrimaryRow() : undefined;
|
|
947
949
|
if (!team) team = JSON.parse(run(["aw", "team", "list", "--json"], root)).active_team;
|
|
948
|
-
if (unmappedPrimary && team) warnings.push(`oats-aweb: team-unmapped — workspace label ${unmappedPrimary.label} is not mapped; using
|
|
950
|
+
if (unmappedPrimary && team) warnings.push(`oats-aweb: team-unmapped — workspace label ${unmappedPrimary.label} is not mapped; using the default team ${team}`);
|
|
949
951
|
if (!team) fatal(`cannot determine target team, so no identity could be minted — ${teamConfigRemedy()}, or activate a team at the aweb root`);
|
|
950
952
|
// A bare team name (no namespace) resolves against the root's memberships.
|
|
951
953
|
if (!team.includes(":")) {
|
|
@@ -955,7 +957,6 @@ function resolvePrimaryTeam() {
|
|
|
955
957
|
else if (match.length > 1) fatal(`team name "${team}" is ambiguous at ${root}: ${match.join(", ")}, so no identity could be minted — ${teamConfigRemedy()}`);
|
|
956
958
|
else fatal(`no membership matching team "${team}" at ${root}, so no identity could be minted — join or create it first (aweb-team-membership skill), or ${teamConfigRemedy()}`);
|
|
957
959
|
}
|
|
958
|
-
if (personalRootDeclared(settings)) warnings.push(`oats-aweb: personal-root-deferred — ${PERSONAL_ROOT_DEFERRED_WARNING}`);
|
|
959
960
|
return { team, root, source, warnings };
|
|
960
961
|
}
|
|
961
962
|
|
|
@@ -1110,19 +1111,19 @@ if (event === "launch") {
|
|
|
1110
1111
|
const deliveryBrief = deliveryMode === "session"
|
|
1111
1112
|
? ` Notification delivery: external (AWEB_DELIVERY=session): the host wake broker (aw wake) is registered for this home and nudges you when mail or chat arrives; the native aweb channel is not running. If you have waited long with nothing arriving, check \`aw mail inbox\` and \`aw chat pending\` yourself at task boundaries.`
|
|
1112
1113
|
: "";
|
|
1113
|
-
let meta = { team: joined.team_id, alias, delivery: deliveryMode,
|
|
1114
|
+
let meta = { team: joined.team_id, alias, delivery: deliveryMode, defaultTeam: { team: joined.team_id, source: primary.source }, ...(process.env.OATS_RUNTIME ? { runtime: process.env.OATS_RUNTIME } : {}), identity: identityMeta({ mode: "local", alias, team: joined.team_id }) };
|
|
1114
1115
|
const joinFloorProblem = joinRows.length ? joinedTeamsAwFloorProblem() : undefined;
|
|
1115
1116
|
if (joinFloorProblem) warnings.push(`oats-aweb: ${joinFloorProblem}`);
|
|
1116
1117
|
else for (const row of joinRows) { const result = mintJoinedTeam(row, meta); meta = result.meta; spawnMeta = meta; writeProviderTeamsState(meta); if (result.warning) warnings.push(`oats-aweb: ${result.warning}`); }
|
|
1117
1118
|
if (joinedTeamsOf(meta).length) { const synced = syncWakeReceive(meta); meta = synced.meta; for (const w of synced.warnings) warnings.push(`oats-aweb: ${w}`); }
|
|
1118
1119
|
writeProviderTeamsState(meta);
|
|
1119
|
-
const
|
|
1120
|
+
const defaultTeamBrief = meta.defaultTeam.source === "setting" ? "the team this deployment configured for you" : "the workspace's default team (the messaging root's active team)";
|
|
1120
1121
|
const joinedNow = joinedTeamsOf(meta);
|
|
1121
1122
|
const joinedBrief = joinedNow.length ? ` Joined teams: ${joinedNow.map((j) => `${j.label} (${j.team}, receive ${j.receive}, send with \`aw --identity-home ${j.identityHome} mail|chat ...\`)`).join("; ")}.` : "";
|
|
1122
1123
|
out({
|
|
1123
1124
|
meta,
|
|
1124
1125
|
env,
|
|
1125
|
-
brief: `Comms: you have an aweb identity — alias "${alias}" on team ${joined.team_id}, ${
|
|
1126
|
+
brief: `Comms: you have an aweb identity — alias "${alias}" on team ${joined.team_id}, ${defaultTeamBrief}.${mismatch}${deliveryBrief}${joinedBrief} Load the oats-aweb skill before messaging: \`oats aweb teams --json\` shows your teams, \`oats aweb roster\` who you can reach. Coordination stays in your deployment's task layer.`,
|
|
1126
1127
|
...(launch ? { launch } : {}),
|
|
1127
1128
|
...(joined.team_id !== team ? { warning: `oats-aweb: team mismatch — joined ${joined.team_id}, expected ${team}` } : warnings.length ? { warning: warnings.join(" | ") } : channelWarning ? { warning: channelWarning } : {}),
|
|
1128
1129
|
});
|
|
@@ -1206,7 +1207,7 @@ if (event === "launch") {
|
|
|
1206
1207
|
// alias = instance name, so the team's member roster lists live instances
|
|
1207
1208
|
// wherever they run (plus human members). Local liveness comes from
|
|
1208
1209
|
// `oats status` in the deployment; this is the network view.
|
|
1209
|
-
// Default: this instance's
|
|
1210
|
+
// Default: this instance's default team, listed from the root that minted
|
|
1210
1211
|
// it. `--label <label>` lists an eligible (joined or not) workspace team from
|
|
1211
1212
|
// the host root that holds it.
|
|
1212
1213
|
const argv = process.argv.slice(3);
|
|
@@ -1220,7 +1221,7 @@ if (event === "launch") {
|
|
|
1220
1221
|
team = row.team; root = awebRootForTeam(team);
|
|
1221
1222
|
if (!root) { console.error(`oats aweb roster: ${awebRootProblem(rootSettingCandidate(team))}, so the roster of ${label} cannot be read from this host`); process.exit(1); }
|
|
1222
1223
|
} else {
|
|
1223
|
-
team = meta.
|
|
1224
|
+
team = meta.defaultTeam?.team || meta.identity?.team || meta.team || process.env.OATS_TEAM_ID;
|
|
1224
1225
|
root = awebRoot();
|
|
1225
1226
|
if (!root) { console.error(`oats aweb roster: ${awebRootProblem(rootSettingCandidate())}`); process.exit(1); }
|
|
1226
1227
|
if (!team) team = JSON.parse(run(["aw", "team", "list", "--json"], root)).active_team;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
## Messaging: aweb
|
|
2
2
|
|
|
3
3
|
Your messaging layer is **aweb**. Your identity's alias is your instance name,
|
|
4
|
-
and it lives in the
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
and it lives in the workspace's default team (the `Comms:` line of your TASK.md
|
|
5
|
+
names it). Wider workspace teams are joined explicitly, each with its own
|
|
6
|
+
identity home.
|
|
7
7
|
|
|
8
8
|
**Load the `oats-aweb` skill before your first `aw mail`/`aw chat` of a session,
|
|
9
9
|
whenever an aweb wake or channel event arrives, and whenever messaging or a
|
|
@@ -14,7 +14,7 @@ memory; if a flag looks wrong run `aw <command> --help`.
|
|
|
14
14
|
Quick crib (run from your instance home, never from `./work`):
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
|
-
oats aweb teams --json #
|
|
17
|
+
oats aweb teams --json # defaultTeam, eligible, joined teams
|
|
18
18
|
oats aweb roster # who you can reach
|
|
19
19
|
aw mail inbox # UNREAD mail only (--show-all: history)
|
|
20
20
|
aw mail send --to <alias> --subject "..." --body-file <f> # recipient needs --to
|
|
@@ -4,7 +4,6 @@ import { isAbsolute, join, resolve } from 'node:path';
|
|
|
4
4
|
import { TextDecoder } from 'node:util';
|
|
5
5
|
import { assessCapturedSessionReadiness } from './session-readiness.mjs';
|
|
6
6
|
import { custodyPreflight } from './grant-custody.mjs';
|
|
7
|
-
import { PERSONAL_ROOT_DEFERRED_WARNING, personalRootDeclared } from './personal-team.mjs';
|
|
8
7
|
import { joinedReceiveModes } from './wake-receive.mjs';
|
|
9
8
|
import {
|
|
10
9
|
MESSAGING_CONTRACT,
|
|
@@ -220,9 +219,8 @@ function readinessDetails(settings,{deployment,env=process.env}={}) {
|
|
|
220
219
|
const initialTeam=typeof settings.team==='string' && settings.team.trim()?settings.team.trim():undefined;
|
|
221
220
|
const candidate=rootCandidate(settings,initialTeam,{deployment,env}),team=teamFromSettings(settings,candidate,{env}),problems=[],warnings=[];
|
|
222
221
|
if(!candidate.root || !isAbsolute(candidate.root) || !existsSync(join(resolve(candidate.root),'.aw'))) problems.push({code:'needs-configuration',message:`no messaging root at ${candidate.root?resolve(candidate.root):process.cwd()}: run oats aweb setup there or set ${candidate.key}`});
|
|
223
|
-
const unmapped=unmappedPrimary(env);if(unmapped&&team)warnings.push({code:'team-unmapped',message:`workspace label ${unmapped.label} is not mapped; using
|
|
222
|
+
const unmapped=unmappedPrimary(env);if(unmapped&&team)warnings.push({code:'team-unmapped',message:`workspace label ${unmapped.label} is not mapped; using the default team ${team}`});
|
|
224
223
|
if(!team) problems.push({code:'needs-configuration',message:'no team: set settings.oats.aweb.team or keep an active team at the aweb root'});
|
|
225
|
-
if(personalRootDeclared(settings)) warnings.push({code:'personal-root-deferred',message:PERSONAL_ROOT_DEFERRED_WARNING});
|
|
226
224
|
return {team,candidate,warnings,result:checkProblems(problems) || {status:'ready',problems:[]}};
|
|
227
225
|
}
|
|
228
226
|
function readinessFromSettings(settings,options) {return readinessDetails(settings,options).result;}
|
|
@@ -30,7 +30,7 @@ export function wakeRegistration({home, primaryIdentityHome, delivery, runtime,
|
|
|
30
30
|
if (!rt || !joined.length) return null;
|
|
31
31
|
const receive = joined.map((j) => ({identity_home: j.identityHome, label: j.label, event_classes: JOINED_EVENT_CLASSES}));
|
|
32
32
|
const doc = rt === 'external-session'
|
|
33
|
-
? {home, delivery: 'session', runtime_delivery: rt, identity_home: primaryIdentityHome, receive_identities: [{identity_home: primaryIdentityHome, label: '
|
|
33
|
+
? {home, delivery: 'session', runtime_delivery: rt, identity_home: primaryIdentityHome, receive_identities: [{identity_home: primaryIdentityHome, label: 'default', controls: true}, ...receive]}
|
|
34
34
|
: {home, delivery: rt, runtime_delivery: rt, primary_identity_home: primaryIdentityHome, receive_identities: receive};
|
|
35
35
|
if (backend) doc.backend = backend;
|
|
36
36
|
return doc;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"capability": "oats.aweb",
|
|
3
3
|
"command": "aweb",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.16.0",
|
|
5
5
|
"compatibility": {
|
|
6
6
|
"oats": ">=0.26.0"
|
|
7
7
|
},
|
|
@@ -142,7 +142,7 @@
|
|
|
142
142
|
"description": "channel: the native aweb channel packages wake the instance (default). session: delivery is external (AWEB_DELIVERY=session), no channel flag; the host wake broker registers the instance once it exists."
|
|
143
143
|
},
|
|
144
144
|
"team": {
|
|
145
|
-
"description": "Target aweb team id for the primary
|
|
145
|
+
"description": "Target aweb team id for the primary identity lifecycle. In workspace v2 spawns this payload value wins over OATS_TEAM_ID; if both are set and differ the hook warns and uses this setting. Unset means the aweb root's active team."
|
|
146
146
|
},
|
|
147
147
|
"root": {
|
|
148
148
|
"hostOnly": true,
|
|
@@ -150,7 +150,7 @@
|
|
|
150
150
|
},
|
|
151
151
|
"roots": {
|
|
152
152
|
"hostOnly": true,
|
|
153
|
-
"description": "Host-owned map of aweb team id to absolute directory whose .aw is that team's minting root, for deployments that mint into several teams. Put this only in oats-local.yaml settings.oats.aweb.roots.
|
|
153
|
+
"description": "Host-owned map of aweb team id to absolute directory whose .aw is that team's minting root, for deployments that mint into several teams. Put this only in oats-local.yaml settings.oats.aweb.roots. Keys are team ids only."
|
|
154
154
|
},
|
|
155
155
|
"identity": {
|
|
156
156
|
"default": {
|
|
@@ -16,7 +16,7 @@ Vendored trees:
|
|
|
16
16
|
- `aweb-identity/`
|
|
17
17
|
|
|
18
18
|
Not vendored: `oats-aweb/` is this package's own OATS playbook (identity,
|
|
19
|
-
|
|
19
|
+
default and joined teams, roster, delivery and wakes, etiquette,
|
|
20
20
|
troubleshooting). Every `aw` invocation it and the vendored skills cite is
|
|
21
21
|
checked against a real published aw by `test/oats-aweb-1-15.test.mjs`.
|
|
22
22
|
|
|
@@ -23,12 +23,12 @@ retire cleanup, readiness, and Desktop operations consistent.
|
|
|
23
23
|
Use the provider commands from the instance home (or with `--home <path>`):
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
oats aweb teams --json #
|
|
26
|
+
oats aweb teams --json # defaultTeam, eligible, joined, unmapped
|
|
27
27
|
oats aweb join --labels <label>[,<label>] # join eligible workspace labels
|
|
28
28
|
oats aweb leave --labels <label>[,<label>] # leave joined wider-team labels
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
- The
|
|
31
|
+
- The workspace's default team cannot be left; attempting it with label `default` is `E_TEAM_DEFAULT`.
|
|
32
32
|
- A label that is not eligible for this soul/workspace is `E_TEAM_NOT_ELIGIBLE`.
|
|
33
33
|
- Joined wider teams use a local identity home such as
|
|
34
34
|
`<home>/.aweb-identity-<label>`. Joined teams require aw >= 1.36.12. The
|
|
@@ -62,15 +62,15 @@ aw id cert show
|
|
|
62
62
|
|
|
63
63
|
Interpret common states:
|
|
64
64
|
|
|
65
|
-
- `teams.
|
|
66
|
-
the aweb root's active team (`
|
|
67
|
-
team (`setting`).
|
|
65
|
+
- `teams.defaultTeam.team` is the primary identity's team, wired to the harness:
|
|
66
|
+
the aweb root's active team (`defaultTeam.source: root`) or a deployment-pinned
|
|
67
|
+
team (`setting`).
|
|
68
68
|
- `eligible[]` are labels this soul/workspace may explicitly join; the primary
|
|
69
69
|
label may appear here and is joinable/leavable like any other wider team.
|
|
70
70
|
- `joined[]` are provider-created wider-team memberships; each has an
|
|
71
71
|
`identityHome`, `since`, and `receive` (`native` or `poll`).
|
|
72
72
|
- `unmapped[]` labels are present on the soul but not mapped by the workspace.
|
|
73
|
-
An unmapped primary falls back to the
|
|
73
|
+
An unmapped primary falls back to the default/root active team with a
|
|
74
74
|
`team-unmapped` warning; it is not a spawn blocker.
|
|
75
75
|
- `teams-unverified` on launch means the kernel supplied recorded/unknown team
|
|
76
76
|
data, so the provider kept memberships instead of leaving anything.
|
|
@@ -81,9 +81,9 @@ Interpret common states:
|
|
|
81
81
|
`default:oats.aweb.ai`).
|
|
82
82
|
- **Team certificate**: a signed membership statement for an identity; stored in
|
|
83
83
|
`.aw/team-certs/` for native identities.
|
|
84
|
-
- **
|
|
85
|
-
aweb root's active team, or `settings.oats.aweb.team` when the deployment
|
|
86
|
-
pins one.
|
|
84
|
+
- **Default team**: the workspace default team for the instance's primary identity:
|
|
85
|
+
the aweb root's active team, or `settings.oats.aweb.team` when the deployment
|
|
86
|
+
pins one.
|
|
87
87
|
- **Joined team**: an explicit wider team joined through `oats aweb join`, with a
|
|
88
88
|
separate local identity home.
|
|
89
89
|
|
package/capabilities/oats-aweb/skills/aweb-team-membership/references/team-membership-reference.md
CHANGED
|
@@ -13,7 +13,7 @@ These layers can combine in multiple ways. Do not assume one from another. The c
|
|
|
13
13
|
|
|
14
14
|
Fully Hosted means aweb operates namespace and team authority for hosted domains such as `*.aweb.ai`. It can mint hosted team certificates and provide simple onboarding. This is the simple default for most users.
|
|
15
15
|
|
|
16
|
-
Hosted OAuth/MCP flows provision custodial addressed/global identities,
|
|
16
|
+
Hosted OAuth/MCP flows provision custodial addressed/global identities, default team membership, and harness credentials before a local CLI workspace exists. Team API-key CLI bootstrap is different: it creates a local self-custodial CLI workspace in a hosted team. In OAuth/MCP flows, use CLI checks for diagnosis only when a local workspace is actually involved; do not force BYOT setup.
|
|
17
17
|
|
|
18
18
|
## BYOT
|
|
19
19
|
|
|
@@ -23,16 +23,16 @@ joined team, put `--identity-home <identityHome>` before the subcommand.
|
|
|
23
23
|
| Fact | Where to read it |
|
|
24
24
|
|---|---|
|
|
25
25
|
| Your alias | your instance name; the `Comms:` line of `TASK.md`; `aw whoami` |
|
|
26
|
-
| Your
|
|
26
|
+
| Your default team | `oats aweb teams --json` → `defaultTeam.team` (`defaultTeam.source`) |
|
|
27
27
|
| Teams you may join | `oats aweb teams --json` → `eligible[]` |
|
|
28
28
|
| Teams you have joined | `oats aweb teams --json` → `joined[]` (each with `identityHome`, `receive`) |
|
|
29
29
|
| How mail reaches you | the `Comms:` line of `TASK.md` (see section 4) |
|
|
30
30
|
|
|
31
|
-
- **
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
- **Default team.** Your primary identity lives in the workspace's default team:
|
|
32
|
+
the aweb root's active team (`defaultTeam.source: root`), or the team the
|
|
33
|
+
deployment pinned (`defaultTeam.source: setting`). `defaultTeam.source` is
|
|
34
|
+
always present and is only `root` or `setting`. Everyone this deployment
|
|
35
|
+
spawns into that team is there with you.
|
|
36
36
|
- **Joined teams.** A wider team the workspace defines, joined explicitly. Each
|
|
37
37
|
gives you a **separate identity** with the same alias in that team, kept
|
|
38
38
|
under `<home>/.aweb-identity-<label>`. You act as that team only with
|
|
@@ -42,7 +42,7 @@ joined team, put `--identity-home <identityHome>` before the subcommand.
|
|
|
42
42
|
## 2. Find who to talk to
|
|
43
43
|
|
|
44
44
|
```bash
|
|
45
|
-
oats aweb roster # your
|
|
45
|
+
oats aweb roster # your default team's members (instances + humans), across machines
|
|
46
46
|
oats aweb roster --label <label> # an eligible workspace team's members
|
|
47
47
|
oats status # live OATS instances on this machine
|
|
48
48
|
```
|
|
@@ -52,7 +52,7 @@ oats status # live OATS instances on this machine
|
|
|
52
52
|
- Outside your team use a full address, `namespace/alias` (`--to-address`), only
|
|
53
53
|
when you were given one.
|
|
54
54
|
- A name that is not on the roster of the team you send from will not resolve:
|
|
55
|
-
pick the identity (
|
|
55
|
+
pick the identity (default-team or joined) whose team holds the recipient.
|
|
56
56
|
|
|
57
57
|
## 3. Send, reply, chat
|
|
58
58
|
|
|
@@ -126,7 +126,7 @@ mail (`--show-all`).
|
|
|
126
126
|
## 5. Teams: join and leave
|
|
127
127
|
|
|
128
128
|
```bash
|
|
129
|
-
oats aweb teams --json # {
|
|
129
|
+
oats aweb teams --json # {defaultTeam, primary, eligible, joined, unmapped}
|
|
130
130
|
oats aweb join --labels <label>[,<label>]
|
|
131
131
|
oats aweb leave --labels <label>[,<label>]
|
|
132
132
|
```
|
|
@@ -134,7 +134,7 @@ oats aweb leave --labels <label>[,<label>]
|
|
|
134
134
|
- Join only when your human, coordinator or task asks you to work with that
|
|
135
135
|
team. Joining mints a new identity for you in that team.
|
|
136
136
|
- You may join only `eligible[]` labels; anything else is `E_TEAM_NOT_ELIGIBLE`.
|
|
137
|
-
-
|
|
137
|
+
- The workspace's default team cannot be left (`E_TEAM_DEFAULT` when the label is `default`).
|
|
138
138
|
- When the workspace stops mapping a team, your next session start leaves it.
|
|
139
139
|
- Do not run native `aw team join|switch|leave|invite` for your identities; the
|
|
140
140
|
provider keeps homes, broker registration and retire cleanup consistent.
|
|
@@ -165,7 +165,7 @@ Check your own state first:
|
|
|
165
165
|
```bash
|
|
166
166
|
aw whoami # identity you act as here
|
|
167
167
|
aw workspace status # connection of the primary identity
|
|
168
|
-
oats aweb teams --json #
|
|
168
|
+
oats aweb teams --json # defaultTeam/joined teams and receive modes
|
|
169
169
|
oats readiness --home "$PWD" --json # the provider's readiness answer for this home
|
|
170
170
|
```
|
|
171
171
|
|
|
@@ -173,8 +173,7 @@ oats readiness --home "$PWD" --json # the provider's readiness answer for this
|
|
|
173
173
|
|
|
174
174
|
| Code | Meaning | Who fixes it |
|
|
175
175
|
|---|---|---|
|
|
176
|
-
| `
|
|
177
|
-
| `team-unmapped` | your soul's primary label is not mapped by the workspace; you are in the personal team | workspace owner, if a shared team was meant |
|
|
176
|
+
| `team-unmapped` | your soul's primary label is not mapped by the workspace; you are in the default team | workspace owner, if a shared team was meant |
|
|
178
177
|
| `joined-team-receive` | a joined team receives live through the broker (informational) | nobody |
|
|
179
178
|
| `joined-team-poll-only` | a joined team does not wake you; the message says why | poll that team at task boundaries; human may start the wake daemon |
|
|
180
179
|
| `wake-daemon-not-running` / `-outdated` / `-version-unknown` | host wake broker is down or older than 1.36.5 | human: upgrade aw, restart the host wake daemon |
|
|
@@ -185,7 +184,7 @@ oats readiness --home "$PWD" --json # the provider's readiness answer for this
|
|
|
185
184
|
|
|
186
185
|
- `E_TEAM_NOT_ELIGIBLE` — the label is not one of your eligible teams; the
|
|
187
186
|
message lists them. Check the spelling against `oats aweb teams --json`.
|
|
188
|
-
- `
|
|
187
|
+
- `E_TEAM_DEFAULT` — the workspace's default team cannot be left.
|
|
189
188
|
- `E_TEAM_GLOBAL_MODE` — this home acts as a resident identity through a
|
|
190
189
|
session grant; joined teams need local identities. Report it.
|
|
191
190
|
- `E_TEAM_AW_FLOOR` — the host `aw` is too old: joined teams need aw >= 1.36.12.
|
package/docs/capabilities.md
CHANGED
|
@@ -216,13 +216,12 @@ team: [engineering, reviewers]
|
|
|
216
216
|
|
|
217
217
|
- `OATS_TEAM_LABEL` is the primary label. The merged messaging payload takes
|
|
218
218
|
**no** label's `byTeam` entry, the primary's included (teams amendment K), so
|
|
219
|
-
`OATS_TEAM_ID` (the payload's `team`) is the
|
|
220
|
-
spawn set; empty means the provider's default.
|
|
219
|
+
`OATS_TEAM_ID` (the payload's `team`) is the default team a host, soul or spawn set; empty means the provider's default.
|
|
221
220
|
- Every label is an **eligible team**: the kernel hands the messaging provider
|
|
222
221
|
`teams`, one `{ label, team, mapped, payload }` per label in order. `payload`
|
|
223
222
|
is `workspace.messaging` ⊕ `byTeam[<label>]` when the workspace maps the
|
|
224
223
|
label (`team` is then its team id), else the base alone with `mapped: false`
|
|
225
|
-
and `team: null`. A soul with no label gets `[]` (
|
|
224
|
+
and `team: null`. A soul with no label gets `[]` (the workspace's default team only).
|
|
226
225
|
- `teams` travels **beside** a provider's settings, never inside them:
|
|
227
226
|
`OATS_TEAMS` (the JSON), `OATS_TEAM_LABELS` (comma-joined) and
|
|
228
227
|
`OATS_TEAMS_SOURCE` in the environment of every hook, home command and
|
|
@@ -518,7 +517,7 @@ passed as arguments; no shell is involved.
|
|
|
518
517
|
- `OATS_CLI_BIN`;
|
|
519
518
|
- `OATS_WORKSPACE` (the deployment);
|
|
520
519
|
- the team variables `OATS_TEAM_ID` (the messaging payload's `team`: the
|
|
521
|
-
|
|
520
|
+
workspace's default team if one is set; empty = the provider's default),
|
|
522
521
|
`OATS_TEAM_SCOPE`, `OATS_TEAM_LABEL`, `OATS_TEAM_NAME`,
|
|
523
522
|
`OATS_TEAM_LABELS`, `OATS_TEAMS`, `OATS_TEAMS_SOURCE`, `OATS_WORKSPACE_NAME` and
|
|
524
523
|
`OATS_WORKSPACE_KEY`;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Desktop Phase F — the Desktop is built FOR workspace model v2
|
|
2
2
|
|
|
3
|
+
> **Vocabulary (2026-09-26):** there is no "personal team". Read it below as **the workspace's default team**. See the AMENDMENT at the top of [the teams contract](2026-09-25-teams-contract.md). This document is a record and keeps its original wording.
|
|
4
|
+
|
|
3
5
|
**Status**: boundary for the Desktop engineer, issued 2026-09-24 by the lead under
|
|
4
6
|
the human's direction: *"the desktop should not just adapt to the new version,
|
|
5
7
|
it should be natively built for it."* Supersedes the Phase 3 parity plan's
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Phase D — the OATS project runs on the architecture it offers (plan)
|
|
2
2
|
|
|
3
|
+
> **Vocabulary (2026-09-26):** there is no "personal team". Read it below as **the workspace's default team**. See the AMENDMENT at the top of [the teams contract](2026-09-25-teams-contract.md). This document is a record and keeps its original wording.
|
|
4
|
+
|
|
3
5
|
**Status**: plan, 2026-09-24, lead. Decisions 18–22 of the workspace model, the
|
|
4
6
|
five-soul roster and its 2026-09-24 amendment, the human's sequencing
|
|
5
7
|
("knowledge centralisation first"; "do not retire live souls until their
|
|
@@ -7,6 +7,31 @@ This document is the kernel half; the provider half (oats.aweb) is the
|
|
|
7
7
|
messaging lane's. Co-lead review (9a18a381): agreed, with three additions,
|
|
8
8
|
folded in below.
|
|
9
9
|
|
|
10
|
+
## AMENDMENT 2026-09-26 (Juan, a total blocker): there is no "personal team"
|
|
11
|
+
|
|
12
|
+
There is **no "personal team" concept**, in aweb or in OATS. **A workspace has its
|
|
13
|
+
DEFAULT TEAM** (the team for the workspace key in its owner's namespace);
|
|
14
|
+
agents can join other teams. Nothing is "personal". Everywhere below, read
|
|
15
|
+
"personal team" as **"the workspace's default team"** (short: "default team").
|
|
16
|
+
The rename is applied everywhere, with no compatibility aliases:
|
|
17
|
+
|
|
18
|
+
- **Prose:** docs, skills, injects, READMEs, release notes (from 0.29.3 on), the
|
|
19
|
+
knowledge base. Past release notes and append-only logs stay as history.
|
|
20
|
+
- **Wire names (the oats.aweb 1.16.0 release; the co-lead's lane):**
|
|
21
|
+
- the teams operation's JSON field `personal` → `defaultTeam` (`{team, source}`);
|
|
22
|
+
- `E_TEAM_PERSONAL` → `E_TEAM_DEFAULT` (leaving the workspace's default team);
|
|
23
|
+
- the broker receive label `personal` → `default`;
|
|
24
|
+
- `settings.oats.aweb.roots.personal` is removed (enrollment is 1.16+ and uses
|
|
25
|
+
the enrolled-root model);
|
|
26
|
+
- readiness codes/messages lose "personal".
|
|
27
|
+
- **aweb** renames its `personal-workspace` endpoints, auth scope, CLI help and
|
|
28
|
+
flags, and binding file likewise (aweb's lane).
|
|
29
|
+
- **The kernel** carries no wire name with "personal" (only prose/comments,
|
|
30
|
+
renamed). The Desktop reads `defaultTeam`.
|
|
31
|
+
|
|
32
|
+
The model below is otherwise unchanged: the default team only, by default;
|
|
33
|
+
joining is explicit; only the soul's labels that the workspace maps.
|
|
34
|
+
|
|
10
35
|
## The model (human, 2026-09-25)
|
|
11
36
|
|
|
12
37
|
- **Default: the personal team only.** Every instance is in its person's
|
|
@@ -143,11 +168,18 @@ folded in below.
|
|
|
143
168
|
7. **Explicit join, spawn choice, Desktop.**
|
|
144
169
|
- The join/leave/list verbs are the provider's (oats.aweb 1.14.0), run
|
|
145
170
|
inside a home or with `--home <abs>`, all idempotent, all with `--json`:
|
|
146
|
-
- `oats aweb teams` answers
|
|
147
|
-
`{
|
|
171
|
+
- `oats aweb teams` answers (oats.aweb ≥1.16.0 names; see the AMENDMENT at the top)
|
|
172
|
+
`{ defaultTeam: {team, source}, primary, eligible: [{label, team, joined}], joined: [{label, team, since, identityHome, receive}], unmapped: [label], at }`, where `receive` is `native` or `poll`, and `source` is always `setting` (the team a setting named) or `root` (the messaging root's active team);
|
|
148
173
|
- `oats aweb join <label>[,<label>]` and
|
|
149
|
-
`oats aweb leave <label>[,<label>]` answer the same document
|
|
150
|
-
|
|
174
|
+
`oats aweb leave <label>[,<label>]` answer the same document **plus**
|
|
175
|
+
`actions: [{action: "join"|"leave", label, released?, receipt?}]`,
|
|
176
|
+
one row per label acted on, in order (since oats.aweb 1.15.0; added
|
|
177
|
+
here 2026-09-26 after the Desktop's real-provider capture found it).
|
|
178
|
+
`released` is the provider's word for what a leave did (e.g.
|
|
179
|
+
`released`); `receipt` is opaque provider evidence (alias release),
|
|
180
|
+
for logs, never shown as UI. A consumer accepts `actions` on
|
|
181
|
+
join/leave answers only, and repaints from the document itself.
|
|
182
|
+
The workspace's default team can't be left (`E_TEAM_DEFAULT`).
|
|
151
183
|
- The same verbs are declared as home-context operations
|
|
152
184
|
`messaging:teams|join|leave`, so the Desktop uses `oats operation run`
|
|
153
185
|
and needs no new kernel surface.
|
|
@@ -90,7 +90,7 @@ An unconfirmed member contributes **nothing**: its souls and capabilities are in
|
|
|
90
90
|
- A soul has one team or several (the first is its **primary**). A repo can set a default team for its souls.
|
|
91
91
|
- A team label can **add default capabilities** for its souls (e.g. every `engineering` soul gets the release tooling).
|
|
92
92
|
- A team label **never** restricts, gates or changes trust. It's organisation, plus optional defaults.
|
|
93
|
-
- For **messaging**, each label a soul carries is a team it's *eligible* to join. By default an instance is only in
|
|
93
|
+
- For **messaging**, each label a soul carries is a team it's *eligible* to join. By default an instance is only in the workspace's **default team**, and joining others is an explicit choice, at spawn or later.
|
|
94
94
|
|
|
95
95
|
---
|
|
96
96
|
|
|
@@ -136,7 +136,7 @@ Plus one **default capability** almost every soul has: **`oats.core`**, which te
|
|
|
136
136
|
### 5.2 Messaging, specifically
|
|
137
137
|
|
|
138
138
|
- Each instance gets a messaging **identity** (its address).
|
|
139
|
-
- By default it's in the
|
|
139
|
+
- By default it's in the workspace's **default team**. It can **join** other eligible teams (from its labels) at spawn or later, and **leave** them. The default team can't be left.
|
|
140
140
|
- Joined teams currently **check mail between tasks**; live delivery for joined teams is **(planned)**.
|
|
141
141
|
- A stopped agent can be **woken** by a message.
|
|
142
142
|
|
|
@@ -196,7 +196,7 @@ When the workspace moves on (a member pushes, a package version is bumped), exis
|
|
|
196
196
|
2. **Who are my agents?** Souls (what roles exist, grouped by team/repo) and instances (what's running, their hierarchy, their state).
|
|
197
197
|
3. **What is this agent made of, and why?** Its composition, with each capability's source and reason (workspace/team/soul), its core capabilities, harness and work mode.
|
|
198
198
|
4. **Where does it work?** Its work mode, branch, and repo; its Git state and pull requests.
|
|
199
|
-
5. **Who can it talk to?** Its messaging identity,
|
|
199
|
+
5. **Who can it talk to?** Its messaging identity, the workspace's default team, eligible teams, joined teams.
|
|
200
200
|
6. **What does it know?** Its knowledge nodes (owned/read). **(planned)** A live browser of them.
|
|
201
201
|
7. **Is anything wrong?** Unconfirmed members, missing clones, team conflicts, drift, readiness problems, each with the plain cause and the fix.
|
|
202
202
|
|
|
@@ -231,7 +231,7 @@ When the workspace moves on (a member pushes, a package version is bumped), exis
|
|
|
231
231
|
- **Official catalog**: the reviewed list of official packages and versions.
|
|
232
232
|
- **Lock**: the exact commit + fingerprint of each package, per deployment.
|
|
233
233
|
- **Team (label)**: an organising label; supplies defaults and eligible messaging teams.
|
|
234
|
-
- **
|
|
234
|
+
- **Default team**: the workspace's messaging team, which every instance is in by default.
|
|
235
235
|
- **Harness**: what runs the agent session (Claude, Codex, Pi).
|
|
236
236
|
- **Work mode**: where an instance works (worktree, checkout, attached, directory, workspace).
|
|
237
237
|
- **Drift**: an instance built from an older state than the workspace's current one.
|
package/docs/official-catalog.md
CHANGED
|
@@ -69,7 +69,7 @@ this policy does not invent new catalog or manifest fields.
|
|
|
69
69
|
`oats.aweb`, `oats.authoring`, `oats.jira`, `oats.linear`, `oats.dev`,
|
|
70
70
|
`oats.knowledge-theory`, `oats.core` and `oats.setup`. `oats.okf-harvest` and
|
|
71
71
|
`oats.okf-maintenance` select the `oats.okf` package (4.0.0).
|
|
72
|
-
- **`oats.framework` 1.3.
|
|
72
|
+
- **`oats.framework` 1.3.1** is listed at tag `oats-framework/v1.3.1` in
|
|
73
73
|
`awebai/oats`, payload root `oats-package`. The `oats.core`, `oats.setup` and
|
|
74
74
|
`oats.knowledge-theory` aliases select that distribution; package identity is
|
|
75
75
|
distinct from capability identity. Core supplies operation/soul guidance;
|
package/docs/packages.md
CHANGED
|
@@ -74,9 +74,9 @@ members:
|
|
|
74
74
|
- git:github.com/acme/agents
|
|
75
75
|
- git:github.com/acme/platform
|
|
76
76
|
packages:
|
|
77
|
-
oats.framework: v1.3.
|
|
77
|
+
oats.framework: v1.3.1
|
|
78
78
|
oats.okf: v4.0.0
|
|
79
|
-
oats.aweb: v1.
|
|
79
|
+
oats.aweb: v1.16.0
|
|
80
80
|
teams:
|
|
81
81
|
global: { description: Org-wide }
|
|
82
82
|
engineering: { description: Platform }
|
|
@@ -344,8 +344,8 @@ A soul that names one of the package's capabilities with
|
|
|
344
344
|
}
|
|
345
345
|
```
|
|
346
346
|
|
|
347
|
-
`ref` carries the tag convention: a workspace's `oats.framework: v1.3.
|
|
348
|
-
resolves to tag `oats-framework/v1.3.
|
|
347
|
+
`ref` carries the tag convention: a workspace's `oats.framework: v1.3.1`
|
|
348
|
+
resolves to tag `oats-framework/v1.3.1`. Resolving through the catalog never
|
|
349
349
|
advances a lock by itself — `oats sync` does, and
|
|
350
350
|
says so.
|
|
351
351
|
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# OATS 0.29.3
|
|
2
|
+
|
|
3
|
+
## Changed
|
|
4
|
+
|
|
5
|
+
- **There is no "personal team"; a workspace has its default team.** The
|
|
6
|
+
vocabulary follows the teams contract's amendment of 2026-09-26: a workspace
|
|
7
|
+
has its **default team** (the team for the workspace key in its owner's
|
|
8
|
+
namespace), and agents may join other teams. The model is unchanged:
|
|
9
|
+
- an instance is in the workspace's default team only, by default;
|
|
10
|
+
- joining an eligible team is an explicit act;
|
|
11
|
+
- `OATS_TEAMS` is `[]` for a soul with no label.
|
|
12
|
+
|
|
13
|
+
The kernel's docs, comments and the `unmapped-team-label` warning use the
|
|
14
|
+
new words. The warning now reads "… fall back to the workspace's default team
|
|
15
|
+
for it". The oats.framework skills (oats.core 2.1.1, oats.setup 2.1.2,
|
|
16
|
+
oats.framework 1.3.1) teach the same model. The kernel carries no wire name
|
|
17
|
+
with "personal", and there are no compatibility aliases.
|
|
18
|
+
- **The messaging provider uses the same words** (oats.aweb 1.16.0, below).
|
|
19
|
+
|
|
20
|
+
## oats.aweb 1.16.0 (catalog pin and bundled mirror)
|
|
21
|
+
|
|
22
|
+
- **The catalog and this repo's workspace pin `oats.aweb` to `v1.16.0`, and
|
|
23
|
+
the bundled `capabilities/oats-aweb` is the tag's tree.** It renames the
|
|
24
|
+
provider's wire names to the default-team vocabulary:
|
|
25
|
+
- the teams operation's `personal` field becomes `defaultTeam`
|
|
26
|
+
(`{ team, source }`, where `source` is `setting` or `root`);
|
|
27
|
+
- `E_TEAM_PERSONAL` becomes `E_TEAM_DEFAULT`;
|
|
28
|
+
- the broker receive label `personal` becomes `default`;
|
|
29
|
+
- `settings.oats.aweb.roots.personal` is removed: `roots` keys are team ids
|
|
30
|
+
only, and the `personal-root-deferred` warning is gone.
|
|
31
|
+
|
|
32
|
+
There are no aliases: a reader of the old names must move to the new ones,
|
|
33
|
+
as the Desktop does in this release. A home spawned under 1.15 still resolves
|
|
34
|
+
its default team from its recorded team. Per-workspace default-team
|
|
35
|
+
enrollment is still deferred.
|
|
36
|
+
|
|
37
|
+
## oats.framework 1.3.1 (catalog pin)
|
|
38
|
+
|
|
39
|
+
- **The catalog and this repo's workspace pin `oats.framework` to
|
|
40
|
+
`oats-framework/v1.3.1`.** Its only change is the default-team vocabulary
|
|
41
|
+
above, in `oats.core` 2.1.1 and `oats.setup` 2.1.2. A deployment on
|
|
42
|
+
`oats.framework: v1.3.0` keeps working, and moving the pin to `v1.3.1` picks
|
|
43
|
+
up the new skill text.
|
|
44
|
+
|
|
45
|
+
## Desktop
|
|
46
|
+
|
|
47
|
+
- **"Default team" everywhere** (#252). The teams panel reads oats.aweb 1.16's
|
|
48
|
+
`defaultTeam` and says where the team comes from: the workspace or host
|
|
49
|
+
setting, or the messaging root's active team. The spawn dialog, the soul
|
|
50
|
+
inspector and the teams panel say "Default team" in place of "Personal".
|
|
51
|
+
A 1.15 `personal` document no longer decodes, so this Desktop needs the
|
|
52
|
+
oats.aweb 1.16.0 pin.
|
|
53
|
+
- The Desktop still accepts OATS CLIs `>=0.25.8 <0.30.0`.
|
package/docs/workspaces.md
CHANGED
|
@@ -59,7 +59,7 @@ members: # repo refs, NO @revision (E_WORKSPAC
|
|
|
59
59
|
- git:github.com/acme/tools # a member that ALSO publishes a package (see below)
|
|
60
60
|
|
|
61
61
|
packages: # the ONLY versioned things
|
|
62
|
-
oats.framework: v1.3.
|
|
62
|
+
oats.framework: v1.3.1 # bare version → resolves through the official catalog
|
|
63
63
|
oats.okf: v4.0.0
|
|
64
64
|
acme.tools: git:github.com/acme/tools@v0.4.0 # outside the catalog → git:<repo>@<tag|OID>; still a package
|
|
65
65
|
|
|
@@ -399,7 +399,7 @@ keys, with `byTeam` stripped) ⊕ soul slot payload ⊕ `local.settings[cap]`
|
|
|
399
399
|
**No `byTeam[<label>]` is merged into it, the primary's included** (teams
|
|
400
400
|
amendment K): each label's `base ⊕ byTeam[label]` reaches the provider only as
|
|
401
401
|
that label's entry in `OATS_TEAMS` (the preview's `teams`). So `settings.team`
|
|
402
|
-
(and `OATS_TEAM_ID`) is the
|
|
402
|
+
(and `OATS_TEAM_ID`) is the workspace's default team if the host, the soul or the spawn
|
|
403
403
|
set one; empty means the provider's own default. The provider's own `binding` contract
|
|
404
404
|
(`normalize → bind → check`) runs over the merged payload exactly as before.
|
|
405
405
|
Two teams, two messaging identities, one workspace:
|
|
@@ -420,7 +420,7 @@ one. A label under `byTeam` that is not declared in `teams:` is
|
|
|
420
420
|
act.** `spawn --preview` shows the merged `settings.<cap>` and the `teams`, so
|
|
421
421
|
the delivery is verifiable, and `instance.json` records both. With oats.aweb
|
|
422
422
|
1.13.1 (which reads `team` from its settings and ignores `OATS_TEAMS`) the
|
|
423
|
-
primary identity therefore mints into the
|
|
423
|
+
primary identity therefore mints into the workspace's default team: the `.aw` root's
|
|
424
424
|
active team, or the one the host set. What the payload does not change is
|
|
425
425
|
**where the `.aw` root is found**: the hook still searches
|
|
426
426
|
bounded candidates, first hit wins — the instance home, the Git repository
|
package/lib/core.mjs
CHANGED
|
@@ -1485,17 +1485,17 @@ export function instanceSoulDir(home, meta = undefined) {
|
|
|
1485
1485
|
/** The team facts a lifecycle hook receives (workspace model only, lead decision
|
|
1486
1486
|
* c3-7): the team SCOPE is the deployment directory, the team ID is the messaging
|
|
1487
1487
|
* slot's merged payload `team` (workspace base ⊕ soul ⊕ host ⊕ spawn; no byTeam entry
|
|
1488
|
-
* is merged since teams amendment K): the
|
|
1488
|
+
* is merged since teams amendment K): the workspace's default team if one is set; empty = the
|
|
1489
1489
|
* provider's default (for oats.aweb, the root's active team). The provider also gets
|
|
1490
1490
|
* the soul's primary team LABEL and the workspace's name and canonical key, so it can
|
|
1491
|
-
* derive
|
|
1491
|
+
* derive the workspace's default team; each label's mapped payload is in
|
|
1492
1492
|
* OATS_TEAMS.
|
|
1493
1493
|
* OATS_TEAM_NAME (the 0.25 `team:` block's name) is always empty, so an ambient
|
|
1494
1494
|
* value never reaches a hook. Human decision 2026-09-24 (messaging default).
|
|
1495
1495
|
*
|
|
1496
1496
|
* Teams contract 2026-09-25 (decision 4): `resolved.teams` is the ELIGIBLE teams,
|
|
1497
1497
|
* `[{ label, team, mapped, payload }]` in soul order. OATS_TEAM_LABELS is their
|
|
1498
|
-
* labels comma-joined and OATS_TEAMS their JSON (`[]` = no label:
|
|
1498
|
+
* labels comma-joined and OATS_TEAMS their JSON (`[]` = no label: the workspace's default team only).
|
|
1499
1499
|
* Both are empty when the teams are not known (a home spawned before 0.26.0 whose
|
|
1500
1500
|
* workspace cannot be read now) — empty means "unknown", never "none".
|
|
1501
1501
|
* OATS_TEAMS_SOURCE says where the list came from: `live` (the workspace read now,
|
package/lib/resolve.mjs
CHANGED
|
@@ -346,7 +346,7 @@ export function teamLabelsOf(soulEntry) {
|
|
|
346
346
|
* `{ label, team, mapped, payload }`. `payload` is workspace.messaging's base ⊕ byTeam[label] when the
|
|
347
347
|
* workspace maps the label, else the base alone with `mapped: false`; `team` is the payload's team id
|
|
348
348
|
* when mapped (null otherwise). Kernel-owned and delivered BESIDE a provider's settings, never inside
|
|
349
|
-
* them; joining any of them is the messaging provider's explicit act. No label → [] (
|
|
349
|
+
* them; joining any of them is the messaging provider's explicit act. No label → [] (the workspace's default team only).
|
|
350
350
|
* Pure: resolveSoul validates every carried label's entry (reserved byTeam, hostOnly keys) first.
|
|
351
351
|
*/
|
|
352
352
|
export function teamsOf(workspace, labels) {
|
|
@@ -731,7 +731,7 @@ export async function resolveSoul(discovery, soulEntry, { local = null, lock = n
|
|
|
731
731
|
// Decision 23 as amended by K (teams contract, co-lead ruling): the provider's settings are
|
|
732
732
|
// base ⊕ soul ⊕ host ⊕ spawn. No byTeam[<label>] is merged, the primary's included: each
|
|
733
733
|
// label's base ⊕ byTeam[label] is delivered only in its `teams` entry (teamsOf → OATS_TEAMS),
|
|
734
|
-
// so settings.team is the
|
|
734
|
+
// so settings.team is the default team a host, soul or spawn set. `byTeam` never reaches the
|
|
735
735
|
// provider, and the primary team's own payload may still not nest one.
|
|
736
736
|
const { byTeam, ...base } = workspace.messaging;
|
|
737
737
|
committed(base, "/messaging", { kind: "workspace", at: "oats-workspace.yaml#/messaging" });
|
package/lib/workspace.mjs
CHANGED
|
@@ -753,8 +753,8 @@ export function workspaceWarnings(workspace, members, externalRows, packageSouls
|
|
|
753
753
|
|
|
754
754
|
/** Teams contract decision 5: a soul label the workspace declares in `teams:` but does not map in
|
|
755
755
|
* `messaging.byTeam` is a WARNING, not a problem — the label stays eligible-but-unmapped and the
|
|
756
|
-
* messaging provider falls back to the
|
|
757
|
-
* ONE warning per unmapped label, naming its souls (a
|
|
756
|
+
* messaging provider falls back to the workspace's default team for it. (An undeclared label is E_TEAM_UNKNOWN.)
|
|
757
|
+
* ONE warning per unmapped label, naming its souls (a workspace on its default team alone would otherwise print
|
|
758
758
|
* a line per soul): { code, label, souls, paths, message }, sorted by label. */
|
|
759
759
|
const byCodepointOrder = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
|
|
760
760
|
function unmappedLabelWarnings(workspace, members, externalRows, teams) {
|
|
@@ -774,7 +774,7 @@ function unmappedLabelWarnings(workspace, members, externalRows, teams) {
|
|
|
774
774
|
const order = names.map((n, i) => i).sort((x, y) => byCodepointOrder(names[x], names[y]) || byCodepointOrder(paths[x], paths[y]));
|
|
775
775
|
const sorted = order.map((i) => names[i]);
|
|
776
776
|
return { code: "unmapped-team-label", label, souls: sorted, paths: order.map((i) => paths[i]),
|
|
777
|
-
message: `team ${show(label)} has no messaging.byTeam entry; its souls (${sorted.join(", ")}) fall back to the
|
|
777
|
+
message: `team ${show(label)} has no messaging.byTeam entry; its souls (${sorted.join(", ")}) fall back to the workspace's default team for it` };
|
|
778
778
|
});
|
|
779
779
|
}
|
|
780
780
|
|
package/package-catalog.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
},
|
|
9
9
|
"oats.aweb": {
|
|
10
10
|
"url": "https://github.com/awebai/oats-aweb.git",
|
|
11
|
-
"ref": "v1.
|
|
11
|
+
"ref": "v1.16.0",
|
|
12
12
|
"path": "oats-package"
|
|
13
13
|
},
|
|
14
14
|
"oats.jira": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"oats.framework": {
|
|
35
35
|
"url": "https://github.com/awebai/oats.git",
|
|
36
|
-
"ref": "oats-framework/v1.3.
|
|
36
|
+
"ref": "oats-framework/v1.3.1",
|
|
37
37
|
"path": "oats-package"
|
|
38
38
|
}
|
|
39
39
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@awebai/oats",
|
|
3
|
-
"version": "0.29.
|
|
3
|
+
"version": "0.29.3",
|
|
4
4
|
"description": "OATS (Open Agent Team Specification) — durable souls, disposable instances, targetable capability packages, and the runtime-neutral oats CLI/kernel.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agents",
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
// Per-workspace personal team: deferred to oats.aweb 1.16.
|
|
2
|
-
//
|
|
3
|
-
// A host's `aw auth` login is one file per OS user, and `aw auth status` does not
|
|
4
|
-
// name the account, so enrolling a workspace's personal team from that login could
|
|
5
|
-
// mint it (and every instance) into whichever account logged in last. 1.16 brings
|
|
6
|
-
// a per-deployment credential location and an expected owner. Until then oats.aweb
|
|
7
|
-
// makes no `aw auth` or `aw team ensure` call on any path, the primary team
|
|
8
|
-
// resolves as in 1.14.2 (settings.team, else the root's active team), and a
|
|
9
|
-
// declared settings.oats.aweb.roots.personal is ignored with a readiness warning.
|
|
10
|
-
|
|
11
|
-
export const PERSONAL_ROOT_KEY = 'settings.oats.aweb.roots.personal';
|
|
12
|
-
export const PERSONAL_ROOT_DEFERRED_WARNING = `${PERSONAL_ROOT_KEY} is ignored: per-workspace personal-team enrollment arrives in oats.aweb 1.16; the primary team is settings.oats.aweb.team, else the aweb root's active team`;
|
|
13
|
-
|
|
14
|
-
const obj = (v) => v !== null && typeof v === 'object' && !Array.isArray(v);
|
|
15
|
-
|
|
16
|
-
/** True when the host declared roots.personal (any value): 1.15 ignores it and says so. */
|
|
17
|
-
export function personalRootDeclared(settings) {
|
|
18
|
-
return obj(settings?.roots) && Object.hasOwn(settings.roots, 'personal');
|
|
19
|
-
}
|