@awebai/oats 0.24.1 → 0.24.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.
@@ -0,0 +1,146 @@
1
+ import { validateInvocationShape, sameInvocationJson } from './invocation-shape.mjs';
2
+ export const MESSAGING_CONTRACT='oats.aweb.messaging';
3
+ export const MESSAGING_CONTRACT_VERSION=1;
4
+ export const RESPONSIBLE_HUMAN_KEY='/bindings/messaging/responsibleHuman';
5
+ export const PRIVATE_TEAM_KEY='/bindings/messaging/privateTeam';
6
+ export const WIDER_KEY='/bindings/messaging/wider';
7
+ const CAPABILITY='oats.aweb';
8
+ const identifierPattern=/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,95}$/;
9
+ const obj=value=>value!==null && typeof value==='object' && !Array.isArray(value);
10
+ const clone=value=>JSON.parse(JSON.stringify(value));
11
+ const canonical=value=>value===null || typeof value!=='object'?JSON.stringify(value):Array.isArray(value)?`[${value.map(canonical).join(',')}]`:`{${Object.keys(value).sort().map(key=>`${JSON.stringify(key)}:${canonical(value[key])}`).join(',')}}`;
12
+ const same=(a,b)=>canonical(a)===canonical(b);
13
+ const fail=(code,message)=>{throw Object.assign(new Error(message),{code});};
14
+ function keys(value,allowed,required,label) {
15
+ if(!obj(value)) fail('invalid-binding',`${label} must be an object`);
16
+ for(const key of Object.keys(value)) if(!allowed.includes(key)) fail('invalid-binding',`unknown ${label} property: ${key}`);
17
+ for(const key of required) if(!Object.hasOwn(value,key)) fail('invalid-binding',`${label} requires ${key}`);
18
+ return value;
19
+ }
20
+ function identifier(value,label='identity') {if(typeof value!=='string' || !identifierPattern.test(value) || ['constructor','__proto__','prototype','toString','valueOf'].includes(value)) fail('invalid-binding',`invalid ${label}`);return value;}
21
+ const pointerKey=value=>String(value).replace(/~/g,'~0').replace(/\//g,'~1');
22
+ export const teamChoiceKey=alias=>`/bindings/messaging/teams/${pointerKey(identifier(alias,'team alias'))}`;
23
+ function originAt(declaration,pointer,kind) {
24
+ const found=declaration.origins[pointer] ?? declaration.origin;
25
+ if(!obj(found)) fail('invalid-binding',`missing origin for ${pointer}`);
26
+ return clone({...found,kind});
27
+ }
28
+ function teamRef(value) {
29
+ keys(value,['provider','id'],['provider','id'],'aweb team reference');
30
+ if(value.provider!==CAPABILITY || typeof value.id!=='string' || !/^[^\s:]+:[^\s:]+$/.test(value.id)) fail('invalid-binding','aweb team reference requires provider oats.aweb and canonical team id');
31
+ return {provider:CAPABILITY,id:value.id};
32
+ }
33
+ function humanRef(value) {
34
+ keys(value,['provider','id'],['provider','id'],'responsible human');
35
+ if(value.provider!==CAPABILITY || typeof value.id!=='string' || !value.id.trim()) fail('invalid-binding','responsible human needs a provider-resolvable oats.aweb id');
36
+ return {provider:CAPABILITY,id:value.id.trim()};
37
+ }
38
+ function exactContext(value) {
39
+ if(value?.kind==='workspace') {keys(value,['kind','identity','observation'],['kind','identity','observation'],'workspace context');if(!obj(value.identity) || !obj(value.observation)) fail('invalid-binding','workspace context needs qualified identity and observation');return {kind:'workspace',identity:clone(value.identity)};}
40
+ if(value?.kind==='standalone') {keys(value,['kind','key'],['kind','key'],'standalone context');if(typeof value.key!=='string' || !value.key.trim()) fail('needs-configuration','messaging-enabled standalone preparation needs an explicit context key');return {kind:'standalone',key:value.key.trim()};}
41
+ fail('invalid-binding','unsupported messaging context');
42
+ }
43
+ function boundContext(value) {
44
+ if(value?.kind==='workspace') {keys(value,['kind','identity'],['kind','identity'],'bound workspace context');if(!obj(value.identity)) fail('invalid-binding','bound workspace context needs qualified identity');return clone(value);}
45
+ if(value?.kind==='standalone') {keys(value,['kind','key'],['kind','key'],'bound standalone context');if(typeof value.key!=='string' || !value.key.trim()) fail('invalid-binding','bound standalone context needs an explicit key');return {kind:'standalone',key:value.key.trim()};}
46
+ fail('invalid-binding','unsupported bound messaging context');
47
+ }
48
+ function declaration(value) {
49
+ keys(value,['kind','value','origin','origins'],['kind','value','origin','origins'],'messaging declaration');
50
+ if(!['soul','workspace','adoption','operator'].includes(value.kind) || !obj(value.value) || !obj(value.origin) || !obj(value.origins)) fail('invalid-binding','invalid messaging declaration');
51
+ return value;
52
+ }
53
+
54
+ /** Emit messaging provider fields for the kernel's single resolver. Team aliases
55
+ * are availability data; only the explicit operator wider list is consent. */
56
+ export function normalizeMessagingDeclarations({declarations,context}={}) {
57
+ if(!Array.isArray(declarations)) fail('invalid-binding','messaging declarations must be an array');
58
+ const exact=exactContext(context),contextOrigin=context?.kind==='workspace'?clone(context.observation):null,requirements=[],candidates=[],teams={},requested=[],requestedOrigins={},aliases={},aliasOrigins={};let soul=null,privatePolicy=false,privatePolicyOrigin=null;
59
+ for(const raw of declarations) {
60
+ const item=declaration(raw);
61
+ // The kernel supplies complete validated source/workspace/operator
62
+ // declarations, including other providers' fields. Consume only messaging
63
+ // fields here; do not impose a second closed schema on the whole document.
64
+ if(item.kind==='soul') {
65
+ if(soul) fail('requirement-conflict','multiple soul messaging declarations');soul=item;
66
+ const list=item.value.teams ?? [];
67
+ if(!Array.isArray(list) || new Set(list).size!==list.length) fail('invalid-binding','soul teams must be a unique array');
68
+ for(let index=0;index<list.length;index++) {const alias=identifier(list[index],'soul team alias');requested.push(alias);requestedOrigins[alias]=originAt(item,`/teams/${index}`,'soul-requirement');}
69
+ } else if(item.kind==='workspace') {
70
+ const value=item.value.teams;if(value===undefined) continue;if(!obj(value)) fail('invalid-binding','workspace teams must be an object');
71
+ for(const [alias,ref] of Object.entries(value)) {
72
+ if(alias==='private') {if(ref!=='per-human') fail('invalid-binding','workspace private team policy must be per-human');privatePolicy=true;privatePolicyOrigin=originAt(item,'/teams/private','workspace-default');continue;}
73
+ const key=teamChoiceKey(alias),origin=originAt(item,`/teams/${pointerKey(alias)}`,'workspace-default');
74
+ teams[alias]=key;candidates.push({key,kind:'workspace-default',value:teamRef(ref),origin});
75
+ }
76
+ } else if(item.kind==='adoption') {
77
+ const value=item.value.teamAliases;if(value===undefined) continue;if(!obj(value)) fail('invalid-binding','adoption teamAliases must be an object');
78
+ for(const [source,target] of Object.entries(value)) {
79
+ identifier(source,'source team alias');identifier(target,'workspace team alias');
80
+ if(Object.hasOwn(aliases,source) && aliases[source]!==target) fail('requirement-conflict','adoption team aliases have conflicting mappings');
81
+ aliases[source]=target;aliasOrigins[source]=originAt(item,`/teamAliases/${pointerKey(source)}`,'import-adoption');
82
+ }
83
+ } else {
84
+ const bindings=item.value.bindings;if(bindings===undefined) continue;
85
+ if(!obj(bindings)) fail('invalid-binding','operator bindings must be an object');
86
+ if(Object.hasOwn(bindings,'responsibleHuman')) candidates.push({key:RESPONSIBLE_HUMAN_KEY,kind:'operator',value:humanRef(bindings.responsibleHuman),origin:originAt(item,'/bindings/responsibleHuman','operator')});
87
+ if(Object.hasOwn(bindings,'privateTeam')) candidates.push({key:PRIVATE_TEAM_KEY,kind:'operator',value:teamRef(bindings.privateTeam),origin:originAt(item,'/bindings/privateTeam','operator')});
88
+ if(Object.hasOwn(bindings,'wider')) {
89
+ if(!Array.isArray(bindings.wider) || new Set(bindings.wider).size!==bindings.wider.length) fail('invalid-binding','operator wider consent must be a unique array');
90
+ candidates.push({key:WIDER_KEY,kind:'operator',value:bindings.wider.map(alias=>identifier(alias,'wider team alias')),origin:originAt(item,'/bindings/wider','operator')});
91
+ }
92
+ }
93
+ }
94
+ if(!soul) fail('needs-configuration','messaging binding needs one soul declaration');
95
+ if(exact.kind==='workspace' && !privatePolicy) fail('needs-configuration','messaging workspace must declare private: per-human');
96
+ const rootOrigin=originAt(soul,'','soul-requirement');
97
+ requirements.push({key:RESPONSIBLE_HUMAN_KEY,kind:'required',origin:rootOrigin},{key:WIDER_KEY,kind:'required',origin:rootOrigin});
98
+ return {requirements,candidates,model:{contract:MESSAGING_CONTRACT,version:MESSAGING_CONTRACT_VERSION,context:exact,contextOrigin,requested,requestedOrigins,aliases,aliasOrigins,teams,privatePolicy,privatePolicyOrigin}};
99
+ }
100
+ function selected(choices,key,{optional=false}={}) {
101
+ const choice=choices?.[key];if(!obj(choice) || !Object.hasOwn(choice,'value') || choice.value===null) {if(optional)return null;fail('needs-configuration',key===RESPONSIBLE_HUMAN_KEY?'an explicit responsible-human binding is required':key===WIDER_KEY?'an explicit wider-membership consent list is required':'a selected wider-team binding is required');}return choice;
102
+ }
103
+
104
+ export function bindMessagingDomain({model,choices}={}) {
105
+ if(!obj(model) || model.contract!==MESSAGING_CONTRACT || model.version!==MESSAGING_CONTRACT_VERSION) fail('invalid-binding','invalid normalized messaging model');
106
+ const humanChoice=selected(choices,RESPONSIBLE_HUMAN_KEY),widerChoice=selected(choices,WIDER_KEY),human=humanRef(humanChoice.value);
107
+ if(!Array.isArray(widerChoice.value) || new Set(widerChoice.value).size!==widerChoice.value.length) fail('invalid-binding','resolved wider consent must be a unique array');
108
+ const wider=[],provenance=[humanChoice.selectedBy,widerChoice.selectedBy,model.contextOrigin,model.privatePolicyOrigin].filter(obj).map(clone);
109
+ for(const sourceAlias of widerChoice.value) {
110
+ identifier(sourceAlias,'wider team alias');if(!model.requested.includes(sourceAlias)) fail('invalid-binding',`wider consent names undeclared soul alias: ${sourceAlias}`);
111
+ const workspaceAlias=model.aliases[sourceAlias] ?? sourceAlias,key=model.teams[workspaceAlias];if(!key) fail('needs-configuration','a selected wider alias needs an explicit workspace team mapping');
112
+ const choice=selected(choices,key),ref=teamRef(choice.value);wider.push(ref);if(obj(choice.selectedBy)) provenance.push(clone(choice.selectedBy));
113
+ if(obj(model.requestedOrigins[sourceAlias])) provenance.push(clone(model.requestedOrigins[sourceAlias]));
114
+ if(obj(model.aliasOrigins[sourceAlias])) provenance.push(clone(model.aliasOrigins[sourceAlias]));
115
+ }
116
+ wider.sort((a,b)=>Buffer.compare(Buffer.from(canonical(a)),Buffer.from(canonical(b))));
117
+ for(let index=1;index<wider.length;index++) if(same(wider[index-1],wider[index])) fail('invalid-binding','duplicate resolved wider team');
118
+ const privateChoice=selected(choices,PRIVATE_TEAM_KEY,{optional:true}),privateTeam=privateChoice?teamRef(privateChoice.value):null;if(privateTeam && wider.some(item=>same(item,privateTeam))) fail('invalid-binding','private team cannot also be a wider team');if(obj(privateChoice?.selectedBy)) provenance.push(clone(privateChoice.selectedBy));
119
+ const unique=[];for(const item of provenance) if(!unique.some(prior=>same(prior,item))) unique.push(item);
120
+ const privateKey={provider:CAPABILITY,human,context:clone(model.context)};
121
+ return {payloadContract:MESSAGING_CONTRACT,payloadVersion:MESSAGING_CONTRACT_VERSION,payload:{responsibleHuman:human,context:clone(model.context),privateTeam,wider},credentialRefs:{},provenance:unique,
122
+ messagingChoice:{schemaVersion:1,enabled:true,privateKey,wider:clone(wider),provenance:clone(unique)}};
123
+ }
124
+
125
+ export function validateAwebBinding(binding) {
126
+ keys(binding,['schemaVersion','capability','payloadContract','payloadVersion','payload','credentialRefs','provenance'],['schemaVersion','capability','payloadContract','payloadVersion','payload','credentialRefs','provenance'],'aweb provider binding');
127
+ if(binding.schemaVersion!==1 || binding.capability!==CAPABILITY || binding.payloadContract!==MESSAGING_CONTRACT || binding.payloadVersion!==MESSAGING_CONTRACT_VERSION || !obj(binding.payload) || !obj(binding.credentialRefs) || !Array.isArray(binding.provenance)) fail('invalid-binding','invalid aweb provider binding');
128
+ keys(binding.payload,['responsibleHuman','context','privateTeam','wider'],['responsibleHuman','context','privateTeam','wider'],'aweb binding payload');
129
+ humanRef(binding.payload.responsibleHuman);boundContext(binding.payload.context);if(!Array.isArray(binding.payload.wider)) fail('invalid-binding','aweb wider teams must be an array');
130
+ const wider=binding.payload.wider.map(teamRef);for(let index=1;index<wider.length;index++) {if(same(wider[index-1],wider[index])) fail('invalid-binding','duplicate aweb wider team');if(Buffer.compare(Buffer.from(canonical(wider[index-1])),Buffer.from(canonical(wider[index])))>0) fail('invalid-binding','aweb wider teams are not canonical');}
131
+ if(binding.payload.privateTeam!==null) {
132
+ const privateTeam=teamRef(binding.payload.privateTeam);
133
+ if(wider.some(team=>same(team,privateTeam))) fail('invalid-binding','private team cannot also be a wider team');
134
+ }
135
+ if(Object.keys(binding.credentialRefs).length) fail('invalid-binding','no credential reference shape is supported by this binding version');
136
+ return binding;
137
+ }
138
+
139
+ export function validateAwebInvocationContext(value,binding,expected={}) {
140
+ validateAwebBinding(binding);
141
+ validateInvocationShape(value,{...expected,capability:CAPABILITY});
142
+ const selected=value.context.kind==='workspace'?{kind:'workspace',identity:value.context.identity}:value.context;
143
+ if(value.messagingChoice.enabled!==true || value.messagingChoice.privateKey.provider!==CAPABILITY || !sameInvocationJson(selected,binding.payload.context)
144
+ || !sameInvocationJson(value.responsibleHuman,binding.payload.responsibleHuman) || !sameInvocationJson(value.messagingChoice.wider,binding.payload.wider)) fail('invalid-binding','invocation contradicts messaging binding');
145
+ return value;
146
+ }
@@ -0,0 +1,56 @@
1
+ // Capability-owned operational readiness for the existing HOME delivery route.
2
+ // This is not human-account delegation, private-grant proof or model completion.
3
+ import {execFileSync} from 'node:child_process';
4
+ import {isAbsolute,resolve} from 'node:path';
5
+ import {BINDING_WIRE_LIMITS,parseBindingJson} from './binding-wire.mjs';
6
+ import {sameInvocationJson as same} from './invocation-shape.mjs';
7
+ import {validateAwebBinding,validateAwebInvocationContext} from './portable-binding.mjs';
8
+ // 0.24.1 supplies HOME custody; 0.24.2 also ships the required public projection
9
+ // and same-kernel codec CLI locator. Source presence is not a released version.
10
+ export const HOME_ROUTE_KERNEL_FLOOR='0.24.2';
11
+ const obj=v=>v!==null&&typeof v==='object'&&!Array.isArray(v);
12
+ const missing=message=>({status:'needs-configuration',problems:[{code:'needs-configuration',message}]});
13
+ const error=()=>{throw Object.assign(new Error('selected kernel observation unavailable'),{code:'provider-unavailable'});};
14
+ /** Preserve native HOME/profile/auth/Git; remove only the invoking instance's
15
+ * OATS selectors so a read-only query cannot accidentally target its parent. */
16
+ export function kernelQueryEnvironment(inherited){
17
+ const env={...inherited};
18
+ for(const key of Object.keys(env))if(/^(OATS_(?!HOME_DIR$)|OAS_|PI_AGENT_)/.test(key)||key==='PI_AGENTS_ROOT')delete env[key];
19
+ return env;
20
+ }
21
+ export function kernelMeetsHomeRouteFloor(version){
22
+ if(typeof version!=='string'||!/^\d+\.\d+\.\d+$/.test(version))return false;
23
+ const parts=version.split('.').map(Number),floor=HOME_ROUTE_KERNEL_FLOOR.split('.').map(Number);if(!parts.every(Number.isSafeInteger))return false;
24
+ for(let i=0;i<3;i++)if(parts[i]!==floor[i])return parts[i]>floor[i];
25
+ return true;
26
+ }
27
+ /** Use the caller-owned CLI location, never search PATH or import private kernel
28
+ * indexes. Binding execution must receive the same OATS_CLI_BIN as hooks. */
29
+ export function querySelectedKernel(args,{env=process.env}={}){
30
+ const cli=env.OATS_CLI_BIN;
31
+ if(typeof cli!=='string'||!isAbsolute(cli)||resolve(cli)!==cli||cli.includes('\0'))error();
32
+ let bytes;
33
+ try{bytes=execFileSync(process.execPath,[cli,...args],{env:kernelQueryEnvironment(env),timeout:10000,maxBuffer:BINDING_WIRE_LIMITS.bytes,stdio:['ignore','pipe','pipe']});}catch{error();}
34
+ try{return parseBindingJson(bytes,BINDING_WIRE_LIMITS);}catch{error();}
35
+ }
36
+ /** Reads only public version/retained selection. A missing profile projection
37
+ * stays explicit; no source default, mutable home label or runtime guess. */
38
+ export function assessCapturedSessionReadiness({binding,invocation,settings},{query=querySelectedKernel,env=process.env}={}){
39
+ if(!binding||!invocation)return missing('selected binding and inline captured invocation are required');
40
+ validateAwebBinding(binding);validateAwebInvocationContext(invocation,binding);
41
+ if(!invocation.instance)return missing('an explicit captured instance home is required');
42
+ if(binding.payload.privateTeam===null)return missing('an explicit private-team binding is required');
43
+ if(settings.delivery!=='session')return missing('captured messaging requires explicit delivery: session');
44
+ if(binding.payload.wider.length)return missing('selected wider memberships need their explicitly qualified native setup; they were not omitted');
45
+ let version,observed;
46
+ try{version=query(['--version','--json'],{env});}catch{return missing('caller-owned OATS_CLI_BIN and readable kernel version are required');}
47
+ if(version?.schemaVersion!==1||version?.name!=='@awebai/oats'||!kernelMeetsHomeRouteFloor(version.version))return missing('oats >=0.24.2 is required for captured HOME custody and retained runtime inspection');
48
+ const b=invocation.executionBinding;
49
+ try{observed=query(['inspect','--deployment',b.deployment,'--resolution',b.resolution.id,'--json'],{env});}catch{return missing('the exact retained runtime profile must be readable');}
50
+ if(observed?.schemaVersion!==1||observed?.ok!==true||!same(observed.result?.resolution,b.resolution))return missing('the kernel must report the exact retained resolution');
51
+ const launch=observed.result.launchSelection;
52
+ if(!obj(launch)||Object.keys(launch).some(k=>!['runtime','model'].includes(k))||!Object.hasOwn(launch,'model')||(launch.model!==null&&(typeof launch.model!=='string'||!launch.model.trim())))return missing('a retained launchSelection runtime/model observation is required');
53
+ if(launch.runtime==='pi')return missing('Pi strict print does not support session input; retain messaging and configure an input-capable profile');
54
+ if(!['claude','codex'].includes(launch.runtime))return missing('a supported input-capable ordinary Claude/Codex profile is required');
55
+ return {status:'ready',problems:[]};
56
+ }
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "capability": "oats.aweb",
3
3
  "command": "aweb",
4
- "version": "1.10.3",
4
+ "version": "1.11.0",
5
5
  "compatibility": {
6
- "oats": ">=0.22.3"
6
+ "oats": ">=0.24.2"
7
7
  },
8
8
  "layer": "messaging",
9
9
  "description": "Messaging layer via aweb: per-instance team identities + native aw mail/chat skills + cross-machine team roster.",
@@ -64,7 +64,16 @@
64
64
  "inject": "injects/aweb.md",
65
65
  "commands": {
66
66
  "roster": "bin/oats-aweb.mjs roster",
67
- "setup": "bin/oats-aweb.mjs setup"
67
+ "setup": "bin/oats-aweb.mjs setup",
68
+ "binding-normalize": "bin/oats-aweb-binding.mjs normalize",
69
+ "binding-bind": "bin/oats-aweb-binding.mjs bind",
70
+ "binding-check": "bin/oats-aweb-binding.mjs check"
71
+ },
72
+ "binding": {
73
+ "version": 1,
74
+ "normalize": "binding-normalize",
75
+ "bind": "binding-bind",
76
+ "check": "binding-check"
68
77
  },
69
78
  "hooks": {
70
79
  "spawn": {
@@ -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-20 17:40Z · main `87292f40` · OKF `v2.1.1`
5
+ **Last update:** 2026-09-21 05:00Z · main `04e930e7` · **OATS v0.24.2 published** · OKF v2.1.1 · oats-framework/v1.1.1 · aweb v1.11.0 · oats-knowledge 8d67eab4
6
6
 
7
7
  Legend: ✅ on main/published · 🔄 in flight (PR/branch) · 🟡 preserved, not adopted · ⬜ not started · ⛔ blocked
8
8
 
@@ -10,14 +10,14 @@ Legend: ✅ on main/published · 🔄 in flight (PR/branch) · 🟡 preserved, n
10
10
 
11
11
  | # | Stream | State | Owner | Next action |
12
12
  |---|---|---|---|---|
13
- | S1 | Knowledge capability contract rework (kernel↔provider boundary, OKF 2.x) | ✅ shipped 0.24 / **OKF 2.1.1 released** (PR4 merged; mirror, catalog ref, soul source bumped) | P | done for this phase; OATS 0.24.1 cut after L's custody fix |
14
- | S2 | Workspace/Portable Souls adoption of the OATS repos | ✅ PR23 + PR24 merged · ✅ member `oats.yaml` on main in oats-okf/aweb/authoring/jira · ⛔ oats-dev, oats-linear (no push access, human) | M, L, lead | human grants access → push 0434f4ef/8c183c37; then pin imports; then fresh deployment gate |
15
- | S3 | Messaging capability readiness on the new infrastructure (aweb) | 🔄 codec PR2 + custody WIP · needs profile pin | P | lead pins pilot profile + answers authority question |
16
- | S4 | Official capabilities `oats.core` / `oats.setup` + explicit default + onboarding `oats-setup-expert` | 🔄 D1 in progress (P, `feat/d1-oats-core-setup`, package → `oats.framework` 1.1.0) · 🔄 D2 in progress (L) · ⬜ D3 | P (D1), L (D2, D3) | review D1/D2 PRs; assign D3 after D2 |
17
- | S5 | Official marketplace = reviewed list in oats repo | ✅ D4 merged PR26 (`docs/official-marketplace.md`, policy pointer) · ⬜ `oats.core`/`oats.setup` entries after D1 release | M | add entries at D1 release |
18
- | S6 | Five expert souls created in the oats repo (`souls/<name>/`) | 🔄 assigned to M (`feat/s6-expert-soul-editions`) from the reviewed candidate; `souls/oats-expert` on main | M | review PR; `oats.core` follow-up after D1 |
19
- | S7 | Centralised per-soul knowledge in `oats-knowledge` (migration + PR-only learning) | 🟡 35 curated concepts uncommitted on local `curation/expert-knowledge`; bootstrap proven on personal repo; `awebai/oats-knowledge` EMPTY, private | lead + human (visibility) | decide visibility; publish curation as PR; point souls' `stores.oats` at it |
20
- | S8 | Desktop parity (marketplace view, soul creation with `oats.core`, onboarding flow) | ⬜ after S4/S5 | fresh Desktop engineer (blocked: `claude` absent) | pick runtime; spawn |
13
+ | S1 | Knowledge capability contract rework (kernel↔provider boundary, OKF 2.x) | ✅ OATS 0.24.1 / OKF 2.1.1 published | P | done for this phase |
14
+ | S2 | Workspace/Portable Souls adoption of the OATS repos | ✅ workspace + seven indexes + six imports · ✅ **0.24.2 published** (onboard verified from the npm tarball) · 🔄 Antares re-run requested · 🔄 five seams → L, 0.24.3 | lead, L, Antares | re-run report; seams PR |
15
+ | S3 | Messaging capability readiness on the new infrastructure (aweb) | ✅ aweb 1.11.0 released · ✅ **catalog + six editions pin v1.11.0 (0.24.2)** · ⬜ second-operator re-run | P, lead | Antares re-run |
16
+ | S4 | Official capabilities `oats.core` / `oats.setup` + explicit default + onboarding `oats-setup-expert` | ✅ D1, D2, **D3 merged (PR35)**: `oats onboard` verified live (acquire 1.1.1 → setup expert with both caps → scaffold composes the five capability skills, no legacy) · `oats.framework` 1.1.1 tagged | P, L | done; Desktop surfaces → S8 |
17
+ | S5 | Official marketplace = reviewed list in oats repo | ✅ D4 merged · ✅ `oats.framework` 1.1.1 listed (`oats.core`, `oats.setup`, `oats.knowledge-theory` aliases) | M | Desktop view → S8 |
18
+ | S6 | Five expert souls created in the oats repo (`souls/<name>/`) | ✅ five + `oats-setup-expert` on main, all declaring `oats.core`, exported + imported | M, L, lead | legacy `agents/` cutover after S7 proof |
19
+ | S7 | Centralised per-soul knowledge in `oats-knowledge` (migration + PR-only learning) | ✅ **repo PUBLIC; PR #1 merged → main 8d67eab4, 25 accepted concepts**, owners = published souls, validator pinned OKF 2.1.1 · 🔄 fresh-reader proof assigned to Juan's side · ⬜ legacy in-soul knowledge decommission | lead, Antares/Juan | fresh-reader + PR-learning proof; then retire `agents/*/soul/knowledge` |
20
+ | S8 | Desktop parity (marketplace view, soul creation with `oats.core`, onboarding flow) | ⬜ after D3 · **host offered: Juan's machine (has `claude`)** — accepted | fresh Desktop engineer on Juan's host | brief + spawn params after D3 |
21
21
 
22
22
  ## S1 — Knowledge capability contract rework
23
23
  - ✅ Provider-neutral contract, binding wire v1, helper/input contract, retained execution: OATS 0.24.0 + OKF 2.1.0 (f20f8e57) published.
@@ -28,21 +28,32 @@ Legend: ✅ on main/published · 🔄 in flight (PR/branch) · 🟡 preserved, n
28
28
  - ✅ **PR23 merged f6d5a89b**: `oats-workspace.yaml` (7 members, `imports: []`), `oats.yaml` (exports souls/oats-expert, oats-package, capabilities/oats-authoring), transitional `souls/oats-expert/` edition, `docs/workspace-adoption.md`, layout tests.
29
29
  - ✅ **PR24 merged da38e5a9**: deletion of `skills/oats-portable-setup` + `oats inspect --request` read-only seam (ACCEPTED as the public inspection route); full gate 1621/0.
30
30
  - ✅ Member `oats.yaml` merged to main: oats-okf #3 (fec78a20), oats-aweb #1 (069ea2f6), oats-authoring #1 (54183a6a), oats-jira #1 (2f855daf).
31
- - ⛔ oats-dev (0434f4ef) and oats-linear (8c183c37): neither M nor the lead's GitHub account has push — **human must grant access or push**.
31
+ - ✅ oats-dev#1 (main 6e164ee3) and oats-linear#1 (main a2121e48) merged after Juan granted write access — M's exact commits 0434f4ef / 8c183c37.
32
32
  - ⬜ `imports:` pin of `souls/oats-expert` at its published revision (after member indexes).
33
33
  - ⬜ Fresh local deployment from the shared definition (P1.5) — the real acceptance gate.
34
34
 
35
+ ## S2 — second-operator gate report (Antares, Juan's machine, 2026-09-20)
36
+ Fresh dir, local `@awebai/oats@0.24.1`, no prior state. `inspect --request` → ready-for-preparation, membership eligible, source `souls/oats-kernel-expert@caa341f3`. `prepare` resolved and materialized `oats-package@caa341f3`, `oats.okf@v2.1.1`, `oats.aweb@v1.10.3`, `oats.core`, `oats.setup`, `oats.knowledge-theory` + soul; artifact-set approvals worked. Terminal: `needs-configuration` + `provider-not-qualified` (aweb 1.10.3 has no binding interface) — expected. Seams (assigned to L, one PR, priority):
37
+ 1. `inspect --request` requires `workTarget`; `prepare --request` refuses it (`buildFreshPreparationRequest` exists but the CLI never uses it).
38
+ 2. `prepare` on the absent deployment inspect blessed → raw `ENOENT` + host path through the JSON envelope.
39
+ 3. `prepare` writes lock v3; `oats trust <cap> --dir` rejects it (`unsupported lockfileVersion 3`) → dead end from `--help`.
40
+ 4. The working `trust --deployment --artifact-set <sha256>` route is absent from `--help`.
41
+ 5. Problems carry `origins: []` and no slot/capability, so a valid and a bogus `stores.oats` binding produce byte-identical output. **Root cause (L's trace):** both OKF `normalize` calls refused because the operator request had no OKF runtime settings (`bindings-file`, `state-dir` — absolute host paths, no defaults); the message never said so. Fix = attribute problems by slot/capability and name the missing item; the identical pair is correct output for that input and stays identical. Guidance for the required settings → P (oats-workspace-setup).
42
+
35
43
  ## S3 — Messaging (aweb) on the new infrastructure
44
+ - ✅ **aweb PR3 merged → v1.11.0 (93f8ab96)**: `binding {normalize,bind,check}` on the existing wire; `check` = HOME-route operational custody only (explicit private team, `delivery: session`, kernel ≥0.24.2 via caller-owned `OATS_CLI_BIN`, retained `launchSelection` must be input-capable Claude/Codex; strict-Pi print → `needs-configuration`, never downgraded). Native adapter over existing `aw` commands with physical identity-dir custody and redacted tokens. Standalone 30/0; coupling 14/0 vs kernel b92f0d07. PR33 (launchSelection projection, OATS_CLI_BIN in codec env) merged b92f0d07.
36
45
  - Facts: released aweb 1.10.3 has no binding interface; broker refuses. aw 1.36.1 broker calls `oats session inspect/input --home H`; never restarts stopped runtime; strict-Pi print mode can't take session input.
37
46
  - 🔄 oats-aweb **PR2** codec (165b20e) + uncommitted `lib/captured-execution.mjs` (6/6).
38
47
  - ✅ Lead answered (d9d912a4): pilot primary = Pi strict print host explicit model; helper = Pi sole-OKF (Claude/Codex allowed by 2.1.1); authority = existing HOME route + L's custody fix, gated on `oats >=0.24.1`; no new grant mechanism. P delivers aweb 1.11.0 PR.
39
- - 🔄 L finding c21e36ff accepted; fix assigned (L, `fix/home-route-captured-custody`): reuse `readCapturedInstanceAuthority` on the HOME-only route, refuse before transport.
48
+ - ✅ **PR27 merged (5af848fc)**: HOME-only session route applies existing captured custody; refuses before transport on drift. Full gate 1626/1632 (2 pre-existing env failures reproduced on main). Ships in **v0.24.1** — the kernel floor the aweb adapter gates on.
40
49
 
41
50
  ## S4 — `oats.core` / `oats.setup` / onboarding
51
+ - ✅ **D3 merged PR35 (37c5c012)**: `oats onboard` classic local bootstrap; edition `souls/oats-setup-expert` (core+setup, provider defaults `none`, no knowledge owner). Full gate 1639/0. Live: onboard → acquire `oats.framework` 1.1.1 @0aad753c → soul declares both caps at that commit → scaffold-only spawn composes exactly `oats-operate, oats-souls, oats-config, oats-packages, oats-workspace-setup` + the `oats.core` injection, no legacy kernel skills. Baseline hygiene fixed on main (a96f24df).
52
+ - ✅ **D1 merged PR28 (70b10822)**, distribution tag `oats-framework/v1.1.0` on 9930dcfb; **D2 merged PR29 (9930dcfb)** full gate 1634/0. Verified live: `oats create` writes `requires.capabilities.oats.core` with the catalog source; `oats install oats.framework` acquires all three capabilities from the tag.
42
53
  - ✅ Decision + plan D1–D4 on main 18af53be; docs reference as accepted-not-shipped.
43
54
  - 🔄 **D1** (P, started 16:29Z; package identity confirmed: rename distribution package to `oats.framework` 1.1.0, capabilities 1.0.0, `oats.knowledge-theory` unchanged) package `oats.core` (`oats-operate`, `oats-souls`, oats.md injection) and `oats.setup` (oats-config, oats-packages, adoption guidance) under `oats-package/capabilities/`. Owner P.
44
55
  - 🔄 **D2** (L, after custody fix) soul creation writes explicit `requires.capabilities.oats.core`; kernel skill list de-ambiented (one-release coexistence); checked-in souls updated. Owner L.
45
- - ⬜ **D3** onboarding creates + instantiates `oats-setup-expert` (edition in `souls/`). Owner L (+M edition).
56
+ - 🔄 **D3** (L, in progress) onboarding creates `oats-setup-expert` (edition in `souls/`); CLI verb **`oats onboard`** — `oats setup` is already the record capture-setup command and stays untouched.
46
57
  - Exit: fresh onboarding → running setup expert; created soul shows `oats.core`; kernel ships no ambient operational skill.
47
58
 
48
59
  ## S5 — Official marketplace
@@ -50,21 +61,23 @@ Legend: ✅ on main/published · 🔄 in flight (PR/branch) · 🟡 preserved, n
50
61
  - ✅ **D4 merged PR26 (786490ae)**: `docs/official-marketplace.md`, `package-catalog.json` policy pointer (inert to the reader), README/packages/capabilities links, D3 sketch in adoption guide. ⬜ entries for `oats.core`/`oats.setup` at D1 release. Desktop view → S8.
51
62
 
52
63
  ## S6 — Five expert souls in the oats repo
64
+ - ✅ **PR30 merged (40a579dc)** + maintainer follow-up **caa341f3**: all five declare `oats.core: {source: repo:oats-package}`, oats.okf@v2.1.1; `oats.yaml` exports all five; `oats-workspace.yaml` imports all five at caa341f3 (375b9f42). Live inspection against published main resolves them.
53
65
  - Roster (decided): `oats-expert`, `oats-kernel-expert`, `oats-desktop-expert`, `market-research-expert`, `oats-assistant`.
54
66
  - 🟡 Candidate: `expert-roster` worktree (b5e233b9 + 519 uncommitted changes: five `agents/<name>/soul/` + legacy roster deletions). Reviewed earlier; NOT committed.
55
67
  - ✅ `souls/oats-expert` transitional edition on main already declares owns/reads for the five nodes.
56
68
  - 🔄 Assigned to M (17:05Z): create `souls/<name>/` editions for the other four from the candidate; each declares `oats.core` explicitly (S4 rule) + `oats.okf`/`oats.aweb` sources; export in `oats.yaml`. Legacy `agents/` roster retirement is a separate, later cutover.
57
69
 
58
70
  ## S7 — Centralised knowledge in `oats-knowledge`
71
+ - ✅ Juan made the repo PUBLIC (2026-09-20). Bootstrap history pushed to main; **PR #1 merged (8d67eab4)**: 25 curated concepts, roadmap re-verified to the 0.24.1 baseline and 2026-09-20 decisions, validator pinned to OKF v2.1.1, strict OKF 25/0/0, ownership tests 24/24.
59
72
  - 🟡 Curated corpus: 35 concepts (five nodes) on local `curation/expert-knowledge` in `/Users/pepe-reyero/OATS-workspace/oats-knowledge`, **uncommitted**. Bootstrap + one PR-only harvest already proven on `josep-reyero/oats-knowledge` (3 commits).
60
73
  - ⛔ Target `awebai/oats-knowledge` is EMPTY and PRIVATE; **visibility undecided** (stated requirement: public). Human decision needed before publishing.
61
74
  - ⬜ Then: push bootstrap + curation as PR to awebai; bind `stores.oats` in the pilot deployment; prove fresh-reader + Git-PR learning with the new souls; retire old in-soul knowledge (`agents/*/soul/knowledge`) as a final cutover.
62
75
 
63
76
  ## S8 — Desktop parity
77
+ - Finding (L, D2 audit): the Desktop server has **no soul-creation endpoint** today (roster reads, existing-soul edits/capability operations, instance spawn only). Soul creation with explicit `oats.core`, the marketplace view and the onboarding flow are new Desktop features, not wiring.
64
78
  - ⬜ After S4/S5: official marketplace view/search; soul creation showing `oats.core`; onboarding flow; redesign parity vs `Oats UX Redesign and Desktop Discovery (1)`.
65
79
  - ⛔ Fresh `oats-desktop-engineer` not spawned: `claude` not on PATH → choose Pi/Codex or install (human).
66
80
 
67
81
  ## Blockers needing the human
68
- 1. `awebai/oats-knowledge` visibility (public vs private) — gates S7 publication.
69
- 2. Push access to `awebai/oats-dev` and `awebai/oats-linear` for `josep-reyero` (or human pushes M's exact commits 0434f4ef / 8c183c37 as `oats.yaml`) — gates S2 completion.
70
- 3. Desktop engineer runtime (Claude absent) — gates S8.
82
+ - ~~oats-knowledge visibility~~ → PUBLIC (Juan). ~~oats-dev/oats-linear access~~ → granted, indexes merged. ~~Desktop runtime~~ → Juan's machine hosts the Desktop lane (has `claude`).
83
+ - None open at 23:10Z. Juan's side (Antares) takes: (a) fresh-deployment gate P1.5, (c) fresh-reader proof, (b) Desktop host after D3.
@@ -9,9 +9,11 @@ owned; production capability/profile readiness is not established by the fixture
9
9
 
10
10
  ```sh
11
11
  oats inspect --request /absolute/inspection.json --json
12
+ # Optional explicit request export (new private file; never overwrite):
13
+ oats inspect --request /absolute/inspection.json --emit-prepare-request /absolute/preparation.json --json
12
14
  ```
13
15
 
14
- This mode accepts only one request file and `--json`. Explicit captured selectors
16
+ This mode accepts one request file, optional `--emit-prepare-request`, and `--json`. Explicit captured selectors
15
17
  or current-context flags conflict before file reads; inherited captured environment
16
18
  is not new-work input. Other existing inspect modes are unchanged. The shared
17
19
  bounded strict JSON request reader feeds the existing inspection validator intact:
@@ -66,21 +68,47 @@ have not been classified by their owner and are omitted. Import summaries expose
66
68
  `payloadOmitted`. Top-level `omitted:{providerPayloads:true,adoptionValues:true}`
67
69
  states that this is a metadata view, not a lossless request or a safe-payload claim.
68
70
  It is not an issued `buildFreshPreparationRequest` witness, even in the same
69
- process. Keep the original authored input for an explicit preparation request.
71
+ process. The opt-in `--emit-prepare-request` route calls that existing builder
72
+ on the real in-process inspection before dropping the private witness. It writes
73
+ only `.preparation` to a new mode-0600 file at an explicit normalized absolute
74
+ path with an existing real parent; existing files/symlinks are refused, never
75
+ overwritten. JSON output names `prepareRequestFile` and records the explicit
76
+ request-file write in `effects`; it does not echo the request contents. The
77
+ export can carry unclassified adoption declarations and must remain private;
78
+ requests must contain nonsecret values or credential references, never secrets.
79
+ A held inspection cannot emit a fresh preparation request. Core callers can
80
+ explicitly request this data via `{includePrepareRequest:true}`; the default
81
+ metadata projection and its omissions are unchanged.
82
+
83
+ The file is reusable new-work input, NOT a stored resolution, approval, admission,
84
+ or serialized ready-inspection permission. Preparation performs fresh validation
85
+ and observations, including re-resolving any mutable source selectors. Provider
86
+ configuration still requires explicit operator choices; conversion invents none.
70
87
 
71
88
  Existing managed deployment state is preserved and reported, not repaired or
72
89
  migrated. An absent selected path requires explicit operator provisioning and
73
- reinspection. The serialized inspection does not lock the filesystem or authorize
90
+ reinspection. Prepare refuses it with typed `needs-configuration` and provisioning
91
+ guidance before fetching or writing managed state, not a raw ENOENT. Inspection's
92
+ `ready` means the path is eligible for fresh setup, not already provisioned.
93
+ The serialized inspection does not lock the filesystem or authorize
74
94
  later mutation; preparation retains its own existing validation/custody rules.
75
95
  The inspected work target does not become source identity or an implied placement
76
96
  choice. Supported captured directory scaffolds own their separate H/work.
77
97
 
78
98
  ## Existing preparation and retained execution
79
99
 
80
- `oats prepare --request` already accepts deployment/source/origin, workspace/member
81
- OR standalone context, operator policy/bindings, mode/local-input authorization,
82
- launch and helperLaunches. Do not pass the inspection result or workTarget/catalog
83
- wrapper. Exact executable approval is separate. A required provider whose binding
100
+ `oats prepare --request` accepts deployment/source/origin, optional `workTarget`,
101
+ workspace/member OR standalone context, operator policy/bindings,
102
+ mode/local-input authorization, launch and helperLaunches. The original minimal
103
+ inspection request (without inspection-only `catalogIndexes`) is also accepted;
104
+ use the converter rather than stripping fields from a metadata/result wrapper.
105
+ Explicit `workTarget` is validated with the same physical existing-directory
106
+ validator as inspection and returned as work-context metadata. It takes precedence
107
+ over any caller assumption about cwd: no cwd/config fallback selects its value.
108
+ Omitting it preserves prior preparation behavior without inventing a placement.
109
+ It does not change source identity, `operator.localBase`, work mode, or captured
110
+ H/work placement. Do not pass an inspection result/catalog wrapper or private
111
+ scratch `directory` to preparation. Exact executable approval is separate. A required provider whose binding
84
112
  code is unapproved may return `needs-configuration` with an `approval-required`
85
113
  problem and exact artifact-set/capability requests, before any record exists:
86
114
 
@@ -92,6 +120,44 @@ oats spawn <subject> --deployment <D> --resolution <R> --home <new-H> --no-launc
92
120
  oats session start --deployment <D> --resolution <R> --home <H> --request /absolute/native.json --json
93
121
  ```
94
122
 
123
+ Each `selections[]` row carries an `artifactSet` id and an `approvalRequired[]`
124
+ array of **capability ids**. Pair them: pass the capability to `trust` and that
125
+ row's artifact-set id to `--artifact-set`. These are not interchangeable ids.
126
+ `trust <capability> --dir <D>` against a v3 deployment now refuses with typed
127
+ `needs-configuration` and exact available-set commands; it never picks or approves
128
+ a set automatically. Classic v1/v2 trust remains the classic route.
129
+
130
+ Provider preparation problems carry `slot` and `capability`, plus original
131
+ provenance where available. A no-interface provider is identified with kernel-known
132
+ manifest/version facts. Other supported slots still normalize, resolve through
133
+ the same choice engine, and bind if their own choices are resolved; any required
134
+ slot problem still prevents publication. Provider free text is not passed through.
135
+ Different opaque inputs need not produce different public errors if both fail the
136
+ same provider prerequisite. In particular, missing OKF host runtime settings can
137
+ hold both syntactically valid Git locators; preparation does not test whether a
138
+ remote repository exists. Required readiness checks remain later, with the provider.
139
+
140
+ ### Operator input
141
+
142
+ When present, `operator` requires both `policy` (object; `{}` is valid) and
143
+ `document` (`{ "kind": "operator", "id": "setup-attempt" }`). Its ONLY optional
144
+ fields are `localBase`, `allowLocalPaths`, `sourceContext`, and `bindings`:
145
+
146
+ - `policy`: explicit provider/additive selections with their selected sources and
147
+ settings, using the existing policy grammar. It cannot erase soul requirements.
148
+ - `localBase`: explicit absolute base for relative local policy sources. Work
149
+ context/cwd is not a substitute.
150
+ - `allowLocalPaths`: explicit boolean authorization for those local policy sources.
151
+ Top-level local acquisition authorization remains a separate input.
152
+ - `sourceContext`: existing qualified repository anchor for `repo:` policy sources;
153
+ not a new repository inferred from workTarget.
154
+ - `bindings`: provider-owned map. Kernel preserves it and its document pointers;
155
+ it does not interpret store names, Git destinations, credentials or private teams.
156
+
157
+ Selecting an inherited store does not replace required provider runtime settings.
158
+ Use the selected provider's instructions for those settings; kernel must not guess
159
+ host-owned durable paths or copy native authentication.
160
+
95
161
  Repreparation after explicit approval is ordinary continuation in the selected,
96
162
  now-managed deployment; do not delete its state to make fresh preflight pass.
97
163
  Required hooks still run under their admitted custody with `--no-launch`; a parsed
@@ -42,6 +42,48 @@ For several repositories initialize their common workspace, then select the
42
42
  repository owning the soul with `--dir /path/to/workspace/project` for
43
43
  create/spawn/retire. A team roster does not select a work repository for spawn.
44
44
 
45
+ ## Onboarding with the setup expert
46
+
47
+ For a kernel build that includes `oats onboard` (check `oats onboard --help`),
48
+ start in an explicit empty deployment:
49
+
50
+ ```bash
51
+ oats onboard --dir /absolute/new-deployment --json
52
+ ```
53
+
54
+ This command is **not present in the published 0.24.0/0.24.1 kernels**. It is a
55
+ classic local bootstrap, not captured preparation or workspace enrollment. It
56
+ acquires `oats.framework` from the official catalog, exact-locks its artifacts,
57
+ selects only `oats.core` and `oats.setup` for the new local `oats-setup-expert`,
58
+ and prints the exact next spawn command. Review and run the returned
59
+ `result.next.command` when ready; it addresses this same kernel and deployment.
60
+ Onboarding itself never launches a model, changes native authentication or
61
+ installs capture hooks/services. **`oats setup` remains the separate record
62
+ capture-setup command**, not an alias for onboarding.
63
+
64
+ The expert receives `oats-operate`, `oats-souls`, `oats-config`, `oats-packages`
65
+ and `oats-workspace-setup`, without duplicate legacy kernel skill copies. It has
66
+ no hard knowledge/messaging dependency, so it can help select and configure those
67
+ providers afterward. Catalog identity grants no executable trust: the bootstrap
68
+ uses resource-only core/setup capabilities and refuses unexpected executable
69
+ surfaces instead of auto-approving them.
70
+
71
+ An existing roster is refused unless `--force-existing` is explicit. That flag
72
+ permits adding the new soul, not overwriting an existing setup expert or disabling
73
+ providers for other souls. Failures report partial acquisition/creation rather
74
+ than claiming atomic captured preparation. Preserve that evidence before retrying.
75
+
76
+ Optional `--workspace git:host/org/repository[@revision]` reads the selected
77
+ repository through ordinary discovery: use its pinned `oats-setup-expert` import
78
+ when present, otherwise its own advertised `souls/oats-setup-expert` edition at
79
+ the observed revision. Missing or incompatible explicit sources refuse; they do
80
+ not fall back to the packaged default. The copied edition's package must match
81
+ the official acquisition; workspace policy, teams and provider adoption values
82
+ are not silently adopted. Without this option, only the packaged definition and
83
+ instruction text are used—no knowledge corpus is bundled.
84
+
85
+ The manual path below retains its stated older integration/version scope.
86
+
45
87
  ## Configure explicit knowledge and optional messaging
46
88
 
47
89
  Edit the existing entries in `oats-config.yaml`; do not append a second
package/docs/layers.md CHANGED
@@ -80,7 +80,7 @@ Messaging is conversation, not automatically task state. Accepted knowledge may
80
80
 
81
81
  The current slot name is **`messaging`**. The capability owns native identity, addressing, team membership, transport, wake delivery and qualification. A team alias in a workspace is a declaration, not proof that an actor is enrolled or a privacy property is enforced.
82
82
 
83
- The released aweb1.10.3 integration supports its legacy setup/lifecycle path but lacks the captured provider-binding interface required for a new portable profile. That capability needs adaptation and real qualification; a codec that always refuses readiness is not completed messaging support.
83
+ aweb 1.10.3 supports its legacy setup/lifecycle path but lacks the captured provider-binding interface. **aweb 1.11.0** (OATS >=0.24.2) adds it: `check` qualifies HOME-route operational custody for an input-capable Claude/Codex primary with an explicit private team and `delivery: session`; a strict-Pi print primary reports `needs-configuration` rather than dropping the requirement. Qualification is not account delegation, broker delivery or model consumption.
84
84
 
85
85
  The earlier proposed `reach` ladder is **not an enforced universal field**. In particular, aweb's `team_and_contacts` includes verified same-team senders; the compatibility spellings `contacts-only` and `contacts_only` do not establish owner-only admission. A config command succeeding proves neither inbound/outbound restrictions nor knowledge visibility. See the [identity/membership amendment](design/2026-09-08-expert-assisted-deployment-proposal.md#membership-reach-and-visibility-are-separate) and [messaging boundary](design/2026-09-16-messaging-capability-contract.md).
86
86
 
@@ -58,17 +58,22 @@ or workspace membership alone does not make a package official.
58
58
  Contact and license evidence may live in the package/repository documentation;
59
59
  this policy does not invent new catalog or manifest fields.
60
60
 
61
- ## Planned first set
61
+ ## Listed first set
62
62
 
63
- - Already listed: `oats.okf`, `oats.aweb`, `oats.authoring`, `oats.jira`,
64
- `oats.linear`, `oats.dev` and `oats.knowledge-theory`.
65
- - **Planned, not yet listed:** `oats.core` for OATS operation/soul guidance, and
66
- `oats.setup` for OATS Soul Setup, configuration and package guidance. Add their
67
- catalog entries only after their actual D1 package releases exist and pass
68
- review. They are not available merely because this document names them.
63
+ - Listed capabilities: `oats.okf`, `oats.aweb`, `oats.authoring`, `oats.jira`,
64
+ `oats.linear`, `oats.dev`, `oats.knowledge-theory`, `oats.core` and `oats.setup`.
65
+ - **`oats.framework` 1.1.1** is listed at tag `oats-framework/v1.1.1` in
66
+ `awebai/oats`, payload root `oats-package`. The `oats.core`, `oats.setup` and
67
+ `oats.knowledge-theory` aliases select that distribution; package identity is
68
+ distinct from capability identity. Core supplies operation/soul guidance;
69
+ setup supplies OATS Soul Setup, configuration and package guidance.
69
70
 
70
- The [workspace adoption guide](workspace-adoption.md) describes the separate
71
- planned setup-expert flow. No package is silently added to an existing soul.
71
+ These entries are in the current repository catalog. An older installed CLI keeps
72
+ its bundled catalog; publication here does not update that installation or rewrite
73
+ old source references, locks or tags. Follow that CLI's supported acquisition path.
74
+ The [workspace adoption guide](workspace-adoption.md) distinguishes the published
75
+ capabilities and five expert imports from the still-pending D3 setup-expert flow.
76
+ No package is silently added to an existing soul.
72
77
 
73
78
  ## Updates, deprecation and removal
74
79
 
package/docs/packages.md CHANGED
@@ -402,7 +402,7 @@ sources; installing a kernel does not advance existing package locks:
402
402
  {
403
403
  "packages": {
404
404
  "oats.okf": { "url": "https://github.com/awebai/oats-okf.git", "ref": "v2.0.0", "path": "oats-package" },
405
- "oats.knowledge-theory": { "url": "https://github.com/awebai/oats.git", "ref": "v0.23.0", "path": "oats-package" },
405
+ "oats.framework": { "url": "https://github.com/awebai/oats.git", "ref": "oats-framework/v1.1.1", "path": "oats-package" },
406
406
  "oats.dev": { "url": "https://github.com/awebai/oats-dev.git", "ref": "v1.0.0", "path": "oats-package" }
407
407
  },
408
408
  "capabilities": { "oats.review": "oats.dev" }
@@ -427,13 +427,17 @@ npm drops the source worker soul's `CLAUDE.md -> AGENTS.md`. It must not be
427
427
  advertised as a complete local package or repaired after acquisition to evade
428
428
  integrity checks. Git transport preserves the canonical source alias.
429
429
 
430
- The optional `oats.knowledge-theory` package is a separate Git payload in this
430
+ The `oats.framework` distribution package is a separate Git payload in this
431
431
  repository's `oats-package/`, excluded from the kernel npm tarball. The catalog
432
- entry selects published framework v0.23.0, which contains package 1.0.0.
433
- The source reference patch 1.0.1 is separately available through an explicit
434
- v0.23.1 Git source after that framework tag is published. It supplies an authoring skill and
435
- `knowledge-theory-expert`, not a default knowledge-layer binding, runtime judge
436
- or OKF dependency. Acquiring it does not activate it.
432
+ entry selects the published `oats-framework/v1.1.1` tag, which exports three
433
+ capabilities: `oats.core` (day-to-day operation: `oats-operate`, `oats-souls`
434
+ and the "you run on OATS" briefing — declared explicitly on every soul by
435
+ default at creation and removable), `oats.setup` (OATS Soul Setup: `oats-config`,
436
+ `oats-packages`, `oats-workspace-setup`) and the optional `oats.knowledge-theory`
437
+ (authoring skill and `knowledge-theory-expert`). Acquire it with
438
+ `oats install oats.framework`; the capability ids also resolve through the
439
+ catalog aliases. Acquiring it does not activate anything, bind a knowledge
440
+ layer or add a runtime judge.
437
441
 
438
442
  Updating OKF v1 to v2 is a breaking capability change. Preserve existing
439
443
  knowledge and source state/cursors, explicitly bind/provision external owners,