@awebai/oats 0.39.4 → 0.40.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.
@@ -33,13 +33,13 @@ canonical (`github.com/<org>/<repo>`, or `local/<abs-path>`). Examples use
33
33
  "harnesses":["pi","claude","codex"],"sessionBackends":["tmux"],"launchOptions":["yolo"],
34
34
  "remote":["spawn","retire","status","session","session-start","session-restart","launch-config","roster","harvest","schedule","session-upload","operations",
35
35
  "readiness","instance-events","instance-git","lifecycle-plans"],
36
- "features":["retire-home","session-start","session-restart","launch-config","schedule","session-upload","operations","instance-git",
36
+ "features":["retire-home","session-start","session-restart","launch-config","schedule","schedule-host-caps","session-upload","operations","instance-git",
37
37
  "instance-git-remote","souls-declarations","lifecycle-plans","retire-retention","readiness","spawn-preview","instance-events",
38
38
  "instance-events-2","schedule-history","schedule-read-2","spawn-preview-2","spawn-idempotency","spawn-idempotency-2","spawn-apply-2",
39
39
  "workspace-v2","instance-modules","spawn-provider-payload","served-identity","packages-no-approval","spawn-name","settings-origins",
40
40
  "team-model-3","settings-declared","capabilities-private","layers-from","harness","package-souls","triggers","automations","desktop-facts","launch-preference",
41
41
  "preview-composed-from","observe-max-age","spawn-preview-max-age","capability-show","capture-file","workspace-identity",
42
- "server-connect","capability-route","servers-per-workspace","operator-default-soul"],
42
+ "server-connect","capability-route","servers-per-workspace","operator-default-soul","waiting-on-you"],
43
43
  "automationsApi":1,"workspaceApi":2,"instanceGitApi":1,"spawnApplyApi":1,"soulsApi":2,"lifecycleApi":1,
44
44
  "readinessApi":2,"spawnPreviewApi":2,"eventsApi":2,"scheduleHistoryApi":3,"scheduleApi":2,"operationsApi":2,
45
45
  "capabilityShowApi":1}
@@ -68,6 +68,7 @@ canonical (`github.com/<org>/<repo>`, or `local/<abs-path>`). Examples use
68
68
  | `session-start`, `session-restart` | `oats session start/restart --home` | |
69
69
  | `launch-config` | `oats launch-config …`; the selection flags on start and restart | |
70
70
  | `schedule` | `oats schedule …` | `scheduleApi: 2` |
