@awebai/oats 0.25.9 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/README.md +8 -6
  2. package/bin/oats.mjs +648 -1755
  3. package/capabilities/oats-authoring/oats-package.json +2 -2
  4. package/capabilities/oats-authoring/oats.json +2 -2
  5. package/capabilities/oats-authoring/skills/integration-authoring/SKILL.md +46 -25
  6. package/capabilities/oats-authoring/skills/soul-craft/SKILL.md +13 -6
  7. package/capabilities/oats-aweb/bin/oats-aweb.mjs +279 -93
  8. package/capabilities/oats-aweb/injects/aweb.md +7 -2
  9. package/capabilities/oats-aweb/lib/binding-wire.mjs +89 -13
  10. package/capabilities/oats-aweb/lib/captured-native.mjs +1 -1
  11. package/capabilities/oats-aweb/lib/grant-custody.mjs +38 -0
  12. package/capabilities/oats-aweb/oats.json +8 -4
  13. package/capabilities/oats-jira/bin/oats-jira.mjs +4 -4
  14. package/capabilities/oats-jira/oats.json +2 -2
  15. package/capabilities/oats-jira/skills/jira-tasks/SKILL.md +6 -3
  16. package/capabilities/oats-linear/bin/oats-linear-hook.mjs +6 -4
  17. package/capabilities/oats-linear/oats.json +2 -2
  18. package/capabilities/oats-linear/skills/linear-tasks/SKILL.md +6 -0
  19. package/capabilities/oats-review/oats.json +3 -2
  20. package/docs/capabilities.md +229 -58
  21. package/docs/capability-manifest.schema.json +29 -9
  22. package/docs/configuration.md +17 -5
  23. package/docs/conventions.md +18 -28
  24. package/docs/design/2026-09-08-expert-assisted-deployment-proposal.md +1 -1
  25. package/docs/design/2026-09-13-knowledge-and-memory-direction.md +3 -3
  26. package/docs/design/2026-09-14-portable-souls-and-git-workspaces.md +2 -2
  27. package/docs/design/2026-09-15-portable-souls-handoff.md +2 -2
  28. package/docs/design/2026-09-15-portable-souls-implementation.md +1 -1
  29. package/docs/design/2026-09-20-redesign-program-board.md +2 -2
  30. package/docs/design/2026-09-23-workspace-module-contracts.md +1 -1
  31. package/docs/design/2026-09-23-workspace-v2-implementation-plan.md +1 -1
  32. package/docs/design/2026-09-24-desktop-phase-f-boundary.md +34 -1
  33. package/docs/design/2026-09-24-phase-d-plan.md +57 -0
  34. package/docs/design/2026-09-25-teams-contract.md +226 -0
  35. package/docs/design/README.md +3 -3
  36. package/docs/design/launch-configurations.md +20 -16
  37. package/docs/design/operations-contract.md +27 -10
  38. package/docs/desktop-cli-api.md +604 -271
  39. package/docs/desktop-instance-start.md +3 -3
  40. package/docs/desktop.md +7 -13
  41. package/docs/execution-targets.md +16 -18
  42. package/docs/first-team.md +15 -18
  43. package/docs/implementation.md +31 -62
  44. package/docs/integrations.md +64 -33
  45. package/docs/knowledge-capability-authoring.md +1 -1
  46. package/docs/knowledge-reference/package-craft.md +10 -8
  47. package/docs/knowledge-theory.md +1 -1
  48. package/docs/knowledge.md +10 -11
  49. package/docs/layers.md +16 -17
  50. package/docs/oats-local.schema.json +30 -1
  51. package/docs/oats-membership.schema.json +5 -3
  52. package/docs/oats-package.schema.json +2 -2
  53. package/docs/oats-workspace.schema.json +1 -1
  54. package/docs/{official-marketplace.md → official-catalog.md} +15 -16
  55. package/docs/packages.md +76 -53
  56. package/docs/release-notes/v0.22.0.md +1 -1
  57. package/docs/release-notes/v0.23.1.md +1 -1
  58. package/docs/release-notes/v0.26.0.md +670 -0
  59. package/docs/release-notes/v0.27.0.md +100 -0
  60. package/docs/schedules.md +54 -132
  61. package/docs/servers.md +4 -4
  62. package/docs/soul.schema.json +11 -4
  63. package/docs/souls-and-instances.md +60 -47
  64. package/docs/workspaces.md +80 -58
  65. package/injects/instance-boundary.md +2 -2
  66. package/injects/work-attached.md +1 -1
  67. package/injects/work-workspace.md +2 -2
  68. package/lib/{portable-files.mjs → bounded-read.mjs} +6 -6
  69. package/lib/{portable-values.mjs → canonical-json.mjs} +3 -12
  70. package/lib/capability-contract.mjs +110 -0
  71. package/lib/config-data.mjs +2 -2
  72. package/lib/core.mjs +947 -5023
  73. package/lib/deprecation.mjs +24 -0
  74. package/lib/digest.mjs +12 -0
  75. package/lib/instance-inspect.mjs +397 -0
  76. package/lib/instance-lifecycle.mjs +3 -4
  77. package/lib/instance-resolution.mjs +212 -26
  78. package/lib/instruction-composition.mjs +0 -20
  79. package/lib/materialize.mjs +6 -4
  80. package/lib/operator-dispatch.mjs +33 -13
  81. package/lib/packages.mjs +25 -190
  82. package/lib/process-group.mjs +1 -1
  83. package/lib/provider-binding.mjs +4 -2
  84. package/lib/provider-reasons.mjs +3 -68
  85. package/lib/remote.mjs +1 -1
  86. package/lib/resolve.mjs +204 -68
  87. package/lib/schedule.mjs +136 -292
  88. package/lib/servers.mjs +70 -38
  89. package/lib/{portable-shape.mjs → shape.mjs} +4 -3
  90. package/lib/tree-copy.mjs +44 -0
  91. package/lib/workspace.mjs +132 -20
  92. package/package-catalog.json +6 -6
  93. package/package.json +1 -1
  94. package/packages/record/lib/session-roots.mjs +8 -6
  95. package/skills/integration-authoring/SKILL.md +48 -40
  96. package/skills/oats-getting-started/SKILL.md +105 -110
  97. package/skills/oats-support/SKILL.md +2 -2
  98. package/skills/soul-craft/SKILL.md +13 -6
  99. package/bin/oats-pi-sdk-host.mjs +0 -17
  100. package/docs/2026-09-03-architecture-proposal.md +0 -642
  101. package/docs/artifact-approvals.schema.json +0 -7
  102. package/docs/captured-invocation-context.schema.json +0 -7
  103. package/docs/captured-resolution.schema.json +0 -7
  104. package/docs/design/package-engine-contract.md +0 -813
  105. package/docs/design/package-runtime-api.md +0 -588
  106. package/docs/desktop-succession.md +0 -57
  107. package/docs/execution-capsule.schema.json +0 -108
  108. package/docs/first-team-demo.md +0 -92
  109. package/docs/knowledge-migration.md +0 -147
  110. package/docs/migration-from-oas.md +0 -103
  111. package/docs/oats-config.schema.json +0 -172
  112. package/docs/oats-lock-v3.schema.json +0 -7
  113. package/docs/oats-lock.schema.json +0 -175
  114. package/docs/operating-team-migration.md +0 -470
  115. package/docs/portable.schema.json +0 -2512
  116. package/docs/provider-check-input.schema.json +0 -7
  117. package/docs/rebuild-to-v2.md +0 -511
  118. package/docs/workspace-adoption.md +0 -74
  119. package/injects/framework-workspace.md +0 -7
  120. package/injects/local-soul.md +0 -19
  121. package/injects/oats-portable.md +0 -20
  122. package/injects/oats.md +0 -11
  123. package/injects/portable-instance-boundary.md +0 -39
  124. package/injects/portable-work-directory.md +0 -29
  125. package/lib/artifact-approvals.mjs +0 -120
  126. package/lib/artifact-tree.mjs +0 -141
  127. package/lib/capability-artifacts.mjs +0 -179
  128. package/lib/capability-execution.mjs +0 -15
  129. package/lib/capability-inputs.mjs +0 -39
  130. package/lib/capability-provenance.mjs +0 -231
  131. package/lib/captured-action-shape.mjs +0 -21
  132. package/lib/captured-admission-shape.mjs +0 -20
  133. package/lib/captured-binding-file.mjs +0 -36
  134. package/lib/captured-dispatch.mjs +0 -66
  135. package/lib/captured-instance-index.mjs +0 -277
  136. package/lib/captured-invocation-context.mjs +0 -130
  137. package/lib/captured-launch-request.mjs +0 -66
  138. package/lib/captured-operation-process.mjs +0 -15
  139. package/lib/captured-pi-custody.mjs +0 -29
  140. package/lib/captured-pi-host.mjs +0 -167
  141. package/lib/captured-pi-outcome.mjs +0 -172
  142. package/lib/captured-resolutions.mjs +0 -275
  143. package/lib/captured-scaffold.mjs +0 -87
  144. package/lib/captured-selector.mjs +0 -28
  145. package/lib/captured-session-backend.mjs +0 -52
  146. package/lib/captured-source-receipt-file.mjs +0 -72
  147. package/lib/helper-injection-policy.mjs +0 -104
  148. package/lib/legacy-lock-codec.mjs +0 -106
  149. package/lib/manifest-settings.mjs +0 -84
  150. package/lib/package-closure.mjs +0 -48
  151. package/lib/package-materialization.mjs +0 -83
  152. package/lib/pi-sdk-host.mjs +0 -229
  153. package/lib/portable-artifacts.mjs +0 -115
  154. package/lib/portable-choices.mjs +0 -82
  155. package/lib/portable-composition.mjs +0 -136
  156. package/lib/portable-digest.mjs +0 -105
  157. package/lib/portable-identity.mjs +0 -40
  158. package/lib/portable-lock.mjs +0 -117
  159. package/lib/portable-onboarding-request.mjs +0 -49
  160. package/lib/portable-onboarding.mjs +0 -256
  161. package/lib/portable-package-preparation.mjs +0 -188
  162. package/lib/portable-policy.mjs +0 -44
  163. package/lib/portable-soul.mjs +0 -42
  164. package/lib/portable-state.mjs +0 -80
  165. package/lib/prepare-composition.mjs +0 -170
  166. package/lib/prepared-bindings.mjs +0 -92
  167. package/lib/prepared-resources.mjs +0 -127
  168. package/lib/provider-binding-broker.mjs +0 -65
  169. package/lib/provider-binding-wire.mjs +0 -116
  170. package/lib/readiness.mjs +0 -225
  171. package/lib/repository-observation.mjs +0 -226
  172. package/lib/resolution-shape.mjs +0 -393
  173. package/lib/schedule-capsule.mjs +0 -206
  174. package/lib/soul-constraints.mjs +0 -40
  175. package/lib/source-projection.mjs +0 -84
  176. package/lib/source-spec.mjs +0 -189
  177. package/lib/workspace-definition.mjs +0 -126
  178. package/lib/workspace-discovery.mjs +0 -146
  179. package/skills/oats/SKILL.md +0 -162
  180. package/skills/oats-config/SKILL.md +0 -164
  181. package/skills/oats-packages/SKILL.md +0 -184
  182. package/skills/oats-portable/SKILL.md +0 -115
  183. package/skills/oats-portable-artifacts/SKILL.md +0 -63
