@awebai/oats 0.23.2 → 0.24.1
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/README.md +224 -391
- package/bin/oats-pi-sdk-host.mjs +17 -0
- package/bin/oats.mjs +470 -51
- package/capabilities/oats-okf/bin/oats-okf-binding.mjs +14 -0
- package/capabilities/oats-okf/bin/oats-okf.mjs +79 -11
- package/capabilities/oats-okf/lib/binding-wire.mjs +268 -0
- package/capabilities/oats-okf/lib/captured-worker.mjs +109 -0
- package/capabilities/oats-okf/lib/config.mjs +2 -1
- package/capabilities/oats-okf/lib/inspection.mjs +16 -1
- package/capabilities/oats-okf/lib/invocation-context.mjs +111 -0
- package/capabilities/oats-okf/lib/invocation-shape.mjs +135 -0
- package/capabilities/oats-okf/lib/io.mjs +1 -1
- package/capabilities/oats-okf/lib/portable-binding.mjs +199 -0
- package/capabilities/oats-okf/lib/source-contract.mjs +46 -0
- package/capabilities/oats-okf/lib/sources.mjs +123 -3
- package/capabilities/oats-okf/lib/stores.mjs +104 -25
- package/capabilities/oats-okf/lib/worker.mjs +69 -10
- package/capabilities/oats-okf/oats.json +35 -7
- package/capabilities/oats-okf/schemas/okf-portable-declaration.schema.json +87 -0
- package/capabilities/oats-okf/schemas/okf-portable-payload.schema.json +113 -0
- package/capabilities/oats-okf/skills/memory-harvest/SKILL.md +23 -5
- package/capabilities/oats-okf/skills/okf/SKILL.md +42 -1
- package/docs/artifact-approvals.schema.json +7 -0
- package/docs/capabilities.md +4 -0
- package/docs/capability-manifest.schema.json +37 -66
- package/docs/captured-invocation-context.schema.json +7 -0
- package/docs/captured-resolution.schema.json +7 -0
- package/docs/design/2026-09-14-artifact-retention-contract.md +190 -0
- package/docs/design/2026-09-14-portable-souls-and-git-workspaces.md +708 -0
- package/docs/design/2026-09-14-portable-souls-contract-amendments.md +85 -0
- package/docs/design/2026-09-14-portable-souls-explainer.md +750 -0
- package/docs/design/2026-09-15-captured-dispatch.md +127 -0
- package/docs/design/2026-09-15-captured-resolution-records.md +143 -0
- package/docs/design/2026-09-15-package-preparation.md +100 -0
- package/docs/design/2026-09-15-portable-data-contract.md +121 -0
- package/docs/design/2026-09-15-portable-declarations.md +189 -0
- package/docs/design/2026-09-15-portable-souls-handoff.md +150 -0
- package/docs/design/2026-09-15-portable-souls-implementation.md +417 -0
- package/docs/design/2026-09-15-selection-lock-and-approval.md +122 -0
- package/docs/design/2026-09-15-source-observation.md +119 -0
- package/docs/design/2026-09-16-captured-admission.md +77 -0
- package/docs/design/2026-09-16-captured-helper-dispatch.md +105 -0
- package/docs/design/2026-09-16-captured-launch-inputs.md +42 -0
- package/docs/design/2026-09-16-command-profile-preparation.md +86 -0
- package/docs/design/2026-09-16-fresh-install-first-rollout.md +47 -0
- package/docs/design/2026-09-16-fresh-operator-walkthrough.md +277 -0
- package/docs/design/2026-09-16-knowledge-capability-contract.md +61 -0
- package/docs/design/2026-09-16-messaging-capability-contract.md +59 -0
- package/docs/design/2026-09-16-portable-migration-evidence.md +156 -0
- package/docs/design/2026-09-16-portable-onboarding.md +177 -0
- package/docs/design/2026-09-16-prepare-request-transport.md +26 -0
- package/docs/design/2026-09-16-provider-binding-codecs.md +98 -0
- package/docs/design/2026-09-16-provider-binding-wire.md +247 -0
- package/docs/design/2026-09-17-capability-helper-input-contract.md +95 -0
- package/docs/design/2026-09-17-captured-backend-parity.md +53 -0
- package/docs/design/2026-09-17-captured-native-start.md +58 -0
- package/docs/design/2026-09-17-portable-boundary-hookup.md +19 -0
- package/docs/design/2026-09-17-portable-boundary-resources.md +52 -0
- package/docs/design/2026-09-17-public-captured-start.md +108 -0
- package/docs/design/2026-09-17-public-prepare-request.md +90 -0
- package/docs/design/2026-09-18-captured-pi-host.md +205 -0
- package/docs/design/2026-09-18-first-cut-release-checklist.md +131 -0
- package/docs/design/2026-09-18-herdr-protocol-compatibility.md +60 -0
- package/docs/design/2026-09-20-redesign-program-board.md +70 -0
- package/docs/design/2026-09-20-workspace-and-portable-adoption-plan.md +287 -0
- package/docs/design/2026-09-20-workspace-onboarding-public.md +124 -0
- package/docs/design/README.md +42 -0
- package/docs/desktop-cli-api.md +5 -2
- package/docs/execution-capsule.schema.json +108 -0
- package/docs/execution-targets.md +20 -7
- package/docs/first-team.md +1 -1
- package/docs/knowledge-theory.md +353 -111
- package/docs/knowledge.md +10 -1
- package/docs/layers.md +89 -354
- package/docs/oats-lock-v3.schema.json +7 -0
- package/docs/oats-member.schema.json +38 -0
- package/docs/oats-workspace.schema.json +68 -0
- package/docs/official-marketplace.md +79 -0
- package/docs/packages.md +4 -0
- package/docs/portable.schema.json +2512 -0
- package/docs/provider-check-input.schema.json +7 -0
- package/docs/release-notes/v0.24.0.md +104 -0
- package/docs/release-notes/v0.24.1.md +17 -0
- package/docs/schedules.md +126 -14
- package/docs/soul.schema.json +82 -0
- package/docs/souls-and-instances.md +20 -7
- package/docs/workspace-adoption.md +285 -0
- package/docs/workspaces.md +154 -0
- package/injects/oats-portable.md +16 -0
- package/injects/portable-instance-boundary.md +39 -0
- package/injects/portable-work-directory.md +29 -0
- package/lib/artifact-approvals.mjs +120 -0
- package/lib/artifact-tree.mjs +141 -0
- package/lib/capability-artifacts.mjs +179 -0
- package/lib/capability-execution.mjs +15 -0
- package/lib/capability-inputs.mjs +39 -0
- package/lib/capability-provenance.mjs +231 -0
- package/lib/captured-action-shape.mjs +21 -0
- package/lib/captured-admission-shape.mjs +20 -0
- package/lib/captured-binding-file.mjs +36 -0
- package/lib/captured-dispatch.mjs +66 -0
- package/lib/captured-instance-index.mjs +277 -0
- package/lib/captured-invocation-context.mjs +130 -0
- package/lib/captured-launch-request.mjs +46 -0
- package/lib/captured-operation-process.mjs +15 -0
- package/lib/captured-pi-custody.mjs +29 -0
- package/lib/captured-pi-host.mjs +167 -0
- package/lib/captured-pi-outcome.mjs +172 -0
- package/lib/captured-resolutions.mjs +275 -0
- package/lib/captured-scaffold.mjs +87 -0
- package/lib/captured-selector.mjs +28 -0
- package/lib/captured-session-backend.mjs +52 -0
- package/lib/captured-source-receipt-file.mjs +72 -0
- package/lib/config-data.mjs +104 -0
- package/lib/core.mjs +961 -566
- package/lib/errors.mjs +7 -0
- package/lib/helper-injection-policy.mjs +98 -0
- package/lib/herdr.mjs +18 -7
- package/lib/instruction-composition.mjs +31 -0
- package/lib/legacy-lock-codec.mjs +106 -0
- package/lib/manifest-settings.mjs +84 -0
- package/lib/package-closure.mjs +48 -0
- package/lib/package-materialization.mjs +83 -0
- package/lib/pi-sdk-host.mjs +229 -0
- package/lib/portable-artifacts.mjs +115 -0
- package/lib/portable-choices.mjs +82 -0
- package/lib/portable-composition.mjs +136 -0
- package/lib/portable-digest.mjs +105 -0
- package/lib/portable-files.mjs +26 -0
- package/lib/portable-identity.mjs +40 -0
- package/lib/portable-lock.mjs +117 -0
- package/lib/portable-migration-artifacts.mjs +135 -0
- package/lib/portable-migration-evidence.mjs +305 -0
- package/lib/portable-migration-store.mjs +199 -0
- package/lib/portable-migration.mjs +104 -0
- package/lib/portable-onboarding-acceptance.mjs +66 -0
- package/lib/portable-onboarding-request.mjs +49 -0
- package/lib/portable-onboarding.mjs +249 -0
- package/lib/portable-package-preparation.mjs +188 -0
- package/lib/portable-policy.mjs +44 -0
- package/lib/portable-shape.mjs +35 -0
- package/lib/portable-soul.mjs +38 -0
- package/lib/portable-state.mjs +80 -0
- package/lib/portable-values.mjs +181 -0
- package/lib/prepare-composition.mjs +151 -0
- package/lib/prepared-bindings.mjs +78 -0
- package/lib/prepared-resources.mjs +127 -0
- package/lib/provider-binding-broker.mjs +59 -0
- package/lib/provider-binding-wire.mjs +110 -0
- package/lib/provider-binding.mjs +22 -0
- package/lib/repository-observation.mjs +226 -0
- package/lib/resolution-shape.mjs +393 -0
- package/lib/schedule-capsule.mjs +206 -0
- package/lib/schedule.mjs +259 -38
- package/lib/servers.mjs +15 -0
- package/lib/soul-constraints.mjs +40 -0
- package/lib/source-projection.mjs +84 -0
- package/lib/source-spec.mjs +189 -0
- package/lib/workspace-definition.mjs +126 -0
- package/lib/workspace-discovery.mjs +146 -0
- package/package-catalog.json +2 -1
- package/package.json +3 -2
- package/packages/record/lib/capture-cc.mjs +14 -6
- package/packages/record/lib/formats.mjs +14 -3
- package/packages/record/lib/native-history.mjs +277 -7
- package/packages/record/lib/session-snapshot.mjs +25 -5
- package/packages/record/lib/sessions-for-home.mjs +30 -13
- package/skills/oats/SKILL.md +12 -7
- package/skills/oats-config/SKILL.md +11 -9
- package/skills/oats-packages/SKILL.md +12 -8
- package/skills/oats-portable/SKILL.md +115 -0
- package/skills/oats-portable-artifacts/SKILL.md +63 -0
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
# Adopt the OATS development workspace
|
|
2
|
+
|
|
3
|
+
OATS hosts the shared `oats-workspace.yaml`. Its separate `oats.yaml` advertises
|
|
4
|
+
source-complete exports and declares its own reciprocal membership. `oats-dev`
|
|
5
|
+
remains a development-capability repository, including `oats.review`; membership
|
|
6
|
+
neither activates that package nor replaces its existing configuration templates.
|
|
7
|
+
|
|
8
|
+
This is phase 1: a shared repository graph and a transitional portable edition of
|
|
9
|
+
**the existing oats-expert**. It is not the five-role rebuild, the curated knowledge
|
|
10
|
+
cutover, a shared live runtime, a private-team enrollment or Desktop feature parity.
|
|
11
|
+
The [phase plan](design/2026-09-20-workspace-and-portable-adoption-plan.md) and
|
|
12
|
+
[knowledge model](knowledge-theory.md) retain those separate boundaries.
|
|
13
|
+
|
|
14
|
+
## Shared versus local
|
|
15
|
+
|
|
16
|
+
| Git-shared declaration | Operator-local input or evidence |
|
|
17
|
+
| --- | --- |
|
|
18
|
+
| Workspace membership candidates and reviewed source import pins | Local source access and qualified repository observations |
|
|
19
|
+
| A repository's backlink and real package/soul export paths | Working checkout mappings and the explicitly chosen work target |
|
|
20
|
+
| Intrinsic capability requirements and logical knowledge interests | Provider settings, explicit store binding, private human/team choices |
|
|
21
|
+
| Complete immutable instructions and skill resources | Native harness/model/auth, backend endpoint, home and durable state |
|
|
22
|
+
| A reviewed source revision | Exact executable approval, current readiness and deployment acceptance |
|
|
23
|
+
|
|
24
|
+
No machine paths, credentials, private team identifiers, accepted-store locator or
|
|
25
|
+
owner registry belongs in the public workspace. The uninitialized phase-2 knowledge
|
|
26
|
+
repository is not advertised as a ready knowledge export. Preserve the parked
|
|
27
|
+
roster/curation and every old home, lock, source, pending job, history and worktree.
|
|
28
|
+
|
|
29
|
+
## Planned onboarding: OATS Soul Setup (D3)
|
|
30
|
+
|
|
31
|
+
**Not shipped in OATS 0.24.** The planned onboarding flow creates and instantiates
|
|
32
|
+
`oats-setup-expert`, declaring both `oats.core` and `oats.setup` from the
|
|
33
|
+
[official marketplace](official-marketplace.md). Their package releases and this
|
|
34
|
+
onboarding flow are future work, not existing catalog entries or a new command
|
|
35
|
+
introduced by this guide.
|
|
36
|
+
|
|
37
|
+
- The setup expert will help the operator adopt repositories, select capabilities
|
|
38
|
+
and carry out the normal prepare/approve/scaffold/start steps. It bypasses no
|
|
39
|
+
executable approval, provider readiness, identity or permission boundary.
|
|
40
|
+
- Every soul created by that flow will declare `requires.capabilities.oats.core`
|
|
41
|
+
and its source explicitly. The operator can remove or replace that dependency
|
|
42
|
+
by editing the authored definition, not a captured record; the kernel will not
|
|
43
|
+
silently reinsert an absent one.
|
|
44
|
+
- The CLI/Desktop entry point remains separately implemented and reviewed. Do not
|
|
45
|
+
invent a workspace init/adopt command, create a setup soul from this sketch, or
|
|
46
|
+
treat a planned package as installed. Existing instances and retained resources
|
|
47
|
+
are not rewritten by the plan.
|
|
48
|
+
|
|
49
|
+
## What this first source commit establishes
|
|
50
|
+
|
|
51
|
+
- `oats-workspace.yaml` explicitly admits `oats` and the six intended capability
|
|
52
|
+
repositories: `oats-dev`, `oats-okf`, `oats-aweb`, `oats-authoring`, `oats-jira`
|
|
53
|
+
and `oats-linear`. It activates no additional capability; tasks default to none.
|
|
54
|
+
- `oats.yaml` advertises `souls/oats-expert` and the actual framework package roots
|
|
55
|
+
`oats-package` and `capabilities/oats-authoring`, not the npm root as a fictitious
|
|
56
|
+
OATS distribution. Its workspace backlink names the same framework repository.
|
|
57
|
+
- `souls/oats-expert/` is parallel to, not a replacement for, the live `agents/`
|
|
58
|
+
source. It contains canonical instructions, `CLAUDE.md -> AGENTS.md`, and the
|
|
59
|
+
existing reviewed PR/release procedure closure. No durable KB is copied into it.
|
|
60
|
+
- The role preserves its knowledge owner, owned node and four cross-read interests.
|
|
61
|
+
Store `oats` requires the explicit `stores.oats` binding; no publisher writer,
|
|
62
|
+
production store or grants are supplied. An acceptance fixture is parent-owned
|
|
63
|
+
and cannot be counted as production knowledge adoption.
|
|
64
|
+
- Knowledge **oats.okf@2.1.1** and messaging **oats.aweb@1.10.3** are explicit hard
|
|
65
|
+
requirements, not optional defaults. They are published starting revisions,
|
|
66
|
+
**not proof that their combined bindings/runtime profile is ready**. The provider
|
|
67
|
+
owner supplies that evidence and any subsequently reviewed compatible revision.
|
|
68
|
+
Do not replace either requirement with none or erase a read edge to launch.
|
|
69
|
+
|
|
70
|
+
At these starting pins, the provider boundary is concrete:
|
|
71
|
+
|
|
72
|
+
- Published OKF2.1.0 already supports `inherit: stores.oats`, normalized to
|
|
73
|
+
`/bindings/knowledge/stores/oats`. The explicit `destination: oats` preserves
|
|
74
|
+
routing; omitting it would instead require `write.default`. No new schema,
|
|
75
|
+
owner or production locator is needed for this declaration.
|
|
76
|
+
- Released aweb1.10.3 (`24efa6f9`) has **no mandatory portable binding interface**,
|
|
77
|
+
so it currently blocks this pilot's portable preparation. Candidate
|
|
78
|
+
[aweb PR2](https://github.com/awebai/oats-aweb/pull/2), `165b20e7`, adds codecs;
|
|
79
|
+
it is not a reviewed/published successor or native lifecycle qualification.
|
|
80
|
+
Human/native-principal, private-context, admin/grant and admitted-lifecycle
|
|
81
|
+
requirements remain provider/integration-owner work.
|
|
82
|
+
- Published OKF2.1.0's captured worker profile retains its strict Pi,
|
|
83
|
+
explicit-model and sole-OKF limitation. Candidate
|
|
84
|
+
[OKF PR4](https://github.com/awebai/oats-okf/pull/4), `7cff887c`, preserves retained
|
|
85
|
+
Claude/Codex/null-model intent and the approved helper capability closure;
|
|
86
|
+
review is pending, not published2.1.0 behavior. Pi plus messaging is still
|
|
87
|
+
unqualified. Do not silently switch runtimes, force a model, or drop capabilities.
|
|
88
|
+
|
|
89
|
+
These are explicit readiness holds, not reasons to weaken the source. Parent must
|
|
90
|
+
select reviewed compatible provider revisions and update the source pin deliberately
|
|
91
|
+
before claiming an operational pilot; metadata-only repository indexes change none
|
|
92
|
+
of these runtime facts.
|
|
93
|
+
|
|
94
|
+
The workspace intentionally starts with **`imports: []`**. A source cannot pin a
|
|
95
|
+
future commit containing itself. This first commit is publishable source metadata,
|
|
96
|
+
not an already usable/adopted pilot graph or a phase-1 exit verdict.
|
|
97
|
+
|
|
98
|
+
## Publish in this order
|
|
99
|
+
|
|
100
|
+
1. Review and publish this source/export commit to the framework repository. Save
|
|
101
|
+
the **actual reviewed immutable source commit** containing the complete soul.
|
|
102
|
+
Do not put an invented SHA, a mutable branch or an unreviewed local candidate
|
|
103
|
+
in the workspace import and describe it as the accepted source.
|
|
104
|
+
2. In each of the six repositories, review a root `oats.yaml` against its actual
|
|
105
|
+
source head and actual `oats-package/oats-package.json`. The declaration is:
|
|
106
|
+
|
|
107
|
+
```yaml
|
|
108
|
+
schemaVersion: 1
|
|
109
|
+
workspace:
|
|
110
|
+
source: git:github.com/awebai/oats
|
|
111
|
+
exports:
|
|
112
|
+
packages:
|
|
113
|
+
- path: oats-package
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Preserve payloads, versions, old tags and legacy templates. This does not
|
|
117
|
+
activate oats.dev, messaging or either optional task integration.
|
|
118
|
+
3. In a subsequent reviewed framework commit, replace the empty imports list with
|
|
119
|
+
an import of the source commit from step 1:
|
|
120
|
+
|
|
121
|
+
```yaml
|
|
122
|
+
imports:
|
|
123
|
+
- source: git:github.com/awebai/oats
|
|
124
|
+
soul: souls/oats-expert
|
|
125
|
+
revision: <actual-reviewed-published-source-commit>
|
|
126
|
+
alias: oats-expert
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The placeholder is explanatory text, never a value to commit. Update the
|
|
130
|
+
staged-import test with that real publication evidence at this step. Do not
|
|
131
|
+
change the stable export path or owner merely because the workspace advances.
|
|
132
|
+
4. Qualify reciprocal admission at the now-published observations. A missing
|
|
133
|
+
backlink, a fork's copied file or a stale workspace observation is not membership.
|
|
134
|
+
Cross-repository indexes may land separately; until both sides exist, report the
|
|
135
|
+
specific unqualified member rather than claim the whole graph is ready.
|
|
136
|
+
|
|
137
|
+
Membership selectors and backlinks omit `revision` deliberately: the repository
|
|
138
|
+
adapter observes the hosting provider's actual default branch, not a guessed
|
|
139
|
+
`main`. Within one preparation, observations are frozen. In particular, the
|
|
140
|
+
framework's self-member and workspace backlink must resolve to the **same commit**.
|
|
141
|
+
A separately pinned older workspace with backlinks resolving to a later head is
|
|
142
|
+
correctly stale; choose a fresh coherent observation, never rewrite an old retained
|
|
143
|
+
record. Imports have their own immutable source revision and need not track each
|
|
144
|
+
new workspace metadata commit.
|
|
145
|
+
|
|
146
|
+
Importing the exported soul directly does **not** follow the publisher's workspace
|
|
147
|
+
as adopter policy. A different workspace, or an explicitly standalone operator,
|
|
148
|
+
may consume it without membership in the OATS development workspace.
|
|
149
|
+
|
|
150
|
+
## Inspect source metadata before preparation
|
|
151
|
+
|
|
152
|
+
The public source inspector is implemented in **PR24, commit
|
|
153
|
+
`bc598c484fd097fc5707fd4a33b7877ca00e5da3`**. Use this section only after the
|
|
154
|
+
integration owner supplies a reviewed CLI containing that implementation. It is
|
|
155
|
+
**not a command supported by the original 0.24.0 release**: that older inspect
|
|
156
|
+
route can ignore the request flag and consult ambient classic configuration.
|
|
157
|
+
Do not infer availability from the version floor of a capability.
|
|
158
|
+
|
|
159
|
+
```sh
|
|
160
|
+
oats inspect --request /absolute/inspection.json --json
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
After the real workspace import from publication step 3 exists, the authored
|
|
164
|
+
inspection input may use the same repository for workspace, member and source:
|
|
165
|
+
|
|
166
|
+
```json
|
|
167
|
+
{
|
|
168
|
+
"deployment": "/operator/deployments/oats-pilot",
|
|
169
|
+
"workTarget": "/operator/projects/oats",
|
|
170
|
+
"source": "oats-expert",
|
|
171
|
+
"origin": {
|
|
172
|
+
"kind": "operator",
|
|
173
|
+
"document": {"kind": "operator", "id": "workspace-adoption"},
|
|
174
|
+
"pointer": "/source"
|
|
175
|
+
},
|
|
176
|
+
"workspace": {
|
|
177
|
+
"source": "git:github.com/awebai/oats",
|
|
178
|
+
"origin": {
|
|
179
|
+
"kind": "operator",
|
|
180
|
+
"document": {"kind": "operator", "id": "workspace-adoption"},
|
|
181
|
+
"pointer": "/workspace"
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
"member": {
|
|
185
|
+
"source": "git:github.com/awebai/oats",
|
|
186
|
+
"origin": {
|
|
187
|
+
"kind": "operator",
|
|
188
|
+
"document": {"kind": "operator", "id": "workspace-adoption"},
|
|
189
|
+
"pointer": "/member"
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
The paths are operator-selected examples, not host defaults or new grants.
|
|
196
|
+
Independent adoption uses the full source/soul/revision/alias reference and an
|
|
197
|
+
explicit standalone context instead of workspace/member. Do not mix this inspect
|
|
198
|
+
mode with current-context flags or captured deployment/resolution selectors.
|
|
199
|
+
|
|
200
|
+
The result is **non-authorizing metadata**, not provider readiness: even `ok:true`
|
|
201
|
+
may carry `needs-configuration` or `separate-deployment-required`. A
|
|
202
|
+
`ready-for-preparation` observation still has no approval or enrollment effect.
|
|
203
|
+
Provider payloads and opaque adoption values are deliberately omitted. Preserve
|
|
204
|
+
the original authored inputs; neither the result nor its inspection request is a
|
|
205
|
+
preparation request or an issued mutation witness. In particular, `workTarget`
|
|
206
|
+
and inspection catalog wrappers are not accepted preparation fields.
|
|
207
|
+
|
|
208
|
+
The inspector owns transient repository scratch but writes no deployment state.
|
|
209
|
+
Missing paths need explicit operator provisioning and reinspection, not automatic
|
|
210
|
+
repair. Observing a project work target does not change the separate captured H/work
|
|
211
|
+
placement. Existing retained inspect remains the later exact-record inspection.
|
|
212
|
+
|
|
213
|
+
## Prepare a fresh local pilot only after the profile is qualified
|
|
214
|
+
|
|
215
|
+
Use the selected installed compatible CLI. Do not turn this source check into a
|
|
216
|
+
global install, a daemon start or a model/GUI test on another operator's machine.
|
|
217
|
+
Keep native HOME/profile/auth and explicit permission choices; no credential copy
|
|
218
|
+
or empty profile. Knowledge, messaging and tasks have distinct authority contracts.
|
|
219
|
+
|
|
220
|
+
Before preparing, the integration lead must supply:
|
|
221
|
+
|
|
222
|
+
- The published workspace/source observations and an explicit fresh physical
|
|
223
|
+
deployment/home placement. Do not copy old locks, retained records or identities.
|
|
224
|
+
- An operator-owned nonsecret request with `workspace` (its source and origin),
|
|
225
|
+
`source: "oats-expert"` after the real import is published, and `mode: "directory"`.
|
|
226
|
+
Standalone callers instead give the complete `{source,soul,revision,alias}`
|
|
227
|
+
reference and an explicit standalone context; they do not inherit this workspace.
|
|
228
|
+
- Explicit provider-specific settings and bindings. OKF preparation needs selected
|
|
229
|
+
absolute `bindings-file` and `state-dir`, `harvest-runtime`, and the `stores.oats`
|
|
230
|
+
binding; an omitted `harvest-model` preserves native-default intent. The parent-owned
|
|
231
|
+
acceptance fixture must supply an accepted node registry supporting the preserved
|
|
232
|
+
owner **and all four read nodes**. This is not accepted production KB publication;
|
|
233
|
+
Git destinations remain PR-only.
|
|
234
|
+
- Actual messaging human/context inputs and the pilot's explicit **`delivery: session`**
|
|
235
|
+
setting (aweb's default is channel). Supply it in the complete supported
|
|
236
|
+
`operator.policy.messaging` selection: capability, matching selected source and
|
|
237
|
+
`settings: {delivery: session}`. Retain host requirements, session `ifInstalled`
|
|
238
|
+
minimums and any selected authoring requirements. Selecting session delivery neither
|
|
239
|
+
adds the missing1.10.3 binding adapter nor supplies captured wake/input authority.
|
|
240
|
+
- A qualified primary/helper runtime/model/resource profile. Capture the intended
|
|
241
|
+
helper selection in `helperLaunches["oats.okf:memory-harvest"]`, not the legacy
|
|
242
|
+
`souls.memory-harvest` configuration. Do not replace retained intent to fit an easier
|
|
243
|
+
runtime profile. An old default-OKF-only learning gate does not qualify a combined
|
|
244
|
+
aweb profile. If provider or kernel support is missing, stop at that typed result;
|
|
245
|
+
do not bypass it with a legacy route, a dropped capability or a fabricated identity.
|
|
246
|
+
|
|
247
|
+
The existing public routes are stepwise (D/R/H are returned or explicitly approved
|
|
248
|
+
values, not names inferred from cwd):
|
|
249
|
+
|
|
250
|
+
```sh
|
|
251
|
+
oats prepare --request /absolute/operator-preparation.json --json
|
|
252
|
+
# Review returned exact artifacts/problems; approve only explicitly authorized code.
|
|
253
|
+
oats trust <capability-id> --deployment "$D" --artifact-set "$ARTIFACT_SET" --json
|
|
254
|
+
oats prepare --request /absolute/operator-preparation.json --json
|
|
255
|
+
oats inspect --deployment "$D" --resolution "$R" --composition --json
|
|
256
|
+
oats spawn oats-expert --deployment "$D" --resolution "$R" --home "$H" --no-launch --json
|
|
257
|
+
oats session start --deployment "$D" --resolution "$R" --home "$H" \
|
|
258
|
+
--request /absolute/approved-native-request.json --json
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Do not mix other preparation flags into request-file mode. A needs-configuration or
|
|
262
|
+
approval result is not a ready instance. A scaffold materializes resources and may
|
|
263
|
+
run approved hooks; it is not a message exchange or model session. Actual dispatch,
|
|
264
|
+
continuation, native capture, messaging and learning require the integration owner's
|
|
265
|
+
qualified profile and receipts. Captured wake/input and public captured retirement
|
|
266
|
+
remain unsupported; a stopped-home observation is not delivery or retirement authority.
|
|
267
|
+
A session-delivered messaging profile therefore cannot pass on start-only evidence.
|
|
268
|
+
Do not route it through legacy input/retire or remove the messaging requirement.
|
|
269
|
+
Consult the current installed public help and the provider's supported commands;
|
|
270
|
+
this guide introduces no new CLI grammar. The source inspector above is a separate
|
|
271
|
+
implementation dependency, not a change to the existing prepare request contract.
|
|
272
|
+
|
|
273
|
+
## Local checks and limits
|
|
274
|
+
|
|
275
|
+
`node --test test/workspace-repository-layout.test.mjs` checks the actual declarations
|
|
276
|
+
against the shipped codecs/schemas, required providers and owner/read mapping, and
|
|
277
|
+
contained source resources. An isolated native-Git fixture exercises source-before-
|
|
278
|
+
import publication, host-default observations, reciprocal/self admission, refusal of
|
|
279
|
+
missing/stale backlinks, and independent public source projection. Fixture member
|
|
280
|
+
indexes are not evidence that the six real repositories are already published.
|
|
281
|
+
|
|
282
|
+
Source and metadata checks do not enroll users, initialize the phase-2 store, register
|
|
283
|
+
production writers or qualify private messaging. Parent alone coordinates publication,
|
|
284
|
+
local operator approval and actual adoption. Full Desktop parity follows usable
|
|
285
|
+
infrastructure adoption, not merely seven YAML files passing validation.
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# Workspaces, repositories and portable souls
|
|
2
|
+
|
|
3
|
+
A **workspace definition** describes a shared agent setup in Git. A **local deployment** is one operator's realization of it. A **portable soul** declares its role, requirements and software sources independently of either operator's directory layout.
|
|
4
|
+
|
|
5
|
+
This is the current OATS architecture. Start here for the model, then use [first-team onboarding](first-team.md) and the version-scoped [configuration](configuration.md) and [packages](packages.md) guides for operations. The [0.24 release notes](release-notes/v0.24.0.md) distinguish shipped foundations from unqualified profiles; an accepted architecture is not proof that every capability is ready.
|
|
6
|
+
|
|
7
|
+
## Four independent things
|
|
8
|
+
|
|
9
|
+
| Thing | What it decides | What it does not imply |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| Workspace | Intended repository membership, shared defaults, source imports and provider declarations | Installed software, executable approval, messaging enrollment or a shared live session |
|
|
12
|
+
| Source repository | The soul/package/store definitions it actually exports | Membership of every consumer in the publisher's workspace |
|
|
13
|
+
| Local deployment | Local mappings, retained artifacts/resolutions, operator inputs and execution state | Permission to change source requirements or copy another operator's credentials |
|
|
14
|
+
| Work target | Where an instance is assigned to work | Where its soul must be published, where knowledge must live or which team it joins |
|
|
15
|
+
|
|
16
|
+
A workspace needs no OATS account, registry or OATS-operated control plane. Git hosting, messaging and model providers retain their own access and authentication requirements.
|
|
17
|
+
|
|
18
|
+
## The three declaration files
|
|
19
|
+
|
|
20
|
+
### `oats-workspace.yaml` — the shared workspace
|
|
21
|
+
|
|
22
|
+
The workspace names intended members and may provide defaults, knowledge-store declarations, team aliases, catalogs and external soul imports. Omitted lists admit or activate nothing.
|
|
23
|
+
|
|
24
|
+
A workspace is a role, not a requirement for a separate repository. It can live in a dedicated repository or beside project code. For OATS development, the selected home is the `oats` framework repository; `oats-dev` remains a development-capability repository.
|
|
25
|
+
|
|
26
|
+
This schematic example uses placeholder sources, not a runnable published team:
|
|
27
|
+
|
|
28
|
+
```yaml
|
|
29
|
+
schemaVersion: 1
|
|
30
|
+
name: example-development
|
|
31
|
+
members:
|
|
32
|
+
- source: git:github.com/example/service
|
|
33
|
+
imports:
|
|
34
|
+
- source: git:github.com/example/experts
|
|
35
|
+
soul: souls/domain-expert
|
|
36
|
+
revision: reviewed-source-ref
|
|
37
|
+
alias: domain-expert
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Use actual reviewed source revisions when preparing work. When a repository reference omits its optional revision, discovery observes the hosting provider's intended default branch; it must not guess `main` or silently reuse unrelated local branch state.
|
|
41
|
+
|
|
42
|
+
### `oats.yaml` — a repository's advertised exports
|
|
43
|
+
|
|
44
|
+
A repository advertises the souls, package roots and provider-owned knowledge declarations it actually supplies. A member also points back to its workspace:
|
|
45
|
+
|
|
46
|
+
```yaml
|
|
47
|
+
schemaVersion: 1
|
|
48
|
+
workspace:
|
|
49
|
+
source: git:github.com/example/workspace
|
|
50
|
+
exports:
|
|
51
|
+
souls:
|
|
52
|
+
- path: souls/domain-expert
|
|
53
|
+
definition: souls/domain-expert/soul.yaml
|
|
54
|
+
packages:
|
|
55
|
+
- path: oats-package
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Only include exports that exist at the selected revision. A repository need not export every kind. A package export identifies a real directory containing `oats-package.json`; it is not an arbitrary npm package directory.
|
|
59
|
+
|
|
60
|
+
`oats-workspace.yaml` and `oats.yaml` may coexist. If the workspace host also participates as a member, it is explicitly admitted and has a matching backlink just like another member.
|
|
61
|
+
|
|
62
|
+
### `soul.yaml` — a source-complete specialist
|
|
63
|
+
|
|
64
|
+
A portable soul is an authored definition, not a dependency on whatever happens to be installed on its publisher's machine. It contains canonical `AGENTS.md`, a relative `CLAUDE.md` alias, its reviewed skill/resource closure and a versioned declaration.
|
|
65
|
+
|
|
66
|
+
For example, this declaration excerpt requires a particular knowledge capability **and names where it comes from**:
|
|
67
|
+
|
|
68
|
+
```yaml
|
|
69
|
+
schemaVersion: 1
|
|
70
|
+
name: domain-expert
|
|
71
|
+
requires:
|
|
72
|
+
knowledge:
|
|
73
|
+
capability: oats.okf
|
|
74
|
+
source: git:github.com/awebai/oats-okf@v2.1.1#oats-package
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
This illustrates software selection, not complete OKF provisioning: the chosen capability also needs its own valid knowledge declaration, bindings and accepted base.
|
|
78
|
+
|
|
79
|
+
- `requires` expresses hard requirements. A fundamental provider can be required by presence or as a concrete capability/source selection.
|
|
80
|
+
- `defaults` supplies choices that remain rebindable within those requirements.
|
|
81
|
+
- Additive capabilities are named under `requires.capabilities` or `defaults.capabilities`; each concrete selection has a `source`, with optional provider-owned settings.
|
|
82
|
+
- `git:` selects versioned software from a repository/package root. `repo:` refers to a contained path in the declaring source repository, not the caller's working directory. `path:` is an explicitly authorised local development choice, not a remotely portable ambient fallback.
|
|
83
|
+
- Capability IDs alone do not establish software origin. An old `from: installed` config entry is not a substitute for a portable source declaration.
|
|
84
|
+
- A source may contain authored knowledge snapshots or resources, but retained artifacts are not writable knowledge stores. Learning locations and procedures belong to the selected capability.
|
|
85
|
+
|
|
86
|
+
See the [soul schema](soul.schema.json) and [declaration contract](design/2026-09-15-portable-declarations.md). Classic fields such as `kind`, `type` and a machine-local `repo` are not portable declaration fields; do not relabel an old file without validating it.
|
|
87
|
+
|
|
88
|
+
## Membership and adoption are different
|
|
89
|
+
|
|
90
|
+
**Repository membership is reciprocal:** the workspace admits the repository and the repository's `oats.yaml` points back to that workspace. Both observations must have compatible identity, access context and revision evidence. A copied backlink, neighbouring folder or URL is not admission.
|
|
91
|
+
|
|
92
|
+
**Source adoption is by reference:** an import identifies `source`, exported `soul` path, `revision` and a local `alias`. It may carry supported adoption choices. Importing does not create an adopter-maintained copy of the soul or automatically follow the publisher's workspace backlink.
|
|
93
|
+
|
|
94
|
+
A team can therefore use a public expert without joining its publisher's organization. One source can serve several workspaces or an explicit standalone context, with different legitimate work targets and knowledge bindings.
|
|
95
|
+
|
|
96
|
+
Publish source/export revisions before pinning imports to them. Do not use invented future SHAs or require two repositories to contain each other's not-yet-created commit IDs.
|
|
97
|
+
|
|
98
|
+
## How requirements and defaults meet
|
|
99
|
+
|
|
100
|
+
The kernel uses one resolver:
|
|
101
|
+
|
|
102
|
+
- Workspace defaults establish shared fallback choices.
|
|
103
|
+
- The soul's own defaults can specialise them.
|
|
104
|
+
- Explicit adoption/operator choices select supported alternatives or supply missing inputs.
|
|
105
|
+
- Hard source requirements remain constraints; a conflicting override is an error, not a reason to discard the requirement.
|
|
106
|
+
|
|
107
|
+
Provider-owned declarations remain opaque to the kernel until the selected provider interprets them through its contract. There is no portable repository-level capability policy tier silently inherited from the publisher, and no mandatory agent-type hierarchy replacing a soul's own requirements.
|
|
108
|
+
|
|
109
|
+
Repository briefing/worktree setup remains work-target behavior with its own supported authority. Merely placing a repository `AGENTS.md` nearby does not guarantee it is composed into every harness's instructions.
|
|
110
|
+
|
|
111
|
+
## From a definition to a running instance
|
|
112
|
+
|
|
113
|
+
1. Select an explicit workspace or standalone context, source reference, deployment location and work target.
|
|
114
|
+
2. Observe actual source identities/revisions and check requested reciprocal membership.
|
|
115
|
+
3. Resolve requirements, defaults and operator inputs; retain the selected source and software closure.
|
|
116
|
+
4. Review and approve exact executable artifacts before provider code runs.
|
|
117
|
+
5. Obtain honest provider readiness and a retained resolution; missing configuration or unsupported behavior remains visible.
|
|
118
|
+
6. Scaffold and start through the supported captured lifecycle. Preserve the exact source/resources and evidence needed for continuation.
|
|
119
|
+
|
|
120
|
+
An existing instance does not silently adopt a new upstream commit, changed workspace default or different curriculum. Updates prepare new choices deliberately; required knowledge refresh and native credential rotation are separate from rewriting its retained software.
|
|
121
|
+
|
|
122
|
+
A successful lookup is not execution, an accepted dispatch is not completed work, and a declared knowledge destination is not accepted learning.
|
|
123
|
+
|
|
124
|
+
## What each operator shares or keeps local
|
|
125
|
+
|
|
126
|
+
Share reviewed definitions, relevant nonsecret configuration/provenance, published source references and accepted knowledge through their chosen Git repositories. Keep credentials, private runtime evidence, instance homes and machine-specific realization local. A messaging roster does not replicate any of these.
|
|
127
|
+
|
|
128
|
+
An adopted package config template is an editable local snapshot, not live inheritance from the package. Updating the kernel or package does not rewrite it, migrate a knowledge base or update a running instance's loaded instructions.
|
|
129
|
+
|
|
130
|
+
## Compatibility and current readiness
|
|
131
|
+
|
|
132
|
+
Classic `oats-config.yaml` scopes, `oats init`, `oats use`, local `agents/` lookup and lock-v2 package restore still have their own supported contracts. They are not renamed portable workspace commands. See [configuration](configuration.md) and [packages](packages.md) for that compatibility surface; do not apply classic lifecycle commands blindly to captured instances.
|
|
133
|
+
|
|
134
|
+
At the documented0.24 baseline, workspace/declaration/retained-execution foundations are shipped. The released `oats.aweb`1.10.3 package lacks the captured provider-binding interface, so its legacy messaging success does not qualify a new captured profile requiring it. Capability adaptation is implementation work, not a YAML setting that can honestly turn readiness green. Follow current [release scope](release-notes/v0.24.0.md) and the provider's actual version/readiness rather than removing requirements.
|
|
135
|
+
|
|
136
|
+
The project's [adoption plan](design/2026-09-20-workspace-and-portable-adoption-plan.md) puts workspace/source adoption first, centralised knowledge and five experts second, and full Desktop parity afterward.
|
|
137
|
+
|
|
138
|
+
## How a soul knows OATS (accepted direction, not yet shipped)
|
|
139
|
+
|
|
140
|
+
An agent's knowledge of OATS itself — how to check status, spawn and retire, find other souls — is ordinary capability content, not kernel magic:
|
|
141
|
+
|
|
142
|
+
- **`oats.core`** carries day-to-day operation (skills `oats-operate`, `oats-souls`, the "you run on OATS" briefing). Every soul gets it **by default at creation, written explicitly into its definition**; you can remove or replace it.
|
|
143
|
+
- **`oats.setup`** carries deployment/workspace configuration and package knowledge ("OATS Soul Setup"). Onboarding a workspace creates and starts an **`oats-setup-expert`** soul with both, which then adopts repositories and creates the team's other souls.
|
|
144
|
+
- The **official marketplace** is the reviewed package list in the `oats` repository; a package becomes official through an approved PR to that list, and official packages are discoverable from the CLI and Desktop. Discoverable is not installed; installed is not approved.
|
|
145
|
+
|
|
146
|
+
At the0.24 baseline these skills still ship inside the kernel. Work packages D1–D4 of the [adoption plan](design/2026-09-20-workspace-and-portable-adoption-plan.md) track the move.
|
|
147
|
+
|
|
148
|
+
## Related references
|
|
149
|
+
|
|
150
|
+
- [Souls and instances](souls-and-instances.md)
|
|
151
|
+
- [Capability contracts](layers.md) and [capability authoring/distribution](capabilities.md)
|
|
152
|
+
- [Knowledge model](knowledge-theory.md) and [version-scoped operations](knowledge.md)
|
|
153
|
+
- [Workspace schema](oats-workspace.schema.json) and [repository export schema](oats-member.schema.json)
|
|
154
|
+
- [Design/contract navigation](design/README.md)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
## You run on a captured OATS composition
|
|
2
|
+
|
|
3
|
+
You are an instance of a retained soul/helper composition selected by
|
|
4
|
+
`instance.json.executionBinding`. Managed instructions, skills, capabilities,
|
|
5
|
+
settings, provider bindings, and executable resources come from that exact
|
|
6
|
+
`deployment` + `resolution`; do not replace them with a current checkout,
|
|
7
|
+
configuration cascade, package lock, similarly named capability, or source path.
|
|
8
|
+
|
|
9
|
+
Load **oats-portable** before invoking or reasoning about captured OATS commands.
|
|
10
|
+
Load **oats-portable-artifacts** for exact retained inspection and approval. Do not load the legacy **oats**,
|
|
11
|
+
**oats-config**, or **oats-packages** procedures to fill a captured input.
|
|
12
|
+
|
|
13
|
+
Captured start/restart use exact retained launch inputs and supported native
|
|
14
|
+
endpoints. Captured wake/retire, unqualified runtime contributions and non-directory
|
|
15
|
+
work remain held. If a command is unsupported or retained authority is missing,
|
|
16
|
+
stop and report it; never remove selectors or fall back to ambient configuration.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
## Captured instance: home, source and work
|
|
2
|
+
|
|
3
|
+
**Your instance home** is the specific OATS instance directory supplied as
|
|
4
|
+
`OATS_INSTANCE_HOME`, not your user home, source repository or work target.
|
|
5
|
+
`instance.json.executionBinding` names the explicit captured **deployment and
|
|
6
|
+
resolution**. Home-bound actions must also match this owned home's incarnation
|
|
7
|
+
and recorded custody. Do not invent, copy or rewrite those identifiers to make
|
|
8
|
+
another home or composition appear authorized.
|
|
9
|
+
|
|
10
|
+
- **Home holds composed instructions and instance state.** `AGENTS.md` is the
|
|
11
|
+
canonical composed instruction file; `CLAUDE.md -> AGENTS.md` is its relative
|
|
12
|
+
compatibility alias, not a second instruction source. Preserve the generated
|
|
13
|
+
instructions, aliases and metadata; do not hand-edit them to change authority.
|
|
14
|
+
Task material and provider-managed state belong where their owning contract
|
|
15
|
+
specifies. The selected capabilities define any knowledge or memory protocol.
|
|
16
|
+
- **`./soul` is a read-only retained source link, not your edit surface.** Reading
|
|
17
|
+
it must not depend on the publisher's current checkout. Never write through it
|
|
18
|
+
or modify retained artifacts. If a task authorizes source changes, use its
|
|
19
|
+
explicitly authorized tracked work surface and review path instead.
|
|
20
|
+
- **`./work` is the task's work surface.** The work-mode instructions determine
|
|
21
|
+
whether it is an owned directory or another permitted repository view. Make
|
|
22
|
+
task edits only on that authorized surface, not in deployment stores or a
|
|
23
|
+
convenient source checkout. Reading an external input is not permission to
|
|
24
|
+
modify it or its owner.
|
|
25
|
+
|
|
26
|
+
For supported captured commands, keep the explicit `--deployment` and
|
|
27
|
+
`--resolution` pair from the recorded binding; supply the exact owned home when
|
|
28
|
+
an action requires one. Running from home preserves the invocation's working
|
|
29
|
+
location, but **cwd and a recorded `repo` path never select configuration or
|
|
30
|
+
execution authority**. Source location, deployment, work target and team
|
|
31
|
+
membership are separate facts. Do not fill missing inputs from a config cascade,
|
|
32
|
+
a current lock, an alias match or another instance's environment.
|
|
33
|
+
|
|
34
|
+
Load **oats-portable** for the running kernel's supported captured operations.
|
|
35
|
+
A no-launch scaffold or `launchPending` receipt is not a running agent. Where
|
|
36
|
+
captured launch, start/restart/wake/retire or recovery is unsupported, stop and
|
|
37
|
+
report the limitation; do not strip selectors or use a legacy command as a
|
|
38
|
+
workaround. Preserve work, knowledge, native history, identities and outstanding
|
|
39
|
+
cleanup receipts. Missing authority is a hold, never permission to erase state.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
## Portable work mode: owned directory
|
|
2
|
+
|
|
3
|
+
Your `./work` is an **instance-owned execution directory**, not a Git worktree,
|
|
4
|
+
a checkout, or a link to the source, deployment or another instance. No Git
|
|
5
|
+
repository or branch is created by this mode. Do not initialize a fake repository
|
|
6
|
+
to satisfy a workflow; a containing Git repository does not grant authority over
|
|
7
|
+
its contents.
|
|
8
|
+
|
|
9
|
+
- Do task work inside `./work`. External inputs and delivery destinations require
|
|
10
|
+
explicit task/capability authorization. Neither a source link nor a recorded
|
|
11
|
+
`repo` or work-target path grants permission to edit that external directory.
|
|
12
|
+
- Execution uses the explicit captured deployment/resolution and, for home-bound
|
|
13
|
+
actions, the matching owned home/incarnation binding. Cwd does not resolve
|
|
14
|
+
configuration or select a provider; do not rebind from a current checkout,
|
|
15
|
+
config cascade, package lock or another instance.
|
|
16
|
+
- Preserve home/work separation and canonical instruction aliases:
|
|
17
|
+
`AGENTS.md` in home, `CLAUDE.md -> AGENTS.md`, and the generated skill aliases.
|
|
18
|
+
The home's `./soul` link and retained software are read-only, not edit surfaces.
|
|
19
|
+
- Deliver results using the task and selected capability's supported protocol.
|
|
20
|
+
This mode imposes no knowledge layout, harvester, storage backend or publication
|
|
21
|
+
policy. A recovery copy, if independently verified, is not publication or
|
|
22
|
+
accepted delivery.
|
|
23
|
+
|
|
24
|
+
Keep nonempty work and its custody evidence intact. This mode does not promise
|
|
25
|
+
implemented captured launch, start/restart/wake/retire or automatic recovery.
|
|
26
|
+
Before any supported, explicitly authorized teardown, require verified
|
|
27
|
+
preservation of outstanding work and receipts; if that capability is unavailable,
|
|
28
|
+
hold and report rather than deleting or moving the home/work yourself. A
|
|
29
|
+
`launchPending` result means runtime launch remains pending.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/** Exact-artifact local approval authority. Presence/catalog/legacy trust and
|
|
2
|
+
* captured booleans never grant approval. No current selection-lock lookup. */
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { canonicalJson, parseStrictJson } from "./portable-values.mjs";
|
|
5
|
+
import { jsonIntegrity } from "./portable-digest.mjs";
|
|
6
|
+
import { objectAt, versionAt } from "./portable-shape.mjs";
|
|
7
|
+
import { validateArtifactRef, validateOrigin } from "./resolution-shape.mjs";
|
|
8
|
+
import { verifyResolutionInputs, verifyRetainedCapability } from "./captured-resolutions.mjs";
|
|
9
|
+
import { verifyPortableArtifact } from "./portable-artifacts.mjs";
|
|
10
|
+
import { readLock3 } from "./portable-lock.mjs";
|
|
11
|
+
import { executableSurfaceOf, hasExecutableSurface } from "./capability-execution.mjs";
|
|
12
|
+
import { isMaterializedCapabilityId } from "./capability-provenance.mjs";
|
|
13
|
+
import { readPortableBytes } from "./portable-files.mjs";
|
|
14
|
+
import { portableStateDirectory, withPortableStateWrite, writeGuardedPortableDocument } from "./portable-state.mjs";
|
|
15
|
+
import { oatsError } from "./errors.mjs";
|
|
16
|
+
|
|
17
|
+
const emptyLedger = () => ({ schemaVersion: 1, capabilities: Object.create(null) });
|
|
18
|
+
const invalid = (message) => { throw oatsError("invalid-approval", message); };
|
|
19
|
+
export function artifactApprovalKey(artifact) {
|
|
20
|
+
validateArtifactRef(artifact);
|
|
21
|
+
if (artifact.kind !== "capability") invalid("capability approval cannot authorize an unrelated resource bundle");
|
|
22
|
+
return `${artifact.integrity.format}:${artifact.integrity.value}`;
|
|
23
|
+
}
|
|
24
|
+
export function validateApprovalLedger(ledger) {
|
|
25
|
+
canonicalJson(ledger);
|
|
26
|
+
objectAt(ledger, ["schemaVersion", "capabilities"], ["schemaVersion", "capabilities"]);
|
|
27
|
+
versionAt(ledger.schemaVersion); objectAt(ledger.capabilities, null, []);
|
|
28
|
+
for (const [id, entries] of Object.entries(ledger.capabilities)) {
|
|
29
|
+
if (!isMaterializedCapabilityId(id)) invalid("invalid approval capability identity");
|
|
30
|
+
objectAt(entries, null, []);
|
|
31
|
+
for (const [key, entry] of Object.entries(entries)) {
|
|
32
|
+
objectAt(entry, ["artifact", "approved", "provenance"], ["artifact", "approved", "provenance"]);
|
|
33
|
+
if (artifactApprovalKey(entry.artifact) !== key || entry.artifact.capability !== id || entry.approved !== true) invalid("approval key, artifact or capability differs");
|
|
34
|
+
if (!Array.isArray(entry.provenance) || !entry.provenance.length) invalid("approval requires explicit operator provenance");
|
|
35
|
+
for (const origin of entry.provenance) {
|
|
36
|
+
validateOrigin(origin);
|
|
37
|
+
if (origin.kind !== "operator" || origin.document.kind !== "operator") invalid("approval cannot inherit source or legacy authority");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return ledger;
|
|
42
|
+
}
|
|
43
|
+
export function readApprovalLedger(scope) {
|
|
44
|
+
const root = portableStateDirectory(scope);
|
|
45
|
+
const bytes = root === null ? null : readPortableBytes(join(root, "approvals.json"), { allowMissing: true, invalidCode: "invalid-approval" });
|
|
46
|
+
if (bytes === null) return { ledger: emptyLedger(), integrity: null };
|
|
47
|
+
const ledger = parseStrictJson(bytes);
|
|
48
|
+
validateApprovalLedger(ledger);
|
|
49
|
+
if (!bytes.equals(Buffer.from(canonicalJson(ledger)))) invalid("approval ledger must use canonical JSON bytes");
|
|
50
|
+
return { ledger, integrity: jsonIntegrity(ledger) };
|
|
51
|
+
}
|
|
52
|
+
function approved(ledger, artifact) {
|
|
53
|
+
const key = artifactApprovalKey(artifact);
|
|
54
|
+
return Object.hasOwn(ledger.capabilities, artifact.capability) && Object.hasOwn(ledger.capabilities[artifact.capability], key);
|
|
55
|
+
}
|
|
56
|
+
function manifestFor(verified, id) {
|
|
57
|
+
return verified.manifests.get(id);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Diagnostic projection for this record's capabilities, not an action permit.
|
|
61
|
+
* Dedicated helper records get their own approval check when used. */
|
|
62
|
+
export function inspectCapturedApprovals(scope, reference) {
|
|
63
|
+
const verified = verifyResolutionInputs(scope, reference), { ledger } = readApprovalLedger(scope);
|
|
64
|
+
return { reference, capabilities: evaluateCapturedApprovals(verified, ledger) };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Shared evaluation over already verified inputs and a freshly read ledger.
|
|
68
|
+
* This remains data; the action loader decides which surfaces the action uses. */
|
|
69
|
+
export function evaluateCapturedApprovals(verified, ledger) {
|
|
70
|
+
validateApprovalLedger(ledger);
|
|
71
|
+
return Object.entries(verified.record.artifacts.capabilities).map(([id, row]) => {
|
|
72
|
+
const manifest = manifestFor(verified, id), required = hasExecutableSurface(manifest);
|
|
73
|
+
return { artifact: row.artifact, required, surface: executableSurfaceOf(manifest),
|
|
74
|
+
status: !required ? "not-required" : approved(ledger, row.artifact) ? "approved" : "approval-required" };
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function grantApproval(context, artifact, manifest, origin) {
|
|
79
|
+
const key = artifactApprovalKey(artifact), id = artifact.capability;
|
|
80
|
+
const { ledger, integrity } = readApprovalLedger(context.deployment);
|
|
81
|
+
if (!hasExecutableSurface(manifest)) return { artifact, status: "not-required" };
|
|
82
|
+
if (approved(ledger, artifact)) return { artifact, status: "already-approved" };
|
|
83
|
+
if (!Object.hasOwn(ledger.capabilities, id)) ledger.capabilities[id] = Object.create(null);
|
|
84
|
+
ledger.capabilities[id][key] = { artifact, approved: true, provenance: [origin] };
|
|
85
|
+
validateApprovalLedger(ledger);
|
|
86
|
+
writeGuardedPortableDocument(context, join(context.root, "approvals.json"), ledger, { absent: integrity === null });
|
|
87
|
+
return { artifact, status: "approved" };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Prospective approval must be possible BEFORE running an executable provider
|
|
91
|
+
* codec to complete a resolution. Address an exact retained artifact set, never
|
|
92
|
+
* today's selected capability ID or a fabricated partial resolution. */
|
|
93
|
+
export function approveAvailableCapability(scope, setKey, id, origin, validateManifest) {
|
|
94
|
+
validateOrigin(origin);
|
|
95
|
+
if (origin.kind !== "operator" || origin.document.kind !== "operator") invalid("approval requires an explicit operator input");
|
|
96
|
+
if (typeof setKey !== "string" || !/^sha256-[a-f0-9]{64}$/.test(setKey) || typeof id !== "string") invalid("invalid artifact-set approval target");
|
|
97
|
+
if (typeof validateManifest !== "function") throw new TypeError("prospective approval requires the complete kernel manifest codec");
|
|
98
|
+
return withPortableStateWrite(scope, (context) => {
|
|
99
|
+
const { lock } = readLock3(context.deployment);
|
|
100
|
+
const set = lock?.artifactSets[setKey];
|
|
101
|
+
if (!set || !Object.hasOwn(set.capabilities, id)) invalid("capability is not in that exact retained artifact set");
|
|
102
|
+
const artifact = set.capabilities[id].artifact;
|
|
103
|
+
const root = verifyPortableArtifact(context.deployment, artifact).dir;
|
|
104
|
+
const manifest = verifyRetainedCapability(root, set, id, validateManifest(root));
|
|
105
|
+
return grantApproval(context, artifact, manifest, origin);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Explicit approval writer. Called by the explicit operator approval operation,
|
|
110
|
+
* not preparation/discovery. Approval still does not qualify provider/host readiness
|
|
111
|
+
* or replace full manifest/launch compilation at the eventual action boundary. */
|
|
112
|
+
export function approveCapturedCapability(scope, reference, id, origin) {
|
|
113
|
+
validateOrigin(origin);
|
|
114
|
+
if (origin.kind !== "operator" || origin.document.kind !== "operator") invalid("approval requires an explicit operator input");
|
|
115
|
+
return withPortableStateWrite(scope, (context) => {
|
|
116
|
+
const verified = verifyResolutionInputs(context.deployment, reference);
|
|
117
|
+
if (typeof id !== "string" || !Object.hasOwn(verified.record.artifacts.capabilities, id)) invalid("approval capability is not selected in this captured record");
|
|
118
|
+
return grantApproval(context, verified.record.artifacts.capabilities[id].artifact, manifestFor(verified, id), origin);
|
|
119
|
+
});
|
|
120
|
+
}
|