@awebai/oats 0.25.7 → 0.25.8

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 CHANGED
@@ -2938,7 +2938,7 @@ async function paneCmd() {
2938
2938
  * remotes, confirm membership, resolve `packages:`, approve (TTY) or list what
2939
2939
  * needs approval (exit 2), write `oats-lock.json`. Nothing is installed, no soul
2940
2940
  * is created, nothing is spawned, no `oats-config.yaml` is written: the member
2941
- * clones and the setup expert are the operator's next steps, printed here. */
2941
+ * clones and the operator expert are the operator's next steps, printed here. */
2942
2942
  async function onboardCmd() {
2943
2943
  const bail = (code, message, details) => (JSON_MODE ? jsonFail(code, message, details) : die(message));
2944
2944
  const usage = "usage: oats onboard [<dir>] --workspace <repo ref> [--json] (or --dir <dir>)";
@@ -3015,11 +3015,11 @@ async function onboardCmd() {
3015
3015
  // (4) The taught layout as next steps (design doc §4), and the envelope.
3016
3016
  const standalone = synced.discovery.standalone === true;
3017
3017
  const members = synced.report.members;
3018
- // The setup expert is suggested only when THIS workspace lists a soul by that name (a
3018
+ // The operator expert is suggested only when THIS workspace lists a soul by that name (a
3019
3019
  // confirmed member's or, standalone, the repo's own); otherwise any listed soul is spawnable.
3020
3020
  const soulNames = synced.items.souls.map((s) => s.name);
3021
- const setupExpert = soulNames.includes("oats-setup-expert");
3022
- const spawnHint = setupExpert ? `oats spawn oats-setup-expert --dir ${shortPath(dir)}` : null;
3021
+ const setupExpert = soulNames.includes("oats-operator-expert");
3022
+ const spawnHint = setupExpert ? `oats spawn oats-operator-expert --dir ${shortPath(dir)}` : null;
3023
3023
  const anySoulHint = `spawn any listed soul: oats spawn <soul> --dir ${shortPath(dir)}${soulNames.length ? ` (e.g. ${soulNames.slice(0, 3).join(", ")})` : ""}`;
3024
3024
  // A member's clone goes beside oats-local.yaml under its repo name; `agents/` is the instance
3025
3025
  // homes, so a member called "agents" is cloned as `agents-repo/` (design doc §4). The HOST is
@@ -3060,7 +3060,7 @@ Next:
3060
3060
  2. Check who may read the host: ${synced.discovery.key}${hostIsMember ? " is itself a member" : " is a dedicated host"}. The workspace file
3061
3061
  names every member, so if any member is private the host must be a private repo that is not
3062
3062
  a public member; public contributors then get the standalone case (from: here + oats.core).
3063
- 3. ${setupExpert ? "Spawn the setup expert to guide the rest (souls, teams, provider settings, approvals):" : "No soul named oats-setup-expert is listed here —"}
3063
+ 3. ${setupExpert ? "Spawn the operator expert to guide the rest (souls, teams, provider settings, approvals):" : "No soul named oats-operator-expert is listed here —"}
3064
3064
  ${spawnHint ?? anySoulHint}${synced.approvalNeeded.length ? `\n (first: \`oats sync --dir ${shortPath(dir)}\` in a terminal to approve ${synced.approvalNeeded.map((a) => `${a.id} ${a.version}`).join(", ")})` : ""}`);
3065
3065
  process.exitCode = synced.approvalNeeded.length ? 2 : 0;
3066
3066
  }
@@ -3911,7 +3911,7 @@ Usage:
3911
3911
  [--json] and agents/, then runs the oats sync path (lock v3;
3912
3912
  exit 2 while approvals are pending) and prints the
3913
3913
  next steps (clone members you work IN, spawn
3914
- oats-setup-expert); creates no soul, spawns nothing
3914
+ oats-operator-expert); creates no soul, spawns nothing
3915
3915
  oats create <name> [--local] [--no-oats-core] create an agent soul; --local = full
3916
3916
  [--description <d>] [--repo <r>] soul under local-agents/ (uncommitted,
3917
3917
  [--work <mode>] [--runtime pi|claude|codex] gitignored; same memory + lifecycle)
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Purpose:** the one accurate view of every work stream in the redesign, what is on main, what is in flight, who owns it, and what blocks it. Lead: `oats-expert` (redesign lead). Updated whenever anything merges, is returned, or reality changes. Older per-lane boards are superseded by this file.
4
4
 
5
- **Last update:** 2026-09-24 13:30Z · **0.25.0–0.25.6 PUBLISHED** (0.25.6 = decision 27 kernel half + Desktop 10B-0 terminal owner leases, native gate 23/23) (workspace model A–C; team-review fixes; operator-rebuild round; OATS_SOUL_ID; quarantine-retry fix; launch meta + catalog pins) · **OKF v2.1.4 + oats.aweb v1.12.0 TAGGED and pinned** · **decision 27 accepted; K1′/K1″/K2 kernel PR next** · **oats.aweb 1.13.0 (#110) queued** · **Desktop 10B-0 resumed** · Phase D plan next · **Desktop engineer paused by the human** (10B-0 uncommitted foundation preserved; resume is the human's call; 0.24.14 to be cut from a maintenance branch off `e5cdaf95` when its PR lands) · parity pipeline ⏸.
5
+ **Last update:** 2026-09-24 14:10Z · **0.25.0–0.25.7 PUBLISHED** (0.25.7 = v2 deployment root is a configuration boundary) (0.25.6 = decision 27 kernel half + Desktop 10B-0 terminal owner leases, native gate 23/23) (workspace model A–C; team-review fixes; operator-rebuild round; OATS_SOUL_ID; quarantine-retry fix; launch meta + catalog pins) · **OKF v2.1.4 + oats.aweb v1.12.0 TAGGED and pinned** · **decision 27 accepted; K1′/K1″/K2 kernel PR next** · **oats.aweb 1.13.0 (#110) queued** · **Desktop 10B-0 resumed** · Phase D plan next · **Desktop engineer paused by the human** (10B-0 uncommitted foundation preserved; resume is the human's call; 0.24.14 to be cut from a maintenance branch off `e5cdaf95` when its PR lands) · parity pipeline ⏸.
6
6
 
7
7
  Legend: ✅ on main/published · 🔄 in flight (PR/branch) · 🟡 preserved, not adopted · ⬜ not started · ⛔ blocked
8
8
 
@@ -81,6 +81,22 @@ identity.mode=… identity.resident=…` (decision 27 — there is no kernel fla
81
81
  `SPAWN_ARG_RULES` gains one `provider` rule (capability id, dotted key, value
82
82
  grammar); no identity-named rules. Work mode select includes `workspace`.
83
83
 
84
+ **F3 amended by the human (2026-09-24). This supersedes design frame 02 and the
85
+ text above wherever they differ.** The dialog leads with the **instance name**:
86
+ the purpose field becomes a name field that shows `<soul>-<purpose>` live and
87
+ then the kernel's final name from the preview. A no-prefix toggle maps to
88
+ `spawn --name <slug>`, gated on the `spawn-name` feature; `--purpose` stays the
89
+ default. **Runtime and model** are always visible, with their resolved value and
90
+ its source. **Work** comes from the soul's `work:` mode, and a `checkout` soul is
91
+ offered "Use a worktree instead?" (`--work worktree`). There is **no**
92
+ modules/capabilities list and no attach-knowledge / child-spawn / open-PR
93
+ toggles, because those behaviours come from capabilities. There is **no**
94
+ preview button either. The preview runs in the background to fill the real
95
+ defaults, and apply still binds with `--expect-decision` (`E_DECISION_STALE`
96
+ re-previews). A collapsed **Advanced** section holds harness permissions, launch
97
+ config, relation, messaging identity (`--provider <cap> identity.mode=…`,
98
+ decision 27), branch/base overrides and the execution server. Every modal gets a darker backdrop.
99
+
84
100
  **F4 — Instance card and roster on v2 facts.** The served-identity line (`acts
85
101
  as <address> via grant, expires <t>` / `alias <a> on <team>`); module rows with
86
102
  "moved since" markers and a **re-spawn** action (preview → apply, then retire
@@ -22,7 +22,7 @@ pushes. Agreed by both on 2026-09-24:
22
22
  | oats.aweb 1.13.0 re-land end to end | Antares | assigned |
23
23
  | D1 operator node + integrations node | Antares | assigned (draft PR `d1/operator-node` handed over) |
24
24
  | aweb and okf package-expert seams | Antares | assigned |
25
- | D2, D3, D4, desktop + kernel bundle migrations (D1 remainder) | Antares | assigned (both humans agreed, 2026-09-24). D2's machine-bound onboard of the lead's deployment is run by the lead on Antares' word; kernel gaps come to the lead as asks. |
25
+ | D2, D3, D4, desktop + kernel bundle migrations (D1 remainder) | lead, driven by the child instance `oats-expert-phase-d` | assigned (human, 2026-09-24: picked up by the lead's side after all, so as not to wait on the other deployment's human). The lead reviews and merges; Class B items go to Antares for ACK; D3's aweb/okf seams are drafted by the driver and settled with Antares. **Antares is a REQUIRED cross-reviewer** on D4's `oats.setup` rewrite (it must not drift from the operator node) and on D3's `aweb-expert` and `okf-expert` souls (the seams); the rest of the driver's PRs it reads without gating. |
26
26
 
27
27
  **Push protocol.**
28
28
  - **Class A** — notify after, one line: stewardship, docs and knowledge inside
@@ -118,14 +118,44 @@ for, never named by convention — decision 9) is the acceptance: `oats onboard`
118
118
 
119
119
  ### D3 — Souls to `souls/<name>` and the six package-expert souls (decision 20)
120
120
 
121
- Each package repo carries `souls/<pkg>-expert` (okf-expert, aweb-expert,
122
- jira-expert, linear-expert, authoring-expert, dev-expert), the expert in that
123
- package, with a node in the central base from day one. **Seams named in the
124
- charters** (roster amendment): `aweb-expert` READS
121
+ Each package repo carries `souls/oats-<pkg>-expert` (oats-okf-expert,
122
+ oats-aweb-expert, oats-jira-expert, oats-linear-expert, oats-authoring-expert,
123
+ oats-dev-expert), the expert in that package, with a node in the central base
124
+ from day one. **Messaging (human, 2026-09-24; supersedes the lead's per-soul rule):**
125
+ `oats.aweb` is the workspace's messaging **default**
126
+ (`defaults.messaging: { oats.aweb: { from: package } }`, oats#140); a soul
127
+ without messaging says `messaging: none`. The human calls it "the most
128
+ important capability, and most workspaces will use it as default", so the
129
+ provider must work well as a default. Open items (oats.aweb unless noted):
130
+ an unconfigured default must not make every soul unspawnable (onboarding sets
131
+ the messaging root before the first spawn, and/or an unconfigured provider
132
+ reports what is missing instead of refusing); error texts and `setup` must stop
133
+ pointing at `oats-config.yaml`; the deployment names its messaging root
134
+ explicitly rather than by search; `aw mail` usable from `work/`; retired aliases
135
+ reusable. Kernel (lead): in v2 the team scope is the deployment directory and
136
+ the team id comes from the messaging payload, not the classic `team:` block.
137
+ #140 merges together with the first answer to the unspawnable-default item.
138
+ **Teams (human, 2026-09-24): seamless by default.** (R1) Every person gets a
139
+ **personal team per workspace**, created on first use with no invite and no
140
+ manual initialisation — two people, or one person on two workspaces, get
141
+ separate teams; stable across one person's machines. (R2) When a soul whose
142
+ `team:` label the workspace maps to a shared team (`messaging.byTeam.<label>.team`)
143
+ is spawned, the instance **joins that team seamlessly**. Authorization for R2
144
+ (what entitles a person to join without an invite) is oats.aweb's design call
145
+ with the aweb project, fail-closed and visible when the entitlement is missing.
146
+ Kernel (lead): pass the soul's team label and the workspace identity so the
147
+ provider derives the personal team deterministically; an unmapped team means
148
+ "personal". The onboarding skill's manual invite-then-join step is the 1.12.0
149
+ path and is rewritten when the provider ships R1/R2.
150
+ **Naming (lead, 2026-09-24):** the `oats-` prefix on all six —
151
+ it matches the repository names and the roster's `oats-kernel-`/`oats-desktop-`/
152
+ `oats-operator-expert`, and it keeps instance aliases from colliding with the
153
+ messaging project's own `aweb-expert` soul on a shared team. **Seams named in the
154
+ charters** (roster amendment): `oats-aweb-expert` READS
125
155
  `aweb-protocol-expert` in base `aweb-oss-knowledge` (repo
126
156
  `github.com/awebai/aweb`, root `knowledge/`, branch `main`, OKF 2.1.x
127
157
  descriptor at `knowledge/okf-base.json`; owner `1913b77b-…`) through a
128
- read-only store reference; `okf-expert` names its seam to the knowledge-theory
158
+ read-only store reference; `oats-okf-expert` names its seam to the knowledge-theory
129
159
  material in `oats-expert`. Whether the aweb bookshelf decisions the program
130
160
  rests on are published into that node is the aweb side's call (asked).
131
161
 
@@ -140,6 +170,27 @@ rule, the rebuild guide as procedure with the operator node as rationale.
140
170
  Developer souls in `oats.dev` gain `promotesTo: <node>` (roster amendment);
141
171
  the harvester delivers to that node as a PR the owning expert reviews.
142
172
 
173
+ **D4 also removes the legacy the v2 model already declared gone** (human,
174
+ 2026-09-24; boundary §3b's native-rework rule applied to the repository):
175
+ - **Docs, skills, examples** (driver, in D4): delete what v2 removed rather than
176
+ rewriting it (e.g. the OAS migration guide, the legacy Desktop succession
177
+ doc, `oats-config.yaml` examples, the `oats-config` skill); rewrite what
178
+ survives against `oats-local.yaml` and the workspace file; every remaining
179
+ mention of `oats-config.yaml` either describes its removal or is gone.
180
+ - **Kernel** (lead, one Class B PR after D2 lands, because the OATS workspace
181
+ itself stops reading `oats-config.yaml` only once D2 converts it): the
182
+ `oats-config.yaml` scope chain and its readers, the `local-agents/` and
183
+ `tmp-agents/` layouts, the OAS-scope probes, the installed-capability tier
184
+ remnants. Removed, not flagged; the `REMOVED_VERBS` answers stay.
185
+ - **In-repo package copies** (`capabilities/oats-{okf,aweb,jira,linear,authoring}`)
186
+ are NOT removed in D4: `package.json` ships `capabilities/` as the kernel's
187
+ bundled providers, pinned by the mirror-parity, release-packaging and
188
+ clean-room tests. Whether 0.26.0 still bundles them is a release decision
189
+ for D5 (lead); until then they stay unmarked. `private` becomes a schema key
190
+ (the kernel already reads it); `oats-review` is marked private.
191
+ - **Legacy souls** (`agents/*` and their knowledge bundles) are NOT part of D4:
192
+ they go when the live instances linking them retire (human rule).
193
+
143
194
  ### D5 — Catalog update and 0.26.0
144
195
 
145
196
  Catalog pins for the new package versions; **widen Desktop `ACCEPT_RANGE` and
@@ -8,7 +8,7 @@ the OATS Desktop app (`packages/desktop/` in the framework repo):
8
8
  |---|---|
9
9
  | `oats.web` marketplace capability (`oats web start`, browser panel) | OATS Desktop app — the same zero-dependency loopback server is bundled at `packages/desktop/server/` and spawned by the app |
10
10
  | `oats pane` CLI command and the Control Pane TUI | OATS Desktop app (Active overview / instance roster) |
11
- | `@awebai/oats/control-pane` package export (`lib/control-pane/model.mjs`) | The roster model moved into `packages/desktop/server/model.mjs`; it is no longer a public kernel export |
11
+ | `@awebai/oats/control-pane` package export (`lib/control-pane/model.mjs`) | The roster model moved into the Desktop app; under workspace model v2 the app reads the kernel's `oats status --json` instead ([deployment model](../packages/desktop/docs/desktop-deployment-model.md)). It is not a public kernel export |
12
12
 
13
13
  ## Migrating a deployment that used `oats.web`
14
14
 
@@ -45,9 +45,9 @@ solarized) exist in the app's theme system.
45
45
  `import ... from "@awebai/oats/control-pane"` no longer resolves. The
46
46
  model's pure helpers (`readMarkdownSection`, `parseTmuxWindows`,
47
47
  `parseGitStatus`, `parseGitDiffStat`, `buildConstellation`, `relativeAge`)
48
- live in `packages/desktop/server/model.mjs`, which is private to the desktop
49
- app. If you depended on this export, vendor the helpers or open an issue —
50
- no known external consumer existed at removal time.
48
+ moved into the private Desktop app and were retired with its workspace-model v2
49
+ rebuild. If you depended on this export, vendor the helpers from a released tag
50
+ or open an issue — no known external consumer existed at removal time.
51
51
 
52
52
  ## Release gating (maintainers)
53
53
 
@@ -0,0 +1,48 @@
1
+ # OATS 0.25.8
2
+
3
+ ## Fixed
4
+
5
+ - **Desktop: quotes are escaped in attribute contexts** (#139). The views share
6
+ one escaper (`escapeHtml`) for element content and attribute values.
7
+
8
+ - **The roster reports an instance where it actually is.** `oats status`
9
+ reports each instance at the directory the kernel enumerated
10
+ (`<soul dir>/instances/<name>`), under that directory's name. An
11
+ `instance.json` whose `home` or `instance` disagrees no longer relocates or
12
+ renames the instance; the disagreeing values appear only as the diagnostics
13
+ `recordedHome` / `recordedInstance`. Before this, a hostile or corrupted
14
+ `instance.json` could make every consumer that acts on `home` (retire,
15
+ `inspect --home`, the Desktop's file roots) target a path outside the
16
+ deployment. Found by the Desktop engineer in Phase F slice F1.
17
+
18
+ ## Added
19
+
20
+ - **Team facts for workspace-model hooks** (human decisions 2026-09-24:
21
+ `oats.aweb` is the messaging default; teams are seamless). A workspace
22
+ deployment has no classic `team:` block, so lifecycle hooks of a workspace
23
+ spawn now receive: `OATS_TEAM_SCOPE` = the deployment directory;
24
+ `OATS_TEAM_ID` = the messaging slot's merged payload `team` (workspace base ⊕
25
+ `byTeam[<soul team>]` ⊕ soul ⊕ host ⊕ spawn), **empty when no shared team is
26
+ mapped — meaning "personal"**; and new `OATS_TEAM_LABEL` (the soul's team
27
+ label), `OATS_WORKSPACE_NAME` and `OATS_WORKSPACE_KEY` (canonical repository
28
+ key), so a messaging provider can derive a personal team per person per
29
+ workspace deterministically. Classic deployments are unchanged.
30
+ - **Desktop F2: Capabilities, Sources, sync and approval, onboarding** (#143).
31
+ The Workspace view gains a Capabilities table (Capability | Status | Used
32
+ by, from `oats capabilities --json`, filtered by team and source) and a
33
+ Sources tab. It can run `oats sync` and approve pending packages: the Desktop
34
+ admits an approval only when its (id, version, executables digest) exactly
35
+ match the latest sync report it holds, and refuses a mismatch with
36
+ `E_APPROVAL_STALE`. A picked folder that isn't yet a workspace can be
37
+ onboarded through single-use offers held by the main process. The 0.24
38
+ Deployment inventory and Workspace readiness blocks are removed.
39
+ - **Desktop: design parity with Redesign v3 and brand artwork** (#137, #128).
40
+ The Desktop F1 deployment model on kernel JSON (#126) is included too.
41
+ - **`oats.aweb` is the workspace messaging default** (#140, human decision).
42
+ The onboarding skill makes messaging setup its own step before the first
43
+ spawn (#141).
44
+ - **The onboarding next-step hint names `oats-operator-expert`** (#134).
45
+ - **Phase D:**
46
+ - The OATS repository hosts a workspace-model workspace (D2, #127).
47
+ - `oats-operator-expert` and `integrations-expert` souls, with the experts' instructions on the workspace model (D3, #129).
48
+ - `oats.core` and `oats.setup` rewritten for the workspace model (D4, #133).
@@ -6,24 +6,22 @@ hook as `$OATS_INSTANCE_HOME`. It is not your user home (`~`), not the repositor
6
6
  root, and not the work tree. Anything that says "your home" means this directory.
7
7
 
8
8
  - **Your brain and your state live here**: `AGENTS.md` (your composed
9
- instructions), `soul/` (your durable knowledge), `TASK.md` (this task),
10
- `instance.json` (what you were given and from where), and whatever working
11
- state your role keeps — your knowledge layer names those files, if you have
12
- one. They belong here, not in the work tree.
9
+ instructions), `TASK.md` (this task), `instance.json` (what you were given
10
+ and from where), and whatever working state your role keeps — your knowledge
11
+ layer names those files, if you have one. They belong here, not in the work
12
+ tree.
13
13
  - **Run OATS operational/lifecycle commands, and commands from active
14
14
  capabilities, from instance home** — `oats status`, `oats doctor`, `oats spawn`,
15
- `oats retire`, and whatever your own capabilities add; for example, when the
15
+ and whatever your own capabilities add; for example, when the
16
16
  aweb messaging capability is active, run `aw` there too. They resolve their
17
17
  scope from the directory you run them in, so running them from the work tree
18
18
  points them at the wrong deployment. To act on a different package or config
19
19
  scope deliberately, pass an explicit resolved path: `oats <cmd> --dir <path>`.
20
- - **The home's `soul` link is not your edit surface.** It is there so you can
21
- READ your durable knowledge. Writing through it changes durable state outside
22
- your branch, where no review sees it and nothing records what changed or why.
23
- If your TASK is to change soul content that lives in this repository, that is
24
- ordinary code work — do it on tracked paths under `work/`, reviewed like the
25
- rest. How your own learnings reach your soul is your knowledge layer's
26
- business, and its instructions below say so if you have one.
20
+ - **Soul work is repository work.** If your TASK is to change soul content that
21
+ lives in this repository, that is ordinary code work — do it on tracked paths
22
+ under `work/`, reviewed like the rest. How your own learnings reach your soul
23
+ is your knowledge layer's business, and its instructions below say so if you
24
+ have one.
27
25
 
28
26
  **`<instance-home>/work` is your repository or workspace view** — whatever your
29
27
  work mode grants you of the code.
package/injects/oats.md CHANGED
@@ -1,10 +1,10 @@
1
1
  ## You run on OATS
2
2
 
3
3
  You are an agent instance in the OATS (Open Agent Team Specification) framework.
4
- You incarnate a durable soul (`./soul/`), you work in `./work/`, and you can
5
- be retired when your task ends. The **oats** skill teaches the essentials —
6
- your home layout, the agent roster (`oats status`), spawning and
7
- retiring instances (only when instructed), inspecting your configuration
4
+ You incarnate a durable soul and you work in `./work/`.
5
+ The **oats** skill teaches the essentials —
6
+ your home layout, the agent roster (`oats status`), spawning
7
+ instances (only when instructed), inspecting your configuration
8
8
  (`oats doctor`, `./instance.json`), and your lifecycle. **Load the oats skill
9
9
  before your first `oats` command of a session** and any time you reason about
10
10
  agents, spawning, or the framework itself — do not guess `oats` flags or
package/lib/core.mjs CHANGED
@@ -4299,7 +4299,8 @@ export function composeInstanceAgentsMd(soulDir, contextDir, soulName, workMode,
4299
4299
  resolved.capabilities = Array.isArray(prepared.capabilityRows) && prepared.capabilityRows.length
4300
4300
  ? prepared.capabilityRows
4301
4301
  : plannedCapabilityRows(prepared.resolution);
4302
- resolved.workspace = { key: prepared.discovery?.key ?? null, commit: prepared.discovery?.commit ?? null, standalone: prepared.discovery?.standalone === true, revision: prepared.resolution.revision, team: prepared.resolution.soul?.team ?? null, slots: prepared.resolution.slots };
4302
+ resolved.workspace = { key: prepared.discovery?.key ?? null, name: prepared.discovery?.workspace?.name ?? null, deployment: prepared.deployment ?? null, commit: prepared.discovery?.commit ?? null, standalone: prepared.discovery?.standalone === true, revision: prepared.resolution.revision, team: prepared.resolution.soul?.team ?? null, slots: prepared.resolution.slots };
4303
+ resolved.payloads = prepared.resolution.payloads ?? {};
4303
4304
  resolved.layers = Object.fromEntries(Object.entries(prepared.resolution.slots || {}).map(([slot, mod]) => [slot, mod ? { capability: mod } : null]));
4304
4305
  }
4305
4306
  const wanted = [];
@@ -4837,6 +4838,28 @@ export function stableSoulId({ soulId, home, soulDir, agentName } = {}) {
4837
4838
  }
4838
4839
  export const workspaceSoulId = (repoKey, name) => `${repoKey}#${name}`;
4839
4840
 
4841
+ /** The team facts a lifecycle hook receives. Classic deployment: the config
4842
+ * chain's `team:` block (name, id, the declaring scope). Workspace model: there is
4843
+ * no `team:` block — the team SCOPE is the deployment directory, the team ID is the
4844
+ * messaging slot's merged payload `team` (workspace base ⊕ byTeam[<soul team>] ⊕
4845
+ * soul ⊕ host ⊕ spawn), and the provider also gets the soul's team LABEL and the
4846
+ * workspace's name and canonical key, so it can derive a per-person, per-workspace
4847
+ * personal team when no shared team is mapped (empty OATS_TEAM_ID = "personal").
4848
+ * Human decision 2026-09-24 (messaging default; seamless teams). */
4849
+ export function teamEnv(resolved) {
4850
+ const ws = resolved?.workspace;
4851
+ if (!ws || typeof ws !== "object") {
4852
+ return { OATS_TEAM_NAME: resolved?.team?.name || "", OATS_TEAM_ID: resolved?.team?.id || "", OATS_TEAM_SCOPE: resolved?.team?.scope || "" };
4853
+ }
4854
+ const messaging = ws.slots?.messaging;
4855
+ const payload = messaging ? resolved.payloads?.[messaging] : null;
4856
+ const teamId = payload && typeof payload === "object" && typeof payload.team === "string" ? payload.team : "";
4857
+ return {
4858
+ OATS_TEAM_NAME: "", OATS_TEAM_ID: teamId, OATS_TEAM_SCOPE: ws.deployment || "",
4859
+ OATS_TEAM_LABEL: typeof ws.team === "string" ? ws.team : "",
4860
+ OATS_WORKSPACE_NAME: typeof ws.name === "string" ? ws.name : "", OATS_WORKSPACE_KEY: typeof ws.key === "string" ? ws.key : "",
4861
+ };
4862
+ }
4840
4863
  export function runLifecycleHooks(event, { home, instance, agentName, soulDir, soulId, contextDir, workspaceDir, rootDir, resolved, priorMeta = {}, extraEnv = {}, assertRoots }) {
4841
4864
  const results = { meta: {}, briefs: [], warnings: [], order: [], launch: {}, env: {}, failures: [], contributions: [] };
4842
4865
  const envOwners = new Map();
@@ -4866,7 +4889,7 @@ export function runLifecycleHooks(event, { home, instance, agentName, soulDir, s
4866
4889
  OATS_EVENT: event, OATS_INSTANCE: instance, OATS_INSTANCE_HOME: home, OATS_HOME: home, OATS_AGENT: agentName,
4867
4890
  OATS_CAPABILITY: cap.id, OATS_LAYER: cap.layer || "", OATS_ROOT: rootDir || "",
4868
4891
  OATS_SOUL: soulDir || "", OATS_SOUL_ID: stableSoulId({ soulId, home, soulDir, agentName }), OATS_CONTEXT: contextDir, OATS_WORKSPACE: workspaceDir || "", OATS_LEVEL: cap.level || "",
4869
- OATS_TEAM_NAME: resolved.team?.name || "", OATS_TEAM_ID: resolved.team?.id || "", OATS_TEAM_SCOPE: resolved.team?.scope || "",
4892
+ ...teamEnv(resolved),
4870
4893
  ...extraEnv,
4871
4894
  // Hooks also run through direct core callers (not only bin/oats).
4872
4895
  // Author this from the running kernel, never PATH, ambient env or
@@ -7428,7 +7451,16 @@ export function listInstances(root, tmuxSession = DEFAULT_TMUX_SESSION) {
7428
7451
  catch (error) { liveness = { running: null, runtimeState: "unreachable", runtimeError: error.message }; }
7429
7452
  }
7430
7453
  const identity = servedIdentityOf(meta);
7431
- return { ...meta, ...(identity ? { identity } : {}), ...(meta.launch && typeof meta.launch === "object" ? { launch: redactLaunchRecipe(meta.launch) } : {}), ...(typeof meta.command === "string" ? { command: redactLaunchCommand(meta.command) } : {}), ...liveness, ...(rollbackIncomplete ? { rollbackIncomplete } : {}), ...(retirePending ? { retirePending } : {}) };
7454
+ // The home IS the directory enumerated here, and the instance its name:
7455
+ // a file inside it cannot relocate or rename itself in the roster (every
7456
+ // consumer acting on `home` — retire, inspect --home, the Desktop's file
7457
+ // roots — would inherit the claim). A disagreeing claim survives only as
7458
+ // a diagnostic.
7459
+ const claims = {
7460
+ ...(meta.home !== undefined && meta.home !== home ? { recordedHome: meta.home } : {}),
7461
+ ...(meta.instance !== undefined && meta.instance !== e.name ? { recordedInstance: meta.instance } : {}),
7462
+ };
7463
+ return { ...meta, ...claims, home, instance: e.name, ...(identity ? { identity } : {}), ...(meta.launch && typeof meta.launch === "object" ? { launch: redactLaunchRecipe(meta.launch) } : {}), ...(typeof meta.command === "string" ? { command: redactLaunchCommand(meta.command) } : {}), ...liveness, ...(rollbackIncomplete ? { rollbackIncomplete } : {}), ...(retirePending ? { retirePending } : {}) };
7432
7464
 
7433
7465
  });
7434
7466
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@awebai/oats",
3
- "version": "0.25.7",
3
+ "version": "0.25.8",
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",
@@ -36,8 +36,6 @@
36
36
  "docs/",
37
37
  "README.md",
38
38
  "package-catalog.json",
39
- "souls/oats-setup-expert/soul.yaml",
40
- "souls/oats-setup-expert/AGENTS.md",
41
39
  "packages/record/bin/",
42
40
  "packages/record/lib/",
43
41
  "packages/record/docs/",
@@ -1,60 +0,0 @@
1
- # OATS Setup Expert
2
-
3
- Help an operator turn an empty deployment into a deliberately configured OATS
4
- workspace. Explain the next small decision, inspect the existing state, obtain
5
- approval for effects, and verify the result before moving on. Do not replace
6
- working deployments or turn setup into an implicit enrollment operation.
7
-
8
- ## Your supplied procedures
9
-
10
- - Load **oats-workspace-setup** for workspace/source discovery and adoption:
11
- declare, inspect, prepare, approve, scaffold and start are different steps.
12
- - Load **oats-config** for version-scoped classic configuration and targeting;
13
- never use its cascade to fill a missing captured input.
14
- - Load **oats-packages** for official package discovery, acquisition, exact locks,
15
- executable approval and updates.
16
- - Load **oats-operate** for lifecycle, directory boundaries and supported CLI
17
- operations; load **oats-souls** for source editions, roster and relations.
18
-
19
- Use the procedures actually included in your composition. Do not fetch a current
20
- skill or invent a command when an older installed version lacks a feature.
21
-
22
- ## Setup sequence
23
-
24
- 1. Establish the operator's intended deployment, work target and workspace/source
25
- separately. Inspect existing configuration, locks and souls before proposing
26
- changes. A workspace is a shared definition, not a shared live runtime.
27
- 2. Explain `oats-workspace.yaml` and each member's separate `oats.yaml` exports
28
- and backlink. Check reciprocal observations; discovery is neither membership
29
- enrollment nor capability activation. Pin imports only after a source is
30
- published at a real reviewed revision; never invent a future commit or tag.
31
- 3. Select capabilities and their exact sources with the operator. New souls
32
- declare removable `oats.core` explicitly. Do not add knowledge, messaging or
33
- tasks merely because the package was discovered or acquired.
34
- 4. Keep package acquisition, executable approval, provider configuration and
35
- native account/team authorization distinct. Inspect the exact artifact and
36
- its effects before asking for approval. An official catalog entry is not a
37
- blanket grant to execute hooks or change credentials.
38
- 5. Use the supported prepare/approve/scaffold/start path for retained portable
39
- adoption. Verify complete resources and required provider readiness before
40
- native effects. A successful inspection, scaffold or submitted command is
41
- not proof of a working session, message delivery or accepted learning.
42
-
43
- ## Bootstrap and safety boundaries
44
-
45
- This setup role has no hard knowledge or messaging dependency: it must be useful
46
- before OKF or aweb is configured. Its defaults permit none. That does NOT permit
47
- removing another soul's hard requirements to make a failing launch appear ready.
48
-
49
- A classic local bootstrap copy is not a captured preparation or retained source
50
- identity. Say which path created your current soul and do not claim one path's
51
- receipts as evidence for the other. Keep a source edition and an operator-local
52
- configuration distinct; never commit live identities, machine paths, accounts,
53
- private bindings or credentials into exported source definitions.
54
-
55
- Never auto-launch a model session, enable dangerous permissions, enroll an
56
- identity, install a host service, overwrite an existing soul or migrate knowledge
57
- without the operator's explicit instruction. Use ordinary native runtime auth;
58
- missing auth is a human login step, not permission to inspect, copy or wrap
59
- credentials. Preserve existing instances, pending jobs, locks and failed receipts.
60
- Report unsupported operations or infrastructure faults instead of bypassing them.
@@ -1,14 +0,0 @@
1
- schemaVersion: 1
2
- name: oats-setup-expert
3
- description: Guide an operator through OATS workspace adoption and explicit capability setup.
4
- work: directory
5
- requires:
6
- capabilities:
7
- oats.core:
8
- source: repo:oats-package
9
- oats.setup:
10
- source: repo:oats-package
11
- defaults:
12
- knowledge: none
13
- messaging: none
14
- tasks: none