71
+ | `schedule-host-caps` | both host-install cap options, their `default` / `none` reset semantics, and cap status reporting; no promise about a particular stored cap value | |
71
72
  | `session-upload` | `oats session upload` (and the host's `session receive`) | |
72
73
  | `operations` | `oats operation run`; `operations[]` in inspect | `operationsApi: 2` |
73
74
  | `instance-git`, `instance-git-remote` | `oats instance git/diff`; the observation's `remote` | `instanceGitApi: 1` |
@@ -106,6 +107,7 @@ canonical (`github.com/<org>/<repo>`, or `local/<abs-path>`). Examples use
106
107
  | `server-connect` | `oats server connect`; `oats onboard --check`; `workspaceReadable` on `oats server check --json`, OATS 0.39.0 ([`oats server connect`](#oats-server-connect)) | |
107
108
  | `capability-route` | `oats <namespace> <command> … --server <id>` runs the capability command on the server, OATS 0.39.0 ([Capability commands on a server](#capability-commands-on-a-server)) | |
108
109
  | `operator-default-soul` | a capability command from a deployment without `--soul` runs as the first soul that provides its namespace (named on stderr); none is `E_BAD_ARGS`, OATS 0.39.0 ([capabilities.md](capabilities.md)) | |
110
+ | `waiting-on-you` | the `waiting` event kind and the session boundary rule; `oats instance waiting` and `oats instance attention`; `waitingOnYou` (with `message`) on `oats status --json` instance rows, on `oats session inspect --json` and in the events read, OATS 0.40.0 ([Waiting on you](#waiting-on-you)) | `eventsApi: 2` |
109
111
 
110
112
  Payload-only integers, never in the probe: `onboardApi: 2`, `syncApi: 1`,
111
113
  `workspaceStatusApi: 1`, `capabilitiesApi: 1`, the `oats souls` document's
@@ -148,7 +150,9 @@ stdout (progress goes to stderr):
148
150
  A kernel command reads `--flag=value` exactly as `--flag value` (the value is
149
151
  everything after the first `=`). `E_BAD_ARGS` for an empty `--flag=`, a value
150
152
  on a switch (`--yolo=false` never turns yolo on) and a value that is itself an
151
- option (`--model=--yolo`). A capability command's own flags are forwarded as
153
+ option (`--model=--yolo`). The one exception is the free-text `--message`
154
+ (`oats instance waiting`, `oats instance attention`): `--message=--text` is
155
+ accepted, and its value is only ever the message. A capability command's own flags are forwarded as
152
156
  typed; the kernel reads only its dispatch flag (`--soul`). There is no feature
153
157
  string for this: to support older kernels, use the spaced form.
154
158
 
@@ -1787,6 +1791,16 @@ Not an envelope: `{root, agents, observation?, workspace?, problems?, warnings?}
1787
1791
  in the row),
1788
1792
  `identity` when a provider recorded one, `rollbackIncomplete` and
1789
1793
  `retirePending` when present, and the Desktop facts below.
1794
+ - **`waitingOnYou`** (feature `waiting-on-you`): `{since, producer, reason,
1795
+ message}` when the row is `running: true` and a producer holds a live claim
1796
+ that the instance needs input from a human, else `null` (unknown, not "not
1797
+ waiting"). Its rules are the events read's ([Waiting on you](#waiting-on-you)):
1798
+ one bounded read of the home's log per running row. A remote roster row
1799
+ carries what the remote kernel reports; an older kernel omits the field.
1800
+ `running` is the window's presence, which a crashed harness's fallback
1801
+ shell or a retained dead pane keeps, so a row with a claim is checked
1802
+ against its session (as `oats session inspect` observes it) and reads
1803
+ `null` unless a harness runs there.
1790
1804
  - **`modules`** becomes drift rows `{name, from, commit, current, status,
1791
1805
  reason?}` when the workspace was read. `status` is `current`, `moved` or
1792
1806
  `missing` (`reason`: `capability-absent`, `package-absent`, or the member's
@@ -2153,27 +2167,134 @@ oats instance events <instance> [--limit <n>] [--since <iso>] [--home <abs>] [--
2153
2167
  `retire-planned`, `retired`, `worktree-retained`, `worktree-removed`,
2154
2168
  `branch-deleted`, `child-spawn-refused`, `launch-warning` (0.30: a
2155
2169
  `launch` hook's warning at session start/restart, `data: {message}`),
2156
- `recomposed` (from earlier kernels). `producer` is `kernel` or a capability id. Older rows may carry
2157
- `eventsApi: 1`.
2170
+ `recomposed` (from earlier kernels), `waiting` (0.40: a producer's claim,
2171
+ [Waiting on you](#waiting-on-you)). `producer` is `kernel`, a capability id,
2172
+ or another producer id (`agent`). Older rows may carry `eventsApi: 1`.
2173
+ `launched` is written by spawn and, since 0.40, once per session start or
2174
+ restart, as soon as the session exists (`data: {harness, backend,
2175
+ launchConfig, phase, startId}`; spawn's row has neither `phase` nor
2176
+ `startId`). `phase` is `start` or `restart`, or `recovered` when a later
2177
+ start adopted an interrupted start's receipt that had no boundary; that row
2178
+ is dated at the receipt's launch time. The boundary is complete per log: a
2179
+ log that missed it gets a copy of the same row (same time and data), never
2180
+ a second one.
2158
2181
  - **Incarnation.** Each row carries the writing home's `createdAt` (or
2159
2182
  `null` for old rows); the top-level `incarnation` is the current home's (or
2160
2183
  `null`). Earlier incarnations are returned as this address's history.
2161
2184
  - **Address.** `--home` must be a home of `<instance>` (`E_HOME_MISMATCH`).
2162
2185
  Rows for another address are dropped and counted in
2163
2186
  `integrity.foreignRows`; torn or invalid lines are counted in
2164
- `integrity.unreadableRows`. Duplicates are removed.
2187
+ `integrity.unreadableRows`. A row present in both logs is returned once;
2188
+ identical rows repeated within one log (a set, a clear and the same set in
2189
+ one millisecond) are all returned, as many as the log holding the most
2190
+ copies has.
2165
2191
  - **Window.** `count` is the rows after `--since`; `returned` the window
2166
2192
  (`--limit`, default 200, 1–2000); `truncated` means rows were cut or a
2167
2193
  source was a tail. `lastEvent` is `{kind, at, producer, incarnation}` of
2168
2194
  the last returned row, or `null`.
2169
- - **Waiting.** `waitingClaims[]` is `{producer, waiting, since, reason}` per
2170
- producer with a claim in the current incarnation (cleared ones included).
2171
- A producer's latest row with `data.waitingOnYou` decides. `waitingOnYou` is
2172
- `{since, producer, reason}` of the newest positive claim, or `null`
2173
- (unknown, not "not waiting"). No kernel path claims waiting today.
2195
+ - **Waiting.** `waitingClaims[]` is `{producer, waiting, since, reason,
2196
+ message}` per producer with a live claim in the current incarnation
2197
+ (cleared ones included). A producer's latest row with `data.waitingOnYou`
2198
+ decides. `waitingOnYou` is `{since, producer, reason, message}` of the
2199
+ newest positive claim, or `null` (unknown, not "not waiting"). See
2200
+ [Waiting on you](#waiting-on-you) for the producers and the rules.
2174
2201
  - Errors: `E_SESSION_UNKNOWN`, `E_AMBIGUOUS_INSTANCE`, `E_HOME_MISMATCH`,
2175
2202
  `E_BAD_ARGS`, `E_EVENTS_FAILED`.
2176
2203
 
2204
+ ### Waiting on you
2205
+
2206
+ Feature `waiting-on-you` (OATS 0.40.0): an instance blocked on a human (a
2207
+ permission prompt, a question, an agent asking for an answer) says so through
2208
+ a producer's claim. **Claims are display-only:** nothing in the kernel acts
2209
+ on `waitingOnYou`. In particular `oats session input` behaves exactly as
2210
+ before whether or not a claim is set.
2211
+
2212
+ ```text
2213
+ oats instance waiting <set|clear> --producer <id> [--reason permission|question|attention] [--message <text>] [--home <abs>] [--dir <d>] --json
2214
+ oats instance attention [--message <text>] [--clear] --json
2215
+ ```
2216
+
2217
+ ```json
2218
+ {"eventsApi":2,"instance":"dev-1","home":"/w/agents/dev/instances/dev-1","producer":"oats.core","changed":true,
2219
+ "waitingOnYou":{"since":"2026-10-03T12:00:00.000Z","producer":"oats.core","reason":"permission","message":null}}
2220
+ ```
2221
+
2222
+ - **The row.** A claim is a `waiting` event, `data: {waitingOnYou: true,
2223
+ reason, message?}` or `{waitingOnYou: false}`, appended to both logs, with
2224
+ `producer` the caller's `--producer`.
2225
+ - **`waiting`.** `--producer` matches `^[a-z0-9][a-z0-9._/-]{0,63}$` and is
2226
+ not `kernel`. `set` needs `--reason`, one of `permission`, `question`,
2227
+ `attention` (closed). `clear` refuses `--reason` and `--message`. The home
2228
+ is `--home`, else `$OATS_INSTANCE_HOME`, else the instance home enclosing
2229
+ the working directory; it must be a home of its own name under the scope
2230
+ (`--dir`, else the agents root the home sits in).
2231
+ - **`attention`** is the agent's own claim, run by the instance from its
2232
+ home: sugar for `waiting set --producer agent --reason attention
2233
+ [--message]`, and `--clear` for `waiting clear --producer agent`. Its home
2234
+ comes only from `$OATS_INSTANCE_HOME`: it has no `--home` or `--dir` and
2235
+ never targets another instance. Unset, or not an instance home (no readable
2236
+ `instance.json`), is `E_USAGE`. `--clear` with `--message` is `E_BAD_ARGS`.
2237
+ - **`--message`**: one line of 1 to 200 characters (code points). Refused,
2238
+ as `E_BAD_ARGS` naming `--message`: control characters (`\p{Cc}`: C0, DEL,
2239
+ C1; so no newline, tab or ESC), the line and paragraph separators U+2028
2240
+ and U+2029, the bidi embeddings, overrides and isolates U+202A–202E and
2241
+ U+2066–2069, the invisible U+200B (zero width space), U+2060 (word
2242
+ joiner) and U+FEFF (BOM), and the tag characters U+E0000–E007F. Everything
2243
+ else is allowed, including ZWJ and ZWNJ (U+200C, U+200D: emoji sequences
2244
+ such as 👩‍💻, Persian and Indic text), the marks LRM, RLM and ALM (U+200E,
2245
+ U+200F, U+061C) and the soft hyphen. A message that
2246
+ starts with `--` goes inline, `--message=--deploy failed`: that value is
2247
+ only ever the message, never a flag (`--message=--clear` sets the message
2248
+ "--clear"). The spaced form `--message --deploy` reads `--deploy` as a
2249
+ flag and is `E_BAD_ARGS`. It is stored as given, only on a
2250
+ positive claim. The reader applies the same rule again: an invalid stored
2251
+ message (a hand-edited log) reads as `null`, and the claim still counts.
2252
+ A stored `reason` outside `permission`, `question`, `attention` reads as
2253
+ `null` too, and a row whose `producer` is neither `kernel` nor a valid
2254
+ producer id is no claim at all.
2255
+ - **Idempotent.** The verb reads the producer's live claim first and appends
2256
+ only on a change: a `set` whose reason or message differs from the live
2257
+ positive claim appends (`changed: true`), an identical one does not; a
2258
+ `clear` appends only over a live positive claim. The answer is
2259
+ `{eventsApi, instance, home, producer, changed, waitingOnYou}`, where
2260
+ `waitingOnYou` is that producer's resulting claim (`null` when it holds
2261
+ none). Concurrent writers append whole lines; the latest row decides.
2262
+ Each log is judged on its own, and success means both took the row: a
2263
+ write either log refused is `E_EVENTS_FAILED` naming it, and the next call
2264
+ (a retry) appends again to repair it.
2265
+ - **Session boundary.** A claim written before the incarnation's latest
2266
+ kernel `launched`, `restarted` or `stopped` row (in time order; rows of the
2267
+ same millisecond in append order) is not live: it belongs to an ended
2268
+ session and is not listed in `waitingClaims`. A crash
2269
+ while waiting reads `null` on the roster (not running), and the next start
2270
+ writes `launched`, which voids the claim.
2271
+ - **Producers.**
2272
+ - `oats.core`: the Claude Code emitter oats.core installs in a Claude
2273
+ instance's `<home>/.claude/settings.json` (`permission` on a permission
2274
+ prompt, `question` on AskUserQuestion or an MCP elicitation, cleared when
2275
+ the session moves on). See [capabilities.md](capabilities.md), "oats.core:
2276
+ needs input".
2277
+ - `agent`: the instance itself, through `oats instance attention`, and
2278
+ only through it: `oats instance waiting --producer agent` is
2279
+ `E_BAD_ARGS`. **Agent claims are cleared only by the agent (`--clear`)
2280
+ or a session boundary**; no hook clears them (a wake broker's paste is
2281
+ also a prompt submit).
2282
+ - **Where it shows.** `waitingOnYou` on the events read, on `oats status
2283
+ --json` instance rows (running rows only) and on `oats session inspect
2284
+ --json` (beside `state`, whose enum is unchanged; `null` unless the harness
2285
+ is running). Plain `oats status` prints `! needs input (<reason>):
2286
+ <message>` under a running instance's row while it holds a claim.
2287
+ - **Cost.** To compute the field, `oats status` reads the home log of each
2288
+ running row (the workspace log only when the home log is absent), with
2289
+ the same bounded read as the events read: at most the last 4 MiB, so a
2290
+ claim older than the last 4 MiB of a very busy log is not seen. Stopped
2291
+ rows read nothing.
2292
+ - **Local only.** Neither verb routes with `--server`: producers run on the
2293
+ instance's own host.
2294
+ - Errors: `E_BAD_ARGS`, `E_USAGE` (attention), `E_SESSION_UNKNOWN` (no
2295
+ readable `instance.json`), `E_HOME_MISMATCH`, `E_EVENTS_FAILED` (the write
2296
+ failed; nothing else is affected).
2297
+
2177
2298
  ## Lifecycle: stop and retire
2178
2299
 
2179
2300
  Feature `lifecycle-plans` (and `retire-retention`), `lifecycleApi: 1`. A
@@ -2359,6 +2480,11 @@ selection flags. See [the start workflow](desktop-instance-start.md).
2359
2480
  instance's events as a `launch-warning` row, `data: {message}`. They are
2360
2481
  advisory: the start went ahead. Earlier kernels omit the field; read a
2361
2482
  missing `warnings` as `[]`.
2483
+ - A start or restart appends a `launched` event as soon as its session
2484
+ exists (0.40, `phase: "start"` or `"restart"`, `startId`), the session
2485
+ boundary that voids earlier waiting claims ([Waiting on you](#waiting-on-you)).
2486
+ A start whose metadata write failed has it already, so its adoption adds
2487
+ none to a log that holds it and copies it into a log that does not.
2362
2488
  - Restart is one command: the kernel validates the new selection before
2363
2489
  stopping, and owns the stop, lock, launch recovery and metadata. Never
2364
2490
  restart by retiring and spawning.
@@ -2498,6 +2624,25 @@ oats schedule show <id> --json
2498
2624
  [shared row fields](#automations-shared-rows).
2499
2625
  `executionStatus` is `{kind: "legacy" | "invalid", capture: "unknown",
2500
2626
  migrationRequired: true, reason?, intent?}`; only `legacy` runs.
2627
+ - **`attempt`** (present while a launch has no recorded result; reconcile
2628
+ resolves it): `{scheduledFor, startedAt, wallClock, error?, exited?,
2629
+ exitStatus?, exitSignal?}`. `error` (0.40.0) is the first run's cause. A
2630
+ `command` or `operation` attempt with `exited: true` (0.40.0) holds no host
2631
+ slot (`running: false`) but still blocks its own job; show it as needing
2632
+ `oats schedule reconcile <id>` (or `--clear`) either way.
2633
+ - **Schedule IDs**: local and workspace schedule definition names permit 1–100
2634
+ lowercase letters, digits and dashes; trigger names retain their 40-character
2635
+ limit. Desktop accepts these schedule names for creation, editing and row
2636
+ actions (enable, disable, test, run and reconcile), including qualified IDs.
2637
+ A spawn's derived instance name still has a 64-character limit.
2638
+ - **`description`** (0.40.0): the shared row field is the local definition's
2639
+ `description` when it has one, else `null` (a workspace schedule's comes
2640
+ from its file header). It is one line of at most 200 characters with no
2641
+ control characters; show it in place of the argv when present. Like `task`,
2642
+ it is untrusted text: render it as text. Desktop preserves it unchanged
2643
+ through edits to timing and other fields. A kernel before 0.40.0 sends
2644
+ `null` for every local schedule, and drops a `description` given to `oats
2645
+ schedule add` without refusing it.
2501
2646
  - **An unreadable row** (`list` only): `{id, scope, scheduleApi,
2502
2647
  scheduleHistoryApi, unreadable: {code, message}, history: {status:
2503
2648
  "corrupt", stored: null, truncated: false}, recentRuns: []}`. One bad job
@@ -2604,8 +2749,9 @@ Details: [schedules.md](schedules.md#workspace-triggers-and-schedules).
2604
2749
  null}}` (this machine's `host.name` and its `gh` logins, compared with a
2605
2750
  row's `owner`), `snapshot: {takenAt, problems (a count)} | null` (the last
2606
2751
  `oats sync` snapshot), and `scheduler: {installed, active, registered,
2607
- lastTick, maxConcurrent, …}` (nothing runs unless installed, active and
2608
- registered).
2752
+ lastTick, maxConcurrent, triggersMaxConcurrent, …}` (nothing runs unless installed, active and
2753
+ registered). `maxConcurrent` is the effective scheduled-job cap (default 5);
2754
+ `triggersMaxConcurrent` is the separate trigger cap, or `null` for no host cap.
2609
2755
 
2610
2756
  **Every row** carries:
2611
2757
  - `id` (a local schedule keeps its bare id; a workspace item is
@@ -139,6 +139,10 @@ oats session attach --home /abs/home
139
139
  harness, `shell` for a fallback shell,
140
140
  `stopped` for an absent or dead terminal, or `not-launched`. An unavailable
141
141
  backend is an error (`E_SESSION_UNAVAILABLE`), never a stopped result.
142
+ Beside `state`, `waitingOnYou` (feature `waiting-on-you`) is a producer's
143
+ live claim that the instance needs input from a human, `{since, producer,
144
+ reason, message}`, or `null`; it is non-null only for a running harness
145
+ (docs/desktop-cli-api.md, "Waiting on you").
142
146
  - **input** submits UTF-8 text (stdin or `--text-file`, at most 256 KiB, no
143
147
  NUL) followed by Enter, as a bracketed paste. The text is never run by a
144
148
  shell. A fallback shell, a stopped session or a split
@@ -16,6 +16,8 @@ reference pages ([workspaces](workspaces.md), [souls and instances](souls-and-in
16
16
  - **`oats.framework`** (`oats-package/`): the `oats.core`, `oats.setup` and
17
17
  `oats.knowledge-theory` capabilities and the `knowledge-theory-expert` soul,
18
18
  released as a package under its own `oats-framework/v<version>` tags.
19
+ `oats.core` is the one with executables: its spawn and launch hook and the
20
+ Claude Code waiting emitter (`capabilities/oats-core/bin/`).
19
21
 
20
22
  The OATS Desktop (`packages/desktop/`) is an Electron app with a bundled,
21
23
  dependency-free localhost server; it is released with the kernel but not
@@ -54,6 +56,7 @@ published to npm. Its developer docs are in
54
56
  | `instruction-composition.mjs` | the generated `AGENTS.md` |
55
57
  | `teams.mjs`, `teams-verbs.mjs` | the team model and the `oats teams` verbs |
56
58
  | `schedule.mjs`, `schedule-host.mjs`, `triggers.mjs`, `automations.mjs` | schedules, triggers and the host timer |
59
+ | `schedule-command.mjs`, `schedule-command-child.mjs` | synchronous scheduler adapter and asynchronous child supervisor: bounded output, TERM/KILL escalation and observed exit; no changes to synchronous tick/lock callbacks |
57
60
  | `operator-dispatch.mjs` | capability commands run from a deployment, and its module store |
58
61
  | `instance-*.mjs` | inspection, lifecycle, events and Git views of an instance |
59
62
  | `tmux-config.mjs`, `session-*.mjs` | the tmux session backend and terminal input |
@@ -61,6 +64,13 @@ published to npm. Its developer docs are in
61
64
  | `servers.mjs` | routing commands to a registered server |
62
65
  | `harness-trust.mjs` | reading (never writing) Claude's and Codex's folder trust for a launch |
63
66
 
67
+ The schedule registry stores explicit concurrency caps, leaving the schedule
68
+ cap absent for its effective default of five. Reads migrate legacy stored one
69
+ to absent once, under `registry.lock`, and record `capsVersion: 2`. Registration
70
+ and cap updates use that same short lock; later explicit one stays explicit.
71
+ `readRegistry()` returns stored choices; scheduling and status apply the default
72
+ without writing it back. The trigger cap is independent and absent means no cap.
73
+
64
74
  The kernel is runtime-neutral: nothing in `lib/` depends on a harness or on
65
75
  a provider. Provider behaviour lives in capabilities; the kernel supplies
66
76
  their contracts ([layers](layers.md)).
@@ -235,6 +245,15 @@ runs the full suite (sharded), `check`, `validate`, `pack:check` and the smoke
235
245
  test, and is the gate. Tests use local bare repositories and fakes; none
236
246
  contacts GitHub, aweb, Jira or Linear.
237
247
 
248
+ Desktop's standalone tests (`cd packages/desktop && npm ci && npm test`) must
249
+ load with only Desktop dependencies installed. Cross-package tests that import
250
+ both the kernel and Desktop belong under root `test/`; install dependencies at
251
+ the root and in `packages/desktop` before running those tests. The schedule
252
+ round-trip case is `node --test test/desktop-schedule-roundtrip.integration.mjs`.
253
+ The root runner includes this file with its existing Desktop dependency group.
254
+ With only root dependencies installed, it omits both Desktop suites and this
255
+ integration case and reports that coverage gap before and after the run.
256
+
238
257
  Tests pin behaviour, so a change that alters behaviour changes its test in the
239
258
  same commit. Never weaken an assertion to make a change pass.
240
259
 
@@ -9,10 +9,10 @@ or workspace membership alone does not make a package official.
9
9
 
10
10
  | package | release | capabilities | package souls |
11
11
  |---|---|---|---|
12
- | `oats.framework` | `oats-framework/v1.5.0` (this repository) | `oats.core`, `oats.setup`, `oats.knowledge-theory` | `knowledge-theory-expert` |
12
+ | `oats.framework` | `oats-framework/v1.6.0` (this repository) | `oats.core`, `oats.setup`, `oats.knowledge-theory` | `knowledge-theory-expert` |
13
13
  | `oats.okf` | `v4.1.1` | `oats.okf` (knowledge), `oats.okf-harvest`, `oats.okf-maintenance` | `knowledge-harvester`, `knowledge-maintainer` |
14
14
  | `oats.aweb` | `v1.21.1` | `oats.aweb` (messaging) | |
15
- | `oats.engineering` | `v1.8.0` | `oats.engineering-expert`, `oats.developer`, `oats.code-review`, `oats.maintainer` | `code-reviewer` |
15
+ | `oats.engineering` | `v1.8.1` | `oats.engineering-expert`, `oats.developer`, `oats.code-review`, `oats.maintainer` | `code-reviewer` |
16
16
  | `oats.authoring` | `v1.0.3` | `oats.authoring` | |
17
17
  | `oats.cloning` | `v1.0.1` | `oats.cloning` | `cloner` |
18
18
  | `oats.jira` | `v1.0.1` | `oats.jira` (tasks) | |
package/docs/packages.md CHANGED
@@ -51,7 +51,7 @@ packages:
51
51
  - **Bare version** (`v4.1.1`, `4.1.1`, `1.0.0-rc.1`): the id is looked up in
52
52
  the official catalog — `package-catalog.json` in the `oats` repo, or the file
53
53
  named by `OATS_PACKAGE_CATALOG` — which supplies the repo url, the tag
54
- convention (`v4.1.1` or `oats-framework/v1.5.0`) and the payload path. An id
54
+ convention (`v4.1.1` or `oats-framework/v1.6.0`) and the payload path. An id
55
55
  the catalog does not know is `E_PACKAGE_MISSING` ("use `git:<repo>@<ref>` for
56
56
  a package outside the catalog"). The catalog is the reviewed official list
57
57
  ([official-catalog.md](official-catalog.md)) and the only way a
@@ -74,7 +74,7 @@ members:
74
74
  - git:github.com/acme/agents
75
75
  - git:github.com/acme/platform
76
76
  packages:
77
- oats.framework: v1.5.0
77
+ oats.framework: v1.6.0
78
78
  oats.okf: v4.1.1
79
79
  oats.aweb: v1.21.1
80
80
  teams:
@@ -333,11 +333,11 @@ A soul that names one of the package's capabilities with
333
333
  "policy": "docs/official-catalog.md",
334
334
  "packages": {
335
335
  "oats.okf": { "url": "https://github.com/awebai/oats-okf.git", "ref": "v4.1.1", "path": "oats-package" },
336
- "oats.framework": { "url": "https://github.com/awebai/oats.git", "ref": "oats-framework/v1.5.0", "path": "oats-package" }
336
+ "oats.framework": { "url": "https://github.com/awebai/oats.git", "ref": "oats-framework/v1.6.0", "path": "oats-package" }
337
337
  }
338
338
  }
339
339
  ```
340
340
 
341
- `ref` carries the tag convention: a workspace's `oats.framework: v1.5.0`
342
- resolves to tag `oats-framework/v1.5.0`. Resolving through the catalog never
341
+ `ref` carries the tag convention: a workspace's `oats.framework: v1.6.0`
342
+ resolves to tag `oats-framework/v1.6.0`. Resolving through the catalog never
343
343
  advances a lock by itself: `oats sync` does, and says so.
@@ -0,0 +1,181 @@
1
+ # OATS 0.40.0
2
+
3
+ ## Added
4
+
5
+ - **"Needs input": an instance can say it is blocked on a human** (feature
6
+ `waiting-on-you`). The `waitingOnYou` fact that `oats instance events` has
7
+ carried since 0.24.12 finally has producers. It shows on every running
8
+ instance row of `oats status --json` and on `oats session inspect --json`
9
+ as `waitingOnYou: {since, producer, reason, message} | null`, and plain
10
+ `oats status` prints `! needs input (<reason>): <message>` under the row.
11
+ Claims are display-only: nothing in the kernel acts on them, and
12
+ `oats session input` is unchanged. See docs/desktop-cli-api.md, "Waiting
13
+ on you".
14
+ - `oats instance waiting <set|clear> --producer <id> [--reason
15
+ permission|question|attention] [--message <text>]` records a producer's
16
+ claim as a `waiting` event, appended only when the claim changes.
17
+ - `oats instance attention [--message "<one line>"] [--clear]` is the
18
+ agent's own claim, run from its home (`$OATS_INSTANCE_HOME` only). The
19
+ oats.core instructions now teach it: when an agent has asked a human
20
+ something and cannot continue without the answer, it runs
21
+ `oats instance attention --message "…"` and ends its turn, then
22
+ `--clear` once it has the answer. Only the agent or a session boundary
23
+ clears an agent claim.
24
+ - `--message` is one line of 1 to 200 characters. Refused, at write and
25
+ again at read (a refused stored message reads as `null`): control
26
+ characters, U+2028/2029, the bidi controls U+202A–202E and
27
+ U+2066–2069, U+200B, U+2060, U+FEFF and the tag characters
28
+ U+E0000–E007F. Everything else is allowed, ZWJ/ZWNJ (U+200C/D) and
29
+ LRM/RLM/ALM (U+200E/F, U+061C) included. The Desktop uses the same set.
30
+ - A claim is live only after the incarnation's latest kernel `launched`,
31
+ `restarted` or `stopped` row, so a crashed or restarted session never
32
+ shows a stale claim. `waitingOnYou` and `waitingClaims[]` entries gain
33
+ `message` (a string or `null`); the shape is otherwise unchanged.
34
+
35
+ - **oats.core 2.4.0 (oats.framework 1.6.0) reports Claude Code permission
36
+ prompts and questions.** For a Claude instance, oats.core manages its own
37
+ hook entries in `<home>/.claude/settings.json`. A permission prompt sets
38
+ `waitingOnYou` with reason `permission`; AskUserQuestion or an MCP
39
+ elicitation sets `question`; the claim clears when the session moves on.
40
+ The hooks always exit 0, print nothing and time out in seconds, so a failing
41
+ emitter means "unknown", never a blocked tool. Every other key and entry in
42
+ that file is left alone. oats.core now requires OATS 0.40.0. See
43
+ docs/capabilities.md, "oats.core: needs input".
44
+ - **Desktop: the sidebar shows which agents are waiting on you.** When an
45
+ agent is waiting for a tool approval, a question or an attention request,
46
+ its row shows a "Needs input" mark next to its name. Hover over the row, or
47
+ focus it from the keyboard, to see what it is waiting for, its message and
48
+ how long it has waited. A collapsed parent shows "N below" for waiting agents
49
+ hidden under it, and an open terminal tab shows the mark as well. The mark
50
+ appears only while the agent is running and the installed OATS reports
51
+ `waiting-on-you`. It goes on the next roster refresh after the wait ends.
52
+ - **Schedules take an optional `description`**
53
+ ([#546](https://github.com/awebai/oats/issues/546)): what a job is for, in
54
+ words. `oats schedule add|update --file` accepts it as one line of 1 to 200
55
+ characters with no control characters; anything else is
56
+ `E_SCHEDULE_INVALID` naming `field: "description"`. It is stored as given
57
+ and returned by `schedule list --json` and `show --json` in each row's
58
+ `description` (`null` when there is none), which is how the Desktop reads
59
+ it. It is informational only and never reaches a run. Jobs without one are
60
+ unchanged. Earlier kernels drop the key without refusing it. See
61
+ [schedules](../schedules.md#kinds).
62
+ - **`oats doctor` warns about unresolved schedule attempts**
63
+ (`schedule-unresolved`, [#545](https://github.com/awebai/oats/issues/545)).
64
+ This covers each job, in this deployment and in the other deployments this
65
+ host ticks, whose launch has no recorded result. The warning gives the job,
66
+ the attempt's scheduledFor and startedAt and its age, whether it holds a
67
+ host slot, the first error, and the remedy: `oats schedule reconcile <id>`,
68
+ with `--clear` when a command's effects can't be proven. In `--json` it is
69
+ a `problems[]` item with `severity: "warning"`; the exit status is
70
+ unchanged. See [schedules](../schedules.md#what-a-run-reports).
71
+
72
+ ## Changed
73
+
74
+ - **An unknown command or operation run no longer stalls the host's other
75
+ jobs** ([#545](https://github.com/awebai/oats/issues/545)). Once the kernel
76
+ has observed the command's process exit (it returned, or was stopped at the
77
+ timeout), its unresolved attempt stops counting against `maxConcurrent`.
78
+ The job itself still waits for `oats schedule reconcile`, so it never runs
79
+ twice on unproven effects. Its attempt now records `exited`, `exitStatus`
80
+ and `exitSignal`, and `show` reports `running: false`. Spawn jobs keep
81
+ their slot, and so does an attempt recorded by an earlier kernel, until
82
+ reconcile.
83
+ - **An unresolved attempt keeps its first error.** Later due ticks used to
84
+ replace the cause ("command timed out…", "answered no valid envelope…",
85
+ "command outcome unconfirmed: …") with "launch attempt without a recorded
86
+ result" in `lastRun` and its history row. The cause is now kept on the
87
+ attempt (`attempt.error`) and in `lastRun`.
88
+ - **Schedule IDs may contain up to 100 characters**, locally and in workspace
89
+ definitions. Trigger IDs remain limited to 40. Spawn schedules still need
90
+ a short enough `purpose` to fit the 64-character instance-name limit.
91
+ - **Desktop timing edits preserve a schedule's description**, including its
92
+ exact whitespace and Unicode text. Existing jobs without descriptions
93
+ remain editable.
94
+ - **oats.engineering 1.8.1** (catalog and workspace pin, and the bundled
95
+ mirrors): a PR is reviewed only after its owner says the developer's review
96
+ loop converged. `/pr-review` starts on the owner's hand-over (the loop's
97
+ final verdict and rounds, the exact head, CI green on it), and a head that
98
+ moves afterwards waits for the next hand-over, after which only the delta is
99
+ reviewed and the verdict re-bound; a PR with no owning expert is ready when
100
+ its author marks it ready or asks for review at a named head.
101
+ Experts verify only converged branches and hand PRs over with all three
102
+ facts; developers report convergence, with the head, instead of
103
+ intermediate heads.
104
+ - **The Desktop accepts OATS CLIs `>=0.25.8 <0.41.0`**, so it runs against
105
+ this release's kernel; the Desktop 0.39.x refuses a 0.40 CLI.
106
+ - **`oats session start` and `restart` now record a `launched` event**
107
+ (`data.phase: "start"` or `"restart"`, `data.startId`), as spawn already
108
+ did, once per start and in each log: a start recovered from an interrupted
109
+ one's receipt adds none, copies the same row into a log that missed it, or
110
+ writes one with `phase: "recovered"` dated at its launch when the
111
+ interrupted start had written it to neither log. A consumer that counts a home's
112
+ events sees one more row per start.
113
+ - **oats.framework 1.6.0** (oats.core 2.4.0; catalog and workspace pin
114
+ `oats-framework/v1.6.0`): the package that carries the "needs input"
115
+ emitter and the `oats instance attention` protocol above. A workspace's
116
+ `oats.framework: v1.6.0` resolves to that tag through the official
117
+ catalog; workspaces pinned to v1.5.0 keep oats.core 2.3.0 until they move
118
+ the pin and sync.
119
+ - **Desktop: collapsing a row hides only rows in its own deployment
120
+ section.** A row whose parent name matched an agent in another deployment
121
+ was hidden when that agent was collapsed. It now stays visible.
122
+
123
+ ## Fixed
124
+
125
+ - **A scheduled command that ignores SIGTERM can no longer wedge the host
126
+ scheduler** ([#547](https://github.com/awebai/oats/issues/547)). Command and
127
+ operation runs, workspace-spawn launches and spawn previews now send SIGTERM
128
+ at the five-minute timeout, then SIGKILL to the remaining process group after
129
+ two seconds. The runner observes the direct child's exit and bounds output
130
+ pipe draining before returning. Timed-out commands remain unknown and wait
131
+ for reconcile, while their exited processes no longer hold host slots;
132
+ spawn jobs retain their existing slot semantics.
133
+
134
+ - **Missing harness-package diagnostics give usable direct install commands.**
135
+ Spawn and restart preflight no longer suggest the removed `oats install`
136
+ verb. Guidance names the operator's responsibility, quotes the selected
137
+ executable and context paths, preserves Pi's resource directory, and keeps
138
+ Claude marketplace registration before plugin installation. OATS still
139
+ verifies requirements without installing packages.
140
+
141
+ ## Notes
142
+
143
+ - **Claude Code honours only the last `--settings` flag.** On Claude Code
144
+ 2.1.288 a second `--settings` replaces the first wholesale, even when it
145
+ has no hooks. That is why oats.core writes the project
146
+ `<home>/.claude/settings.json`, which composes with the user's settings and
147
+ with a `--settings`. Any capability that needs Claude settings must manage
148
+ its own entries in that file, under its own marker, and never pass
149
+ `--settings`.
150
+ - **Claude instances spawned before the upgrade get the emitter only on
151
+ respawn.** A home's launch hook comes from its recorded module copy, so a
152
+ restart keeps the old oats.core. The `attention` verb works on any harness
153
+ as soon as the kernel is upgraded.
154
+ - If a user's Claude configuration sets `disableAllHooks` or
155
+ `allowManagedHooksOnly`, the emitter never runs and the field stays `null`.
156
+ - Refusing a Claude Code permission prompt fires no hook (Claude Code
157
+ 2.1.288), so after a "No" the claim stays, labelled `permission`, until the
158
+ human's next prompt; Claude is waiting for that prompt anyway.
159
+ - The emitter debounces only the per-tool-call clears; `UserPromptSubmit`,
160
+ `Stop` and `SessionEnd` are not debounced. A turn-boundary clear gets a
161
+ CLI call: from that hook, or, if another hook holds the lock, from that
162
+ holder if it still has time; otherwise from the next event. That bounds
163
+ what an unfenced kernel write can leave wrong
164
+ ([#568](https://github.com/awebai/oats/issues/568)): after a hook
165
+ suspended past 5 s mid-call (the machine slept) or a reaper killed at a
166
+ precise instant, a wrongly shown claim lasts until the end of the turn,
167
+ or, if the turn's last hook found a reconciliation out of time, until the
168
+ next event (the human's next prompt); a hidden question lasts until the
169
+ human answers it. A permission prompt can also stay hidden until it is
170
+ answered without any of that: when it opens while another hook's
171
+ reconciliation runs out of time (a slow clear on a loaded machine).
172
+ Parallel main-thread tool calls may clear a claim early. See
173
+ docs/capabilities.md, oats.core: needs input, Limits.
174
+ - Tool calls by background or parallel subagents in the same Claude session
175
+ do not clear the claim: the emitter skips tool events that carry a
176
+ subagent's `agent_id`. A permission prompt never says who asked, so after
177
+ a human approves a subagent's prompt the claim stays until the next
178
+ main-thread event (its next tool call, the subagent's completion, a stop or
179
+ a prompt). For a foreground subagent the main thread makes no call until
180
+ the subagent finishes, so the claim can last the whole subagent run: too
181
+ long, never hiding a real block.
@@ -0,0 +1,20 @@
1
+ # OATS 0.40.1
2
+
3
+ 0.40.0 was tagged but never published because its Desktop build failed in the release workflow. 0.40.1 is the first published 0.40 release and includes everything in the [0.40.0 notes](v0.40.0.md).
4
+
5
+ ## Changed
6
+
7
+ - **Scheduled jobs default to a host concurrency of five.** The registry stores
8
+ explicit choices only. Legacy stored one migrates to the default once; an
9
+ explicit `oats schedule host install --max-concurrent 1` after upgrade stays
10
+ one. Use `--max-concurrent N|default` and the independent
11
+ `--triggers-max-concurrent N|none` to configure caps through the CLI
12
+ ([#550](https://github.com/awebai/oats/issues/550)). Host status reports both
13
+ caps; triggers remain uncapped by the host unless explicitly limited.
14
+
15
+ ## Fixed
16
+
17
+ - **Desktop tests run with only Desktop dependencies installed.** The schedule
18
+ description round-trip integration test now lives in the root suite, where
19
+ kernel dependencies are available. Desktop's standalone release test suite
20
+ retains its unit coverage without importing the kernel.