@awebai/oats 0.39.3 → 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.
- package/bin/oats.mjs +101 -11
- package/docs/capabilities.md +215 -1
- package/docs/desktop-cli-api.md +159 -13
- package/docs/execution-targets.md +30 -3
- package/docs/implementation.md +19 -0
- package/docs/official-catalog.md +2 -2
- package/docs/packages.md +5 -5
- package/docs/release-notes/v0.39.4.md +22 -0
- package/docs/release-notes/v0.40.0.md +181 -0
- package/docs/release-notes/v0.40.1.md +20 -0
- package/docs/schedules.md +85 -16
- package/docs/workspaces.md +1 -1
- package/lib/automations.mjs +4 -1
- package/lib/core.mjs +49 -9
- package/lib/instance-events.mjs +178 -23
- package/lib/schedule-command-child.mjs +58 -0
- package/lib/schedule-command.mjs +26 -0
- package/lib/schedule.mjs +142 -37
- package/lib/servers.mjs +14 -2
- package/lib/session-input.mjs +88 -2
- package/package-catalog.json +2 -2
- package/package.json +1 -1
- package/skills/oats-getting-started/SKILL.md +1 -1
package/docs/desktop-cli-api.md
CHANGED
|
@@ -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`).
|
|
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)
|
|
2157
|
-
`
|
|
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`.
|
|
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
|
|
2170
|
-
producer with a claim in the current incarnation
|
|
2171
|
-
A producer's latest row with `data.waitingOnYou`
|
|
2172
|
-
`{since, producer, reason}` of the
|
|
2173
|
-
(unknown, not "not waiting").
|
|
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,12 +139,39 @@ 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
|
|
145
|
-
tmux window is refused.
|
|
146
|
-
|
|
147
|
-
|
|
149
|
+
tmux window is refused. The text is pasted once. Enter waits for the pane to
|
|
150
|
+
settle (two identical captures, at least about 200 ms, longer for a larger
|
|
151
|
+
paste, at most 2 s), and is judged by whether it changed the bottom 15 lines
|
|
152
|
+
of the pane. The comparison is of bytes only, and the pane's text is never
|
|
153
|
+
interpreted. Trailing spaces are ignored. When the pane was seen to change
|
|
154
|
+
size (a resize, or a second client attaching), a reflow of the same content
|
|
155
|
+
is not a change either: each side's content must already be on the other
|
|
156
|
+
side's screen or in its history, so content that appeared or disappeared
|
|
157
|
+
still counts. An Enter that changed nothing was swallowed, and is resent
|
|
158
|
+
after a backoff, at most 3 Enters in total. The answer adds:
|
|
159
|
+
- `submitted: true, verified: true`: an Enter was taken.
|
|
160
|
+
- `submitted: false, verified: true, reason: "enter-not-taken"`: none of the
|
|
161
|
+
3 Enters changed the pane. The text stays in the agent's input box; it is
|
|
162
|
+
not pasted again.
|
|
163
|
+
- `submitted: true, verified: false`: a capture failed, so no further Enter
|
|
164
|
+
was sent and the last one was not judged. As before, this means the
|
|
165
|
+
terminal accepted the keys. When the pane cannot be read before the first
|
|
166
|
+
resend, exactly one Enter was sent.
|
|
167
|
+
|
|
168
|
+
`submitted` never means the agent processed the text. A pane that changes
|
|
169
|
+
for another reason after Enter (a spinner, a clock, a human typing) reads as
|
|
170
|
+
taken. A harness that shows no visible reaction to Enter receives up to two
|
|
171
|
+
extra Enters; real harnesses (claude, codex, pi) redraw on submit. A call takes at most about 4 s plus its tmux calls. A failed paste or
|
|
172
|
+
key send is `E_SESSION_INPUT_FAILED`, with no retry. Wake schedules and
|
|
173
|
+
messaging capabilities use this command ([schedules.md](schedules.md)); a
|
|
174
|
+
wake schedule records any answer as delivered.
|
|
148
175
|
- **attach** is interactive and takes no `--json`. It opens a temporary tmux
|
|
149
176
|
session linked to the agent's window alone.
|
|
150
177
|
Closing the viewer leaves the agent running.
|
package/docs/implementation.md
CHANGED
|
@@ -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
|
|
package/docs/official-catalog.md
CHANGED
|
@@ -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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
342
|
-
resolves to tag `oats-framework/v1.
|
|
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,22 @@
|
|
|
1
|
+
# OATS 0.39.4
|
|
2
|
+
|
|
3
|
+
## Fixed
|
|
4
|
+
|
|
5
|
+
- **`oats session input` no longer reports an unsent message as submitted.**
|
|
6
|
+
After a large bracketed paste, Claude Code could swallow the Enter that
|
|
7
|
+
followed it at once, leaving the text in the agent's input box until someone
|
|
8
|
+
pressed Enter, while the command answered `submitted: true` (#562). Enter
|
|
9
|
+
now waits for the pane to settle, and is judged by whether it changed the
|
|
10
|
+
bottom of the pane. This is a byte comparison that ignores trailing spaces,
|
|
11
|
+
and also ignores a reflow when the pane was seen to change size, as when
|
|
12
|
+
OATS Desktop attaches. The pane's text is never interpreted. A swallowed
|
|
13
|
+
Enter is resent with a backoff, at most 3 in total, and the text is never
|
|
14
|
+
pasted again. The answer gains `verified`: `true` when the comparison
|
|
15
|
+
judged the Enter, `false` when a capture failed (then no further Enter is
|
|
16
|
+
sent, and `submitted: true` keeps its old meaning). When no Enter is taken
|
|
17
|
+
the answer is `submitted: false, verified: true, reason: "enter-not-taken"`;
|
|
18
|
+
a consumer that requires `submitted: true`, such as the aw wake broker, then
|
|
19
|
+
reports a failed delivery instead of a silent one. A harness that shows no
|
|
20
|
+
visible reaction to Enter receives up to two extra Enters; real harnesses
|
|
21
|
+
(claude, codex, pi) redraw on submit. A call now takes up to about 4 s. See
|
|
22
|
+
[execution targets](../execution-targets.md).
|
|
@@ -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.
|