@@ -0,0 +1,100 @@
1
+ # OATS 0.27.0
2
+
3
+ What starts an instance (pi, claude or codex) is now called its **harness**
4
+ everywhere the kernel used to say `runtime`: in flags, configuration, records,
5
+ JSON and error codes. Nothing already written stops working. The rule is read
6
+ either, write new: every spelling from before 0.27.0 is still read, and the
7
+ next write records the new one. A command that reads an old spelling answers
8
+ one `deprecated-runtime-name` warning, and a later release drops the old
9
+ spellings. See [Upgrading from 0.26](#upgrading-from-026).
10
+
11
+ ## Changed
12
+
13
+ - **runtime → harness.** [The Desktop CLI API](../desktop-cli-api.md#the-harness-rename-feature-harness-oats-0270)
14
+ has the complete table. In short:
15
+ - Flags: `--harness` replaces `--runtime` on `spawn` (and `--preview`),
16
+ `session start|restart` and `launch-config preview`, including their
17
+ `--server` forms. `--runtime` is still accepted, with the warning. The
18
+ two given with different values are refused (`E_BAD_ARGS`).
19
+ - `oats-local.yaml`: a launch configuration names `harness:`. `runtime:` is
20
+ still read, with the warning. Both, disagreeing, is a schema error
21
+ (`E_WORKSPACE_SCHEMA`). `oats launch-config set` writes `harness`.
22
+ - Schedules: a spawn job names `harness`. A job stored with `runtime` is
23
+ read as `harness`, with the warning, and saved in the new name next time.
24
+ Both, disagreeing, makes that job invalid (`E_SCHEDULE_INVALID`).
25
+ `lastRun`/`recentRuns` record `startedHarness` (was `startedRuntime`).
26
+ - Homes: `instance.json` records `harness`, and the launch recipe is version
27
+ **2** (`harness`; version 1 said `runtime`). A home spawned by 0.26.0 is
28
+ read in the new names, with the warning naming the home. It inspects,
29
+ starts, restarts and retires as before, and its next start or restart
30
+ records the new names.
31
+ - `soul.yaml` names `harness:`. `runtime:` is still read, **without** a
32
+ warning, because released capabilities ship it (oats.aweb 1.13.1's agents)
33
+ and an operator cannot fix a provider's file. Both, disagreeing:
34
+ `E_BAD_MANIFEST`. The same holds for a capability manifest's
35
+ `requires[]` harness package (`harness`, or `runtime`, never both).
36
+ - Hooks get `OATS_HARNESS` and `OATS_PREVIOUS_HARNESS` beside
37
+ `OATS_RUNTIME` and `OATS_PREVIOUS_RUNTIME`, with the same values.
38
+ - JSON outputs speak only the new names:
39
+ - `oats version --json` lists `harnesses` (no `runtimes`) and the feature
40
+ `harness`;
41
+ - `harness` replaces `runtime` in the status, inspect, spawn, preview,
42
+ session, launch-config, schedule and event documents;
43
+ - `harnessPackages` and `harnessPosture` replace `runtimePackages` and
44
+ `runtimePosture` in `composition.materialized`;
45
+ - the launch plan's package check (`launch-config preview` `problems[]`)
46
+ is `harness-packages`, and package verification's `loadedBy` is
47
+ `harness-discovery`.
48
+ - Error codes: `E_UNSUPPORTED_HARNESS`, `E_HARNESS_PACKAGE` and
49
+ `E_HARNESS_RESOURCE_MISSING` replace `E_UNSUPPORTED_RUNTIME`,
50
+ `E_RUNTIME_PACKAGE` and `E_RUNTIME_RESOURCE_MISSING`.
51
+ - JSON envelopes may carry `warnings: [...]`, only when there is something
52
+ to say. `oats status --json` carries it beside `problems`. In text mode,
53
+ a warning is one `oats: warning: …` line on stderr.
54
+ - Routed commands (`--server`) speak each host's own vocabulary. A host
55
+ without the `harness` feature (0.26.x and older) is sent `--runtime` and
56
+ `runtime` keys, and its `runtimes` list and `runtime` roster rows are read
57
+ as harnesses.
58
+ - A spawn decision previewed by a 0.26 kernel is `E_DECISION_STALE` at a
59
+ 0.27 apply (the revision covers the key names), with the fresh decision
60
+ attached.
61
+ - Unchanged, because they do not name the harness: the session endpoint's
62
+ `runtimeAuthority`, `runtimeState` and `runtimeError`, the
63
+ `E_RUNTIME_ENDPOINT_*`, `E_RUNTIME_AUTHORITY_MISMATCH` and
64
+ `E_RUNTIME_QUIESCE_FAILED` codes, `capabilityRuntime`, the retirement
65
+ baseline, and oats.okf's `harvest-runtime` setting.
66
+
67
+ ## Desktop
68
+
69
+ - **The Desktop speaks the harness names** on a kernel that declares feature
70
+ `harness` (`--harness`, `harness`/`harnesses`), and the old names on released
71
+ 0.25.8–0.26.x kernels. It reads either spelling everywhere, shows only the
72
+ harness the kernel reports (no `pi` default for an instance that doesn't say),
73
+ and accepts kernels `>=0.25.8 <0.28.0`.
74
+ - **Core capabilities name their origin** (soul, workspace or team) on the soul
75
+ page and the instance sidebar, on a kernel with feature `layers-from`.
76
+ - The unused "the workspace's team settings" origin label is gone (0.26.0's
77
+ teams amendment K stopped emitting it).
78
+
79
+ ## Fixed
80
+
81
+ - **0.26.0's notes said per-workspace personal teams need undeployed aweb
82
+ server support.** The aweb service (0.8.13 and later) and CLI (1.36.8 and
83
+ later) already carry personal enrollment; what remains is oats.aweb 1.15
84
+ adopting it. The bundled oats.aweb is still 1.13.1 (the personal team only);
85
+ the team verbs come with oats.aweb 1.14.1 in a 0.27.x patch.
86
+
87
+ ## Upgrading from 0.26
88
+
89
+ Nothing to do. Old spellings keep working with a `deprecated-runtime-name`
90
+ warning, and a later release drops them. To stop the warning:
91
+
92
+ - write `harness:` for `runtime:` in `oats-local.yaml` launch configurations
93
+ (or re-save them with `oats launch-config set`);
94
+ - pass `--harness` for `--runtime` in scripts;
95
+ - re-save any schedule the warning names (`oats schedule update`). A stored
96
+ job is also rewritten on its next save.
97
+
98
+ A 0.26.0 home stops warning after its next start or restart. A Desktop that
99
+ gates on the `harness` feature reads the new names; an older Desktop reads
100
+ `runtimes` and `runtime` and needs its update.
package/docs/schedules.md CHANGED
@@ -3,16 +3,12 @@
3
3
  A schedule launches an agent, runs an oats command, or wakes an existing
4
4
  instance on a cron. Definitions belong to a scope and are committable; every
5
5
  `oats schedule` command run anywhere inside that scope, including from an
6
- instance home, reads and writes the same file. On a **workspace deployment**
7
- (0.25, [workspaces.md](workspaces.md)) the scope is the deployment directory
8
- — the one holding `oats-local.yaml` and the `agents/` root (the kernel derives
9
- it as the directory above the agents root; a leftover `oats-config.yaml` that
10
- declares `team:` would still win, so remove it); scheduled spawns there
11
- materialize exactly like `oats spawn`. On a classic 0.24 deployment the scope
12
- is the team workspace (the config level that declares the team, else the
13
- outermost `oats-config.yaml` level). Execution belongs to the host that holds
14
- the scope, so a schedule on a registered server keeps running while your laptop
15
- sleeps.
6
+ instance home, reads and writes the same file. The scope is the deployment
7
+ directory ([workspaces.md](workspaces.md)) — the one holding `oats-local.yaml`
8
+ and the `agents/` root, found walking up; with none in reach, `oats schedule`
9
+ is `E_LOCAL_MISSING`. Scheduled spawns materialize exactly like `oats spawn`.
10
+ Execution belongs to the host that holds the scope, so a schedule on a
11
+ registered server keeps running while your laptop sleeps.
16
12
 
17
13
  There is no daemon. One host timer (a launchd user agent on macOS, a systemd
18
14
  user timer on Linux) runs `oats schedule tick --host` once a minute; the tick
@@ -25,15 +21,9 @@ and no queue.
25
21
  ## Files
26
22
 
27
23
  - `<workspace>/oats-schedules.json` — the definitions (`{version: 1|2, jobs:
28
- {<id>: ...}}`). Version 1 is the legacy format. Adding the first explicit
29
- version-2 execution upgrades the whole document to version 2 so an older
30
- scheduler refuses it instead of ignoring capture policy. Existing legacy
31
- entries may remain visibly unmigrated; new entries in a v2 file must declare
32
- their policy. Commit the file if you want the schedule shared with the team.
33
- Automatic wake creation uses this same document-version gate. Remote captured
34
- mutations require advertised numeric schedule API 2 before forwarding; the old
35
- feature-only gate is insufficient. Unclassifiable remote spec files also require
36
- API 2. Legacy inline specs/read operations remain compatible with older hosts.
24
+ {<id>: ...}}`). A new file is version 1. A version-2 file (written by 0.24–0.25
25
+ for captured definitions) is still read; it is never rewritten to version 1.
26
+ Commit the file if you want the schedule shared with the team.
37
27
  - `<workspace>/.agents/schedules/state.json` — last attempted minute and
38
28
  last run per job (gitignored), plus one lock directory per running job.
39
29
  - `~/.oats/schedules/registry.json` — the host registry: which scopes the
@@ -43,19 +33,21 @@ and no queue.
43
33
  with the directory to remove, and the holder removes its own lock on exit
44
34
  and on SIGINT/SIGTERM. Definition edits take a short per-scope lock.
45
35
 
46
- The existing Desktop adapter can inspect/manage supported API-2 schedules, but its
47
- legacy editor refuses captured policy fields rather than dropping them. Full captured
48
- editing UI remains later Desktop work; use the explicit CLI for those definitions.
36
+ Captured (versioned) definitions are refused (the captured/portable path was removed in 0.26):
37
+ see [Captured definitions](#captured-definitions-removed-in-026).
49
38
 
50
39
  ## Kinds
51
40
 
52
41
  - **spawn** `{id, enabled, cron, tz, kind: "spawn", agent, agentsRoot?,
53
- repo?, backend?, purpose?, task, runtime?, model?, yolo?, wake?}` — every
42
+ repo?, backend?, purpose?, task, harness?, model?, yolo?, wake?}` — every
54
43
  due minute launches one disposable instance of `agent` with the same
55
44
  options `oats spawn` takes. `agentsRoot` names the exact agents root that
56
45
  holds the soul (it must lie inside the workspace and defaults to the
57
46
  workspace's own root); it is what tells same-named souls in different
58
- member repositories apart. `repo` is the work repository, as `--repo`. The task gets a trailing schedule block naming the job and the
47
+ member repositories apart. `repo` is the work repository, as `--repo`.
48
+ Each run is named `<agent>-<purpose or id>-<YYYYMMDDHHMM>`. Instance names
49
+ are at most 64 characters, so a definition whose run names would be longer
50
+ is refused when it is saved (`E_SCHEDULE_INVALID`, field `purpose` or `id`). The task gets a trailing schedule block naming the job and the
59
51
  minute and ending with `oats retire --self`. An optional `wake` object
60
52
  (`{cron, tz, message}`) attaches a wake schedule to each launched instance;
61
53
  nothing is attached unless you ask.
@@ -66,8 +58,8 @@ editing UI remains later Desktop work; use the explicit CLI for those definition
66
58
  from durable context; the job follows that worker until its home is gone.
67
59
  Command return is not task completion. Avoid binding durable work to a
68
60
  disposable source-home cwd; see [OKF v2 source jobs](#okf-v2-source-jobs).
69
- New exact-record command definitions use the fields described in
70
- [Captured execution and recurrence](#captured-execution-and-recurrence).
61
+ An argv carrying a captured selector (`--deployment`, `--resolution`,
62
+ `--artifact-set`) is refused when saved (`E_SCHEDULE_INVALID`, field `argv`).
71
63
  - **wake** `{id, enabled, cron, tz, kind: "wake", home, message}` — every
72
64
  due minute inspects the instance at `home` through its session receipts.
73
65
  Running: `message` is delivered once with `session input`. Not running
@@ -97,87 +89,28 @@ required IANA zone; both are evaluated by the croner library. `--wake-every
97
89
  N` at spawn time means `*/N * * * *`: every 7 fires at :00, :07, ... :56 and
98
90
  then :00 again, so 1, 5, 10, 15 and 30 give an even cadence.
99
91
 
100
- ## Captured execution and recurrence
101
-
102
- A new captured command definition is explicitly versioned and chooses its
103
- recurrence policy. Its containing schedule document is version 2:
104
-
105
- ```json
106
- {
107
- "id": "retained-job",
108
- "definitionVersion": 2,
109
- "recurrencePolicy": "capture",
110
- "kind": "command",
111
- "cwd": "/absolute/workspace",
112
- "argv": [
113
- "oats", "example-action", "run",
114
- "--deployment", "/absolute/deployment",
115
- "--resolution", "sha256-...",
116
- "--", "--provider-argument", "--json"
117
- ],
118
- "responsibleHuman": null,
119
- "cron": "0 * * * *",
120
- "tz": "UTC"
121
- }
122
- ```
123
-
124
- The admitted-attempt wire is published as
125
- [`execution-capsule.schema.json`](execution-capsule.schema.json). Runtime
126
- validation checks selector/target agreement. A canonical `oats.json.v1` digest
127
- of all fields except `executionId` is the separate content witness;
128
- `executionId` itself is opaque admission identity.
129
-
130
- `capture` requires the explicit deployment/resolution selector pair and
131
- `--json` in the **saved argv**. The scheduler never appends an unrecorded
132
- protocol argument to a captured target. Adding or updating the definition
133
- derives an immutable `execution` template containing that exact target,
134
- resolution, input references and explicitly supplied responsible-human value.
135
- It contains no execution ID; `executionStatus.contentIntegrity` exposes its
136
- canonical content witness. At each due tick the
137
- scheduler verifies the retained action first, then mints a fresh opaque
138
- `executionId`, writes the resulting capsule into the attempt before reserving a
139
- slot, and only then invokes the CLI. Thus two attempts with identical content
140
- have the same capsule digest but remain different intents. Definition edits
141
- affect later admissions only; an unknown attempt, `run`, or reconciliation never
142
- replaces its capsule with the edited definition or today's config/lock. Captured
143
- attempts carry their own `schemaVersion:1`; their launch-slot lock names the same
144
- `executionId`. A mismatching lock or malformed/unknown attempt version stays
145
- unresolved and cannot dispatch. Scheduler launch also scrubs ambient
146
- `OATS_DEPLOYMENT` and `OATS_RESOLUTION`; only the saved argv is authority.
147
-
148
- `prepare-on-tick` is a distinct explicit policy for a genuinely new command
149
- tick. Its `preparation` object maps directly to the generic
150
- `prepareCapturedComposition({deployment,source,workspace?,member?,operator?,mode?})`
151
- input; scheduler code does not parse source/workspace policy itself. Production
152
- uses the core adapter and tests may inject the same contract. Direct-source and
153
- workspace-alias requests are supported; `mode` is a work-mode string, not a nested
154
- launch object. A complete result must preserve the requested deployment and
155
- returned resolution, and contain `executionBinding` and an explicit
156
- `responsibleHuman` (`null` means messaging was actually disabled). The scheduler
157
- then inserts the exact selector pair before `--`, verifies the captured action,
158
- mints and persists the attempt, and dispatches. Missing adapters and incomplete
159
- results return typed `migration-required`/`needs-configuration` with no attempt.
160
- A dry run never invokes preparation or mints intent. There is no current-context
161
- fallback. Captured spawn and
162
- operation definitions remain unavailable until their public captured consumer
163
- adapters exist. A captured wake definition is accepted only when its target
164
- `instance.json` has an exact `executionBinding`; the binding is copied into the
165
- execution template and checked again at admission without consulting source or
166
- configuration. Actual captured wake delivery/start remains blocked with
167
- `migration-required` until the parent-owned lifecycle consumer lands. Legacy
168
- wakes continue through the old lifecycle boundary in this release.
169
-
170
- Definitions without `definitionVersion`/`recurrencePolicy` are legacy v1
171
- definitions. They retain the old release behavior during migration and are not
172
- reported as captured execution. `list`/`show` report their `executionStatus` as
173
- `{kind:"legacy",capture:"unknown",migrationRequired:true}`. A captured definition
174
- reports only `capture:"recorded"` until action admission verifies the retained
175
- record and current exact approval; it does not claim launch readiness. While an
176
- attempt is unresolved or its confirmed launched work still holds a slot,
177
- `executionStatus.intent` separately reports captured, legacy-unknown or invalid
178
- authority, so editing a future definition cannot hide an older admitted capsule.
179
- Partial, malformed or unsupported versioned
180
- definitions/attempts are invalid or blocked, never reinterpreted as legacy.
92
+ ## Captured definitions (removed in 0.26)
93
+
94
+ 0.24–0.25 could save captured command definitions: `definitionVersion`,
95
+ `recurrencePolicy` (`capture` or `prepare-on-tick`), an `execution` template and a
96
+ `preparation` request, run against a captured deployment/resolution. That path
97
+ was removed in 0.26:
98
+
99
+ - `add` and `update` refuse any of those four keys (`E_SCHEDULE_INVALID`, the
100
+ key as `field`), locally and, with `--server`, before anything is forwarded.
101
+ - A stored captured definition is invalid on its own job: every tick reports it
102
+ (`invalid`, "captured schedules are refused (the captured/portable path was removed in 0.26) …") and never runs it;
103
+ the rest of the scope's jobs continue. `list`/`show` report its
104
+ `executionStatus` as `{kind:"invalid", …, reason}`.
105
+ - A captured attempt or job lock left mid-run by 0.25 is reported on that job
106
+ (`executionStatus.intent`, `reconcile` refuses with `E_SCHEDULE_INVALID`) and is
107
+ never run, adopted or released. A held captured lock keeps its launch slot
108
+ until the job is gone: remove it with `oats schedule remove --force <id>`, or
109
+ re-add it without the captured keys.
110
+
111
+ Every other definition is a plain one; `list`/`show` report its `executionStatus`
112
+ as `{kind:"legacy",capture:"unknown",migrationRequired:true}` (a released wire,
113
+ kept as it was).
181
114
 
182
115
  ## Commands
183
116
 
@@ -202,27 +135,23 @@ running}], scheduler: {installed, active, lastTick, maxConcurrent, ...}}`.
202
135
 
203
136
  ## What a run reports
204
137
 
205
- `launched` (spawn or command returned), `blocked` (versioned execution
206
- admission refused before a launch slot or child process), `active` (the instance is running;
207
- a home whose retirement is pending still counts, its runtime may be alive),
138
+ `launched` (spawn or command returned), `active` (the instance is running;
139
+ a home whose retirement is pending still counts, its harness may be alive),
208
140
  `ended` (its home is gone), `stopped` (home present, nothing running: needs
209
141
  attention, never removed for you), `launch-failed`, `unknown`, and for wake
210
142
  jobs `delivered`, `started` or `skipped`. The kernel never claims a task
211
143
  succeeded.
212
144
 
213
- `blocked` includes an unavailable exact record/approval or incomplete new-work
214
- preparation, including not-yet-qualified provider bindings. The result preserves the typed
215
- `errorCode`; no attempt capsule or launch lock is created.
145
+ A run recorded by 0.24–0.25 may also read `blocked` (a captured admission that
146
+ refused before a launch slot); 0.26 never produces it.
216
147
 
217
148
  `unknown` means the launch's side effects are unconfirmed: a command timed
218
149
  out or answered no envelope, an envelope named an instance the roster
219
150
  cannot place, or an attempt was never recorded. The job keeps its slot and
220
151
  is skipped until `oats schedule reconcile <id>`. Reconcile adopts only an
221
- attributable receipt: a legacy spawn job's instance is named deterministically
222
- for its minute. A captured command requires the SAME admitted execution ID and
223
- content witness, plus its explicitly recorded home and matching instance metadata;
224
- current-config roster lookup or a previous attempt's name cannot establish it.
225
- Nothing is inferred from file times. Observation validates custody before releasing
152
+ attributable receipt: a spawn job's instance is named deterministically for its
153
+ minute; a command job's, only the instance its answer named. Nothing is inferred
154
+ from file times. Observation validates custody before releasing
226
155
  slots, and unresolved attempts remain held even in the crash gap before a lock
227
156
  exists. Ordinary removal refuses those attempts; force-forget remains explicit. A command whose answer named nothing stays
228
157
  unknown; check the roster and the host by hand, then
@@ -230,13 +159,13 @@ unknown; check the roster and the host by hand, then
230
159
  slot (or `remove --force` forgets the job).
231
160
 
232
161
  A wake job that starts a stopped home holds a launch slot while that
233
- runtime is starting, active, retiring or unobservable, and releases it when
234
- the runtime is proven stopped (the session start receipt's exit marker for
162
+ harness is starting, active, retiring or unobservable, and releases it when
163
+ the harness is proven stopped (the session start receipt's exit marker for
235
164
  that launch, or a home that no longer has a session) or the home is gone.
236
165
  A persistent home that outlives its process does not keep a slot. Delivering
237
166
  a message to a home that is already running takes no slot. The host tick
238
167
  observes every registered scope first, then admits due jobs in one
239
- host-wide order, least recently launched first (only an actual runtime
168
+ host-wide order, least recently launched first (only an actual harness
240
169
  launch counts; a skipped or pending job keeps its place at the front), so
241
170
  one frequent job in one scope cannot keep the only slot forever. An invalid
242
171
  or malformed definition is reported on that job and the rest of the tick
@@ -244,12 +173,11 @@ continues.
244
173
 
245
174
  `disable` never stops anything. `update` never touches a running instance,
246
175
  and while a job holds a slot or has an unresolved attempt its complete
247
- execution identity (including a versioned capsule), kind and target cannot
248
- change; cron, tz and enabled can. Legacy definitions retain their narrower
249
- compatibility behavior until migrated. A cold wake persists its slot before
176
+ execution identity, kind and target cannot
177
+ change; cron, tz and enabled can. A cold wake persists its slot before
250
178
  the session start runs and keeps it on any start exception, whatever its code
251
179
  (the kernel can refuse while recording, after the session exists); the next
252
- observation releases it once the runtime is proven stopped or absent, one tick
180
+ observation releases it once the harness is proven stopped or absent, one tick
253
181
  at worst.
254
182
  `remove` refuses while the job's instance is still tracked (`--force`
255
183
  forgets the job without stopping anything). Retiring an instance removes the
@@ -262,13 +190,7 @@ listed with its skipped reason.
262
190
  saves a wake job `wake-<instance>` bound to the new home after the spawn
263
191
  succeeded. If the spawn succeeds but the save fails, the spawn result still
264
192
  carries the full instance receipt, plus `wakeScheduleError` and a warning;
265
- the instance is neither hidden nor spawned again. When the spawning consumer
266
- supplies both the returned `executionBinding` and `responsibleHuman`,
267
- `saveWakeForHome` creates a version-2 captured wake from the matching binding in
268
- the new home. Supplying only one, or a result binding that differs from the
269
- home, refuses. The current parent-owned spawn caller still needs to pass these
270
- fields when its captured lifecycle path lands; omission retains explicit legacy
271
- behavior rather than inventing a binding.
193
+ the instance is neither hidden nor spawned again.
272
194
 
273
195
  ## OKF v2 source jobs
274
196
 
package/docs/servers.md CHANGED
@@ -25,8 +25,8 @@ oats server list
25
25
  - `--path` names directories to prepend to the remote PATH for every routed
26
26
  command (`~/.local/bin:/opt/pi/bin`). A non-interactive ssh command runs in
27
27
  the login shell's minimal PATH, and the remote kernel's spawn preflight looks
28
- for the runtime binary (`claude`, `pi`, `codex`) there; without this, a
29
- runtime installed under the user's home is "not found" even though it runs
28
+ for the harness binary (`claude`, `pi`, `codex`) there; without this, a
29
+ harness installed under the user's home is "not found" even though it runs
30
30
  fine in an interactive shell on that host.
31
31
  - Registrations live in `~/.oats/servers.json` on this machine, never in a
32
32
  repository scope.
@@ -44,13 +44,13 @@ worktree, identity, launch, retirement. The local side only routes: a local
44
44
  `--task-file` travels as text, every argument is quoted for the remote login
45
45
  shell, and the remote's version and envelope are checked before either
46
46
  mutation (spawn and retire). A spawn is also held to what the remote
47
- advertises: a runtime it does not list (including the soul's own default as
47
+ advertises: a harness it does not list (including the soul's own default as
48
48
  the remote roster reports it), a session backend it lacks, or a launch option
49
49
  such as `--yolo` it does not know is refused with `E_REMOTE_INCOMPATIBLE`
50
50
  saying what was established. A remote that advertises nothing (any kernel
51
51
  before 0.22.2) is assumed to run pi and claude on tmux with no options, and
52
52
  the refusal says so rather than claiming the remote lacks the feature; a soul
53
- the remote roster does not list with a runtime is validated by the remote
53
+ the remote roster does not list with a harness is validated by the remote
54
54
  kernel itself at spawn. `--dir` and `--server` do not combine; the remote
55
55
  workspace comes from the registration.
56
56
 
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://oats.dev/schemas/soul-v2.json",
4
4
  "title": "Soul declaration v2 (soul.yaml)",
5
- "description": "Authored shape only. A soul names each capability WITH WHERE IT COMES FROM (`from: here | <repo key> | package`) — a location, never a version. Provider payloads (knowledge, messaging, tasks) are opaque to the kernel; `none` empties the slot. Membership, privacy and team semantics are enforced by discovery/resolution, not here.",
5
+ "description": "Authored shape only. A soul names each capability WITH WHERE IT COMES FROM (`from: here | <repo key> | package`) — a location, never a version. Core-capability payloads (knowledge, messaging, tasks) are opaque to the kernel; `none` empties the slot. Membership, privacy and team semantics are enforced by discovery/resolution, not here.",
6
6
  "type": "object",
7
7
  "required": ["schemaVersion", "name", "description", "work"],
8
8
  "additionalProperties": false,
@@ -11,8 +11,9 @@
11
11
  "name": { "$ref": "#/$defs/slug" },
12
12
  "description": { "type": "string" },
13
13
  "work": { "enum": ["worktree", "checkout", "directory", "workspace"] },
14
- "team": { "$ref": "#/$defs/label", "description": "Team label; overrides the repo's default from oats-membership.yaml." },
15
- "private": { "type": "boolean", "description": "true → not discoverable in the workspace; usable only from its own repo." },
14
+ "team": { "$ref": "#/$defs/teamLabels", "description": "Team label, or a non-empty list of distinct labels (the first is the primary); overrides the repo's default from oats-membership.yaml. Each label's messaging payload reaches the provider as an eligible team (OATS_TEAMS); joining is the provider's explicit act." },
15
+ "private": { "type": "boolean", "deprecated": true,
16
+ "description": "Ignored since 0.26.0: souls have no private mode. Every soul of a confirmed member is listed and spawnable; discovery warns soul-private-ignored. Accepted so existing files still validate; remove it." },
16
17
  "capabilities": {
17
18
  "type": "object",
18
19
  "propertyNames": { "$ref": "#/$defs/capabilityName" },
@@ -31,6 +32,12 @@
31
32
  "$defs": {
32
33
  "slug": { "type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$" },
33
34
  "label": { "type": "string", "pattern": "^[a-z0-9][a-z0-9._-]*$" },
35
+ "teamLabels": {
36
+ "anyOf": [
37
+ { "$ref": "#/$defs/label" },
38
+ { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/label" } }
39
+ ]
40
+ },
34
41
  "capabilityName": { "type": "string", "pattern": "^[a-z0-9][a-z0-9._-]*$" },
35
42
  "repoKey": { "type": "string", "pattern": "^[^\\s@/][^\\s@]*/[^\\s@]+$" },
36
43
  "fromLocation": {
@@ -49,7 +56,7 @@
49
56
  "capabilityChoice": { "anyOf": [{ "$ref": "#/$defs/capabilityRef" }, { "const": "off" }] },
50
57
  "slotPayload": {
51
58
  "anyOf": [{ "const": "none" }, { "type": "object" }],
52
- "description": "Opaque provider payload, or `none` to leave the slot empty."
59
+ "description": "Opaque payload for the slot's core capability, or `none` to leave the slot empty."
53
60
  }
54
61
  }
55
62
  }