@awebai/oats 0.30.2 → 0.31.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.
- package/bin/oats.mjs +111 -44
- package/docs/configuration.md +21 -1
- package/docs/desktop-cli-api.md +120 -14
- package/docs/desktop-instance-start.md +3 -1
- package/docs/desktop.md +20 -0
- package/docs/execution-targets.md +53 -30
- package/docs/implementation.md +1 -1
- package/docs/integrations.md +1 -1
- package/docs/oats-local.schema.json +8 -0
- package/docs/official-catalog.md +1 -1
- package/docs/packages.md +2 -2
- package/docs/release-notes/v0.30.3.md +75 -0
- package/docs/release-notes/v0.31.0.md +130 -0
- package/docs/schedules.md +4 -1
- package/docs/servers.md +94 -25
- package/docs/souls-and-instances.md +8 -3
- package/lib/attachments.mjs +2 -1
- package/lib/core.mjs +233 -216
- package/lib/errors.mjs +17 -0
- package/lib/instance-inspect.mjs +11 -3
- package/lib/schedule.mjs +21 -8
- package/lib/servers.mjs +265 -45
- package/lib/session-input.mjs +9 -23
- package/lib/session-viewer.mjs +0 -5
- package/lib/triggers.mjs +10 -8
- package/package-catalog.json +1 -1
- package/package.json +1 -1
- package/lib/herdr.mjs +0 -106
package/docs/desktop-cli-api.md
CHANGED
|
@@ -30,8 +30,9 @@ canonical (`github.com/<org>/<repo>`, or `local/<abs-path>`). Examples use
|
|
|
30
30
|
|
|
31
31
|
```json
|
|
32
32
|
{"schemaVersion":1,"name":"@awebai/oats","version":"0.30.0","desktopApi":1,
|
|
33
|
-
"harnesses":["pi","claude","codex"],"sessionBackends":["tmux"
|
|
34
|
-
"remote":["spawn","retire","status","session","session-start","session-restart","launch-config","roster","harvest","schedule","session-upload","operations"
|
|
33
|
+
"harnesses":["pi","claude","codex"],"sessionBackends":["tmux"],"launchOptions":["yolo"],
|
|
34
|
+
"remote":["spawn","retire","status","session","session-start","session-restart","launch-config","roster","harvest","schedule","session-upload","operations",
|
|
35
|
+
"readiness","instance-events","instance-git","lifecycle-plans"],
|
|
35
36
|
"features":["retire-home","session-start","session-restart","launch-config","schedule","session-upload","operations","instance-git",
|
|
36
37
|
"instance-git-remote","souls-declarations","lifecycle-plans","retire-retention","readiness","spawn-preview","instance-events",
|
|
37
38
|
"instance-events-2","schedule-history","schedule-read-2","spawn-preview-2","spawn-idempotency","spawn-idempotency-2","spawn-apply-2",
|
|
@@ -47,10 +48,14 @@ canonical (`github.com/<org>/<repo>`, or `local/<abs-path>`). Examples use
|
|
|
47
48
|
accepted. The real gate is the feature list; its minimum is
|
|
48
49
|
`packages-no-approval`.
|
|
49
50
|
- `harnesses` is what `--harness` accepts; `sessionBackends` what `--backend`
|
|
50
|
-
accepts
|
|
51
|
+
accepts: `["tmux"]` since 0.31.0, when Herdr was removed (`--backend herdr`
|
|
52
|
+
is refused with `E_HERDR_REMOVED`). A host without the `harness` feature
|
|
53
|
+
lists `runtimes` instead.
|
|
51
54
|
- `remote` is the routed surface: the commands `--server <id>` sends to a
|
|
52
55
|
registered server, plus `roster`. The Desktop checks the execution host's
|
|
53
|
-
probe before a routed mutation.
|
|
56
|
+
probe before a routed mutation. From 0.31: `readiness`, `instance-events`,
|
|
57
|
+
`instance-git` and `lifecycle-plans` name the
|
|
58
|
+
[routed reads and plans](#routed-reads-and-plans).
|
|
54
59
|
- In text mode the command prints `@awebai/oats <version> (desktop API v1)`.
|
|
55
60
|
|
|
56
61
|
### Features
|
|
@@ -149,6 +154,20 @@ string for this: to support older kernels, use the spaced form.
|
|
|
149
154
|
| `E_LOCAL_MISSING` | No `oats-local.yaml` in reach of `--dir` or the working directory |
|
|
150
155
|
| `E_UNSUPPORTED_MODE` | A home or selector the kernel no longer runs (below) |
|
|
151
156
|
|
|
157
|
+
<a id="ssh-failures-e_ssh"></a>
|
|
158
|
+
### ssh failures (`E_SSH`)
|
|
159
|
+
|
|
160
|
+
A routed command (`--server`, and `oats server check`) reports ssh's own
|
|
161
|
+
failure as `E_SSH`, message `ssh to <host> failed: …`:
|
|
162
|
+
|
|
163
|
+
- `error.details` is `{"sshStarted": false}` when ssh never started on this
|
|
164
|
+
machine (not installed, not executable): nothing reached the host, and
|
|
165
|
+
retrying cannot help.
|
|
166
|
+
- No `details`: ssh ran and the link failed (unreachable host, refused key,
|
|
167
|
+
lost connection, timeout); a retry may succeed.
|
|
168
|
+
|
|
169
|
+
(0.31.0; before it `E_SSH` never carried details.)
|
|
170
|
+
|
|
152
171
|
Capability dispatch inside a home uses the home's module copies; from a
|
|
153
172
|
deployment it resolves the module as `oats spawn --soul <x>` would and runs it
|
|
154
173
|
with the soul's merged payload. `oats <namespace> --help --json` answers
|
|
@@ -1157,6 +1176,9 @@ it to a temporary copy (`soulFetched: true`).
|
|
|
1157
1176
|
repeatable, `a.b=c` nests): a malformed pair is `E_BAD_ARGS`; a capability
|
|
1158
1177
|
the soul does not resolve is `E_CAPABILITY_MISSING {capability, soul,
|
|
1159
1178
|
modules}`.
|
|
1179
|
+
- Any other positional after the soul, or a flag spawn does not read, is
|
|
1180
|
+
`E_BAD_ARGS` naming the argument, before anything is resolved; a bare
|
|
1181
|
+
`key=value` is refused with the `--provider <capability> key=value` form.
|
|
1160
1182
|
|
|
1161
1183
|
### The decision
|
|
1162
1184
|
|
|
@@ -1204,8 +1226,8 @@ with `--expect-decision` records the key and decision in `instance.json`.
|
|
|
1204
1226
|
|
|
1205
1227
|
```json
|
|
1206
1228
|
{"instance":"rm-api","agent":"rm","home":"/w/agents/rm/instances/rm-api","work":"worktree","branch":"agents/rm-api","launched":true,"warnings":[],
|
|
1207
|
-
"tmux":{"session":"
|
|
1208
|
-
"spawnOrigin":"operator","attach":"tmux attach -t
|
|
1229
|
+
"tmux":{"session":"oats-agents","window":"rm-api"},"backend":"tmux","repo":"/w/agents-repo","harness":"pi","model":null,"parent":null,"sibling":null,"relation":null,
|
|
1230
|
+
"spawnOrigin":"operator","attach":"tmux attach -t oats-agents","decision":{"instance":"rm-api","revision":"c557d8ec9a272ba1c1739dc3"},"replayed":false,
|
|
1209
1231
|
"wake":{"requested":false,"saved":null,"error":null},"launchConfig":null,
|
|
1210
1232
|
"launch":{"version":2,"harness":"pi","launchConfig":null,"launchConfigSource":null,"executable":"/usr/local/bin/pi","executableDeclared":null,
|
|
1211
1233
|
"executableResolvedFrom":"PATH","args":[],"env":{},"model":null,"hooks":{"launch":{},"env":{},"contributions":[]},"prompt":{"kind":"task-file","file":"TASK.md"}}}
|
|
@@ -1214,10 +1236,11 @@ with `--expect-decision` records the key and decision in `instance.json`.
|
|
|
1214
1236
|
(`decision` is abridged: it is the full bound decision.)
|
|
1215
1237
|
|
|
1216
1238
|
- Always present: `instance, agent, home, work, branch, launched, warnings
|
|
1217
|
-
(array), tmux ({session, window} | null),
|
|
1239
|
+
(array), tmux ({session, window} | null), backend ("tmux"), repo, harness,
|
|
1240
|
+
model, parent,
|
|
1218
1241
|
sibling, relation, spawnOrigin (operator | instance), attach, launchConfig,
|
|
1219
1242
|
launch` (the redacted recipe).
|
|
1220
|
-
- When they apply: `
|
|
1243
|
+
- When they apply: `yolo`, `decision` and
|
|
1221
1244
|
`replayed` (bound apply), `wake` (keyed apply), `wakeSchedule` and
|
|
1222
1245
|
`wakeScheduleError` (a requested wake).
|
|
1223
1246
|
|
|
@@ -1239,7 +1262,7 @@ Feature `spawn-name`. `--name <slug>` is the exact name, with no prefix.
|
|
|
1239
1262
|
|
|
1240
1263
|
| Code | Details | When |
|
|
1241
1264
|
|---|---|---|
|
|
1242
|
-
| `E_USAGE`, `E_BAD_ARGS` | | no soul; bad, contradictory or
|
|
1265
|
+
| `E_USAGE`, `E_BAD_ARGS` | | no soul; bad, contradictory, removed or unknown flags; an argument after the soul |
|
|
1243
1266
|
| `E_LOCAL_MISSING`, `E_NO_DEPLOYMENT` | | no `oats-local.yaml`; no `agents/` root |
|
|
1244
1267
|
| `E_SOUL_UNKNOWN` | `{name, members, packages}` | no such soul, or not at `--agents-root` |
|
|
1245
1268
|
| `E_SOUL_AMBIGUOUS` | `{name, repos, qualified}` | several souls answer the bare name; use one of `qualified` |
|
|
@@ -1262,6 +1285,7 @@ Feature `spawn-name`. `--name <slug>` is the exact name, with no prefix.
|
|
|
1262
1285
|
| `E_PLACEMENT_TAKEN`, `E_IDEMPOTENCY_CONFLICT` | `{instance, home}` | |
|
|
1263
1286
|
| `E_SPAWN_INCOMPLETE` | `{instance, home, launched}` | |
|
|
1264
1287
|
| `E_LAUNCH_*`, `E_MODEL_UNKNOWN`, `E_UNSUPPORTED_HARNESS` | | the launch selection is refused |
|
|
1288
|
+
| `E_LAUNCH_SHIM` | | the home's `oats` (`<home>/.oats/bin/oats`) cannot be written; the spawn is rolled back |
|
|
1265
1289
|
| `E_SCHEDULE_INVALID` | | a bad wake (`--wake-json`, `--wake-file`, `--wake-*`) |
|
|
1266
1290
|
| `E_SPAWN_FAILED` | | anything else |
|
|
1267
1291
|
|
|
@@ -1293,7 +1317,7 @@ workspace-model fields (feature `instance-modules`):
|
|
|
1293
1317
|
```
|
|
1294
1318
|
|
|
1295
1319
|
Abridged: the record also carries the launch recipe and command,
|
|
1296
|
-
composition evidence, the capability runtime, the tmux
|
|
1320
|
+
composition evidence, the capability runtime, the tmux target,
|
|
1297
1321
|
lineage (`parentInstance`, `siblingInstance`, `relation`, `relativeTo`), and
|
|
1298
1322
|
the keyed-spawn fields `decision`, `spawnIdempotencyKey`, `spawnCompleted` and
|
|
1299
1323
|
`wake`; later starts add `restarts` and `restartCount`.
|
|
@@ -1350,8 +1374,13 @@ Not an envelope: `{root, agents, workspace?, problems?, warnings?}`.
|
|
|
1350
1374
|
description, dir, instances}`.
|
|
1351
1375
|
- **Instance rows**: the home's `instance.json` (launch recipe and command
|
|
1352
1376
|
redacted) plus `home` and `instance` (from the directory; a disagreeing
|
|
1353
|
-
claim is kept as `recordedHome`/`recordedInstance`), `running` (
|
|
1354
|
-
|
|
1377
|
+
claim is kept as `recordedHome`/`recordedInstance`), `running` (read from
|
|
1378
|
+
the row's recorded tmux socket and session, never the caller's `$TMUX`;
|
|
1379
|
+
`null` with `runtimeState: "unreachable"` and the tmux error as
|
|
1380
|
+
`runtimeError` when that server cannot be read; `null` for a home a
|
|
1381
|
+
Herdr-era kernel recorded, with `runtimeState: "unsupported"` and
|
|
1382
|
+
`runtimeError: "E_HERDR_REMOVED: …"`, the recorded `sessionTarget` staying
|
|
1383
|
+
in the row),
|
|
1355
1384
|
`identity` when a provider recorded one, `rollbackIncomplete` and
|
|
1356
1385
|
`retirePending` when present, and the Desktop facts below.
|
|
1357
1386
|
- **`modules`** becomes drift rows `{name, from, commit, current, status,
|
|
@@ -1375,6 +1404,82 @@ restart, else `createdAt` for a launched home, else `null`. `modelFrom` is
|
|
|
1375
1404
|
`"harness-default"`, or `null` for an older home. `identityAddress` is the
|
|
1376
1405
|
messaging identity's `address` (else `alias`), or `null`.
|
|
1377
1406
|
|
|
1407
|
+
<a id="the-remote-roster-oats-server-roster---json"></a>
|
|
1408
|
+
### The remote roster (`oats server roster --json`)
|
|
1409
|
+
|
|
1410
|
+
```text
|
|
1411
|
+
oats server roster [--server <id>] [--per-target <ms>] [--budget <ms>] --json
|
|
1412
|
+
```
|
|
1413
|
+
|
|
1414
|
+
An envelope; `result` is `{groups, bounds}` (remote `roster`,
|
|
1415
|
+
[servers.md](servers.md#the-roster-and-harvest)). One group per server id and
|
|
1416
|
+
route target:
|
|
1417
|
+
|
|
1418
|
+
```json
|
|
1419
|
+
{"id":"build:3f2a…","server":"build","label":"Build box","registrationPresent":true,
|
|
1420
|
+
"target":{"sshHost":"build-host","workspace":"/srv/team","oatsPath":"oats"},
|
|
1421
|
+
"probe":{"ok":true},"agentsRoot":"/srv/team/agents",
|
|
1422
|
+
"souls":[{"name":"dev","harness":"claude","work":"worktree","agentsRoot":"/srv/team/agents"}],
|
|
1423
|
+
"instances":[{"server":"build","instance":"dev-a","agent":"dev","home":"/srv/team/agents/dev/instances/dev-a",
|
|
1424
|
+
"agentsRoot":"/srv/team/agents","harness":"claude","backend":"tmux","tmux":{"session":"oats-agents","window":"dev-a"},
|
|
1425
|
+
"running":true,"identity":{"alias":"dev-a","address":"acme/dev-a"},"identityAddress":"acme/dev-a",
|
|
1426
|
+
"teams":[{"label":"default","team":"acme:team"}],"startedAt":"2026-09-29T10:00:00.000Z","createdAt":"2026-09-29T09:58:12.004Z",
|
|
1427
|
+
"model":"opus","runtimeState":null,"parentInstance":"lead","siblingInstance":null,"relation":"child","relativeTo":"lead",
|
|
1428
|
+
"spawnOrigin":"instance","retirePending":false,"rollbackIncomplete":false,
|
|
1429
|
+
"savedRoute":false,"addressable":true,"missingRemotely":false}],
|
|
1430
|
+
"retireFailures":[]}
|
|
1431
|
+
```
|
|
1432
|
+
|
|
1433
|
+
- **Instance rows** relay the host's own `status --json` row: `identity`,
|
|
1434
|
+
`identityAddress`, `teams`, `startedAt`, `createdAt`, `model`,
|
|
1435
|
+
`runtimeState`, `parentInstance`, `siblingInstance`, `relation`,
|
|
1436
|
+
`relativeTo` and `spawnOrigin` are always present, `null` when the host
|
|
1437
|
+
does not supply them (a host before 0.31, a fact it never recorded, or a
|
|
1438
|
+
saved route the host no longer lists). Nothing is derived on this side.
|
|
1439
|
+
- **`addressable`** (0.31): `true` for every row the host reports. Routed
|
|
1440
|
+
session and lifecycle commands reach it by `--home`, or by name when the
|
|
1441
|
+
name is unique on the host ([addressing](servers.md#run-there); a shared
|
|
1442
|
+
name is `E_AMBIGUOUS` with `error.details.candidates: [{agent, home}]`). A
|
|
1443
|
+
saved-route row the host did not list is addressable only while the host's
|
|
1444
|
+
answer is unknown (`missingRemotely: false`).
|
|
1445
|
+
- **`savedRoute`**: the instance was spawned from this machine and has a
|
|
1446
|
+
saved route here. Information only; no action depends on it.
|
|
1447
|
+
- `running` is `null` when unknown; `backend` is `tmux` for a row with a tmux
|
|
1448
|
+
target, else `null`; `tmux`, `sessionTarget` (the recorded target of a home
|
|
1449
|
+
a Herdr-era kernel opened) and `runtimeError` are as the host reports them.
|
|
1450
|
+
|
|
1451
|
+
<a id="routed-reads-and-plans"></a>
|
|
1452
|
+
### Routed reads and plans (`--server`, 0.31)
|
|
1453
|
+
|
|
1454
|
+
The Desktop's per-instance reads and the lifecycle plans run on the
|
|
1455
|
+
instance's own machine: the local command, with `--server <id>` added.
|
|
1456
|
+
|
|
1457
|
+
| Command | `remote` entry | The host must advertise |
|
|
1458
|
+
|---|---|---|
|
|
1459
|
+
| `oats readiness --server <id> (--home <abs> \| --soul <n>) …` | `readiness` | `readiness`, `readinessApi: 2` |
|
|
1460
|
+
| `oats instance events <name> --server <id> …` | `instance-events` | `instance-events-2`, `eventsApi: 2` |
|
|
1461
|
+
| `oats instance git\|diff <name> --server <id> …` | `instance-git` | `instance-git`, `instanceGitApi: 1` |
|
|
1462
|
+
| `oats instance stop <name> --server <id> (--plan \| --apply …)` | `lifecycle-plans` | `lifecycle-plans`, `lifecycleApi: 1` |
|
|
1463
|
+
| `oats retire <name> --server <id> --plan`, and the guarded apply (`--plan-revision`, `--idempotency-key`) | `lifecycle-plans` | `lifecycle-plans`, `lifecycleApi: 1` |
|
|
1464
|
+
|
|
1465
|
+
- The flags are the local command's. The instance is addressed like every
|
|
1466
|
+
routed instance command ([servers.md](servers.md#run-there)): `--home` as
|
|
1467
|
+
given, else the name through its saved route or the host's roster, sent
|
|
1468
|
+
as `--home`. `--dir` names a directory on the host and travels as is;
|
|
1469
|
+
without it the registered workspace is sent (not for `readiness --home`,
|
|
1470
|
+
whose home is its own context). A retire plan and its guarded apply take
|
|
1471
|
+
`--dir` like the rest; an unguarded `retire --server` refuses it.
|
|
1472
|
+
- An instance with a saved route is reached through it, registration or not.
|
|
1473
|
+
A guarded retire apply whose name the host no longer lists is sent by name,
|
|
1474
|
+
so a repeated key gets the host's recorded receipt (or its refusal).
|
|
1475
|
+
- The host's envelope is relayed unchanged, success or failure: the same
|
|
1476
|
+
document the local command answers, with no routing keys added. The
|
|
1477
|
+
guarded retire apply is the routed `retire`, whose result carries
|
|
1478
|
+
`server` and `target` as before.
|
|
1479
|
+
- A host that does not advertise the feature and API number is refused with
|
|
1480
|
+
`E_REMOTE_INCOMPATIBLE`, naming both and the host's version, before
|
|
1481
|
+
anything is sent. A name two homes share on the host is `E_AMBIGUOUS`.
|
|
1482
|
+
|
|
1378
1483
|
<a id="instance-git-state-oats-instance-gitdiff-instancegitapi-1-oats-0247"></a>
|
|
1379
1484
|
## Git and diff
|
|
1380
1485
|
|
|
@@ -1670,8 +1775,9 @@ selection flags. See [the start workflow](desktop-instance-start.md).
|
|
|
1670
1775
|
- A lost response does not mean the launch failed: check status before a
|
|
1671
1776
|
retry. A remote home's saved route names its execution host.
|
|
1672
1777
|
- Errors: `E_BAD_ARGS`, `E_SESSION_UNKNOWN`, `E_UNSUPPORTED_MODE`,
|
|
1673
|
-
`E_SESSION_START_BUSY`, `E_INSTANCE_RETIRING`, `E_LAUNCH_
|
|
1674
|
-
`
|
|
1778
|
+
`E_SESSION_START_BUSY`, `E_INSTANCE_RETIRING`, `E_LAUNCH_*` (among them
|
|
1779
|
+
`E_LAUNCH_SHIM`: the home's `oats` link cannot be written, nothing was
|
|
1780
|
+
started), `E_MODEL_UNKNOWN`, `E_UNSUPPORTED_HARNESS`, `E_SESSION_FAILED`.
|
|
1675
1781
|
|
|
1676
1782
|
### Upload
|
|
1677
1783
|
|
|
@@ -67,4 +67,6 @@ before launch. Desktop does not scaffold a home or execute a launcher itself.
|
|
|
67
67
|
Status collection reads each instance's recorded tmux socket and session,
|
|
68
68
|
with one query per socket per collection. A launcher shell with a harness
|
|
69
69
|
child remains running; a fallback shell or dead pane is stopped. Errors that
|
|
70
|
-
prevent a reliable observation remain unknown.
|
|
70
|
+
prevent a reliable observation remain unknown. A row that records a Herdr
|
|
71
|
+
target (Herdr was removed in 0.31.0) is never observed: it shows the kernel's
|
|
72
|
+
`E_HERDR_REMOVED` text, and Open and Start are disabled.
|
package/docs/desktop.md
CHANGED
|
@@ -110,6 +110,26 @@ registered remote workspace the timer and definitions live on that server, so
|
|
|
110
110
|
they do not depend on the Mac staying awake. See [Schedules](schedules.md) for
|
|
111
111
|
the CLI, cron semantics, observed outcomes and recovery commands.
|
|
112
112
|
|
|
113
|
+
## Remote terminals
|
|
114
|
+
|
|
115
|
+
A terminal for an instance on a registered server is a viewer over ssh
|
|
116
|
+
(`oats session attach --server`). When the link dies, ssh ends the viewer with
|
|
117
|
+
exit 255 within about a minute, and the tab reconnects by itself. It keeps its
|
|
118
|
+
place and scrollback, stops taking input, and shows "Disconnected from
|
|
119
|
+
<server>" with a countdown and a **Reconnect now** button. Attempts wait 1, 2,
|
|
120
|
+
4, 8 and 15 s, then 30 s each for as long as the tab is open. A successful
|
|
121
|
+
attach resets that. Tmux redraws the screen when the viewer attaches again.
|
|
122
|
+
|
|
123
|
+
Reconnecting stops, with a message and "Close this tab", when the server
|
|
124
|
+
answers that the session is gone, the instance is unknown, the terminal limit
|
|
125
|
+
is reached or the app's backend changed, and at once when ssh cannot be run on
|
|
126
|
+
this computer. It stops after four attempts in a
|
|
127
|
+
row in which OATS on this computer gave no answer, since that is more likely
|
|
128
|
+
the local CLI failing than the link. It also stops when the viewer ends with
|
|
129
|
+
any other exit code. Closing the tab ends the reconnecting. Reconnecting
|
|
130
|
+
never stops or restarts the agent on the server: only the local ssh viewer
|
|
131
|
+
ends.
|
|
132
|
+
|
|
113
133
|
## Attach files and screenshots
|
|
114
134
|
|
|
115
135
|
Drop a file onto an agent terminal to insert its path into that agent's draft.
|
|
@@ -35,33 +35,56 @@ variables point at are described in
|
|
|
35
35
|
|
|
36
36
|
## Backends
|
|
37
37
|
|
|
38
|
-
`oats spawn --backend tmux
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
tmux is the only session backend. `oats spawn --backend tmux` is accepted (it
|
|
39
|
+
is the default); `tmux` must be installed on the execution host. A launched
|
|
40
|
+
home keeps the session it recorded: `session start` and `restart` never
|
|
41
|
+
re-read the defaults. The session target is recorded twice: in
|
|
42
|
+
`instance.json` and in an independent lifecycle receipt. Every session command
|
|
43
|
+
checks that the two agree (`E_RUNTIME_AUTHORITY_MISMATCH` otherwise).
|
|
43
44
|
|
|
44
45
|
### tmux
|
|
45
46
|
|
|
46
|
-
Each instance is a window named after the instance in
|
|
47
|
-
|
|
47
|
+
Each instance is a window named after the instance in a tmux session: the
|
|
48
|
+
deployment's `session.tmuxSession`, else `OATS_TMUX_SESSION`, else
|
|
49
|
+
`PI_AGENTS_TMUX_SESSION` (the pre-0.31 variable), else `oats-agents`. Before
|
|
50
|
+
0.31 the default was `pi-agents`; a home launched then keeps the `pi-agents`
|
|
51
|
+
session it recorded, and `oats status` reads each home on its recorded tmux
|
|
52
|
+
socket and session, never the caller's `$TMUX` server: a caller outside the
|
|
53
|
+
agents' tmux (ssh, cron, a plain terminal) sees the same liveness as `session
|
|
54
|
+
inspect`. A recorded server that cannot be read gives `running: null` with
|
|
55
|
+
`runtimeState: "unreachable"`. The environment variables are read when the spawn runs, and `oats
|
|
56
|
+
inspect --json` reports the session a new spawn would open in as `session`
|
|
57
|
+
(`{tmuxSession}`). A spawn refuses an instance name that is a live window in the
|
|
58
|
+
session it would open in (`E_INSTANCE_NAME_TAKEN`); a live window of that name
|
|
59
|
+
in another session, such as a `pi-agents` window after the default moved, does
|
|
60
|
+
not block it. Session commands target each home's exact recorded window, so
|
|
61
|
+
the two never mix. The receipt records the
|
|
48
62
|
session, window and socket. The spawn result prints the attach command.
|
|
49
63
|
|
|
50
|
-
### Herdr
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
64
|
+
### Herdr (removed in 0.31.0)
|
|
65
|
+
|
|
66
|
+
OATS no longer supports Herdr. Everything that meets it refuses with
|
|
67
|
+
`E_HERDR_REMOVED`, whose message starts `Herdr is no longer supported by OATS
|
|
68
|
+
(removed in 0.31.0); tmux is the only session backend.` and says what to do:
|
|
69
|
+
|
|
70
|
+
- `oats spawn --backend herdr` or `--herdr-socket`, local or routed with
|
|
71
|
+
`--server` (refused before the server is contacted), and `oats server add
|
|
72
|
+
--herdr`: remove the flag, or use tmux.
|
|
73
|
+
- A schedule's `backend: herdr` or a trigger's `spawn.backend: herdr`: the
|
|
74
|
+
message names the file and key; remove it, or use tmux. A stored local job
|
|
75
|
+
that names it is reported invalid and never runs.
|
|
76
|
+
- `session inspect`, `attach`, `input`, `start`, `restart` and `instance stop`
|
|
77
|
+
on a home a Herdr-era kernel recorded (its `instance.json` records a
|
|
78
|
+
`sessionTarget` or `backend: "herdr"`, or its receipt records a session
|
|
79
|
+
target): retire it and spawn a new instance, which opens in tmux.
|
|
80
|
+
- `oats retire` of such a home needs no Herdr: when no process works in the
|
|
81
|
+
home it proceeds as for an absent session; when one does, it refuses and
|
|
82
|
+
names the pids, so stop its Herdr pane first (for example `herdr --session
|
|
83
|
+
oats server stop`).
|
|
84
|
+
|
|
85
|
+
`oats status` lists such a home with `running: null`, `runtimeState:
|
|
86
|
+
"unsupported"` and the refusal as `runtimeError`. A server registration or
|
|
87
|
+
saved route that records `herdrPath` still loads; the field is ignored.
|
|
65
88
|
|
|
66
89
|
## Lifecycle
|
|
67
90
|
|
|
@@ -77,8 +100,8 @@ id distinguishes a replacement occupant of the same pane.
|
|
|
77
100
|
|
|
78
101
|
`session start` keeps the instance's identity, work tree and notes. It runs no
|
|
79
102
|
spawn hooks and creates no new home. It runs the recorded launch recipe on the
|
|
80
|
-
recorded tmux session
|
|
81
|
-
|
|
103
|
+
recorded tmux session; a `--no-launch` home starts on the default tmux
|
|
104
|
+
server.
|
|
82
105
|
|
|
83
106
|
- `--model`, `--launch-config <name>|none`, `--harness` and `--yolo` /
|
|
84
107
|
`--no-yolo` re-resolve the recipe against the home's recorded context and
|
|
@@ -112,18 +135,18 @@ oats session input --home /abs/home --text-file message.txt --json
|
|
|
112
135
|
oats session attach --home /abs/home
|
|
113
136
|
```
|
|
114
137
|
|
|
115
|
-
- **inspect** reports `backend`, `present` and `state`:
|
|
116
|
-
|
|
138
|
+
- **inspect** reports `backend`, `present` and `state`: `unknown` for a live
|
|
139
|
+
harness, `shell` for a fallback shell,
|
|
117
140
|
`stopped` for an absent or dead terminal, or `not-launched`. An unavailable
|
|
118
141
|
backend is an error (`E_SESSION_UNAVAILABLE`), never a stopped result.
|
|
119
142
|
- **input** submits UTF-8 text (stdin or `--text-file`, at most 256 KiB, no
|
|
120
|
-
NUL) followed by Enter
|
|
121
|
-
|
|
143
|
+
NUL) followed by Enter, as a bracketed paste. The text is never run by a
|
|
144
|
+
shell. A fallback shell, a stopped session or a split
|
|
122
145
|
tmux window is refused. `submitted: true` means the terminal accepted the
|
|
123
146
|
text, not that the agent processed it. Wake schedules and messaging
|
|
124
147
|
capabilities use this command ([schedules.md](schedules.md)).
|
|
125
|
-
- **attach** is interactive and takes no `--json`. It opens a
|
|
126
|
-
|
|
148
|
+
- **attach** is interactive and takes no `--json`. It opens a temporary tmux
|
|
149
|
+
session linked to the agent's window alone.
|
|
127
150
|
Closing the viewer leaves the agent running.
|
|
128
151
|
|
|
129
152
|
### Attachments
|
package/docs/implementation.md
CHANGED
|
@@ -54,7 +54,7 @@ published to npm. Its developer docs are in
|
|
|
54
54
|
| `schedule.mjs`, `schedule-host.mjs`, `triggers.mjs`, `automations.mjs` | schedules, triggers and the host timer |
|
|
55
55
|
| `operator-dispatch.mjs` | capability commands run from a deployment, and its module store |
|
|
56
56
|
| `instance-*.mjs` | inspection, lifecycle, events and Git views of an instance |
|
|
57
|
-
| `
|
|
57
|
+
| `tmux-config.mjs`, `session-*.mjs` | the tmux session backend and terminal input |
|
|
58
58
|
| `capability-contract.mjs`, `provider-binding.mjs` | manifest validation, the hook environment rules, the readiness wire |
|
|
59
59
|
| `servers.mjs` | routing commands to a registered server |
|
|
60
60
|
|
package/docs/integrations.md
CHANGED
|
@@ -64,6 +64,14 @@
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
},
|
|
67
|
+
"session": {
|
|
68
|
+
"type": "object",
|
|
69
|
+
"additionalProperties": false,
|
|
70
|
+
"description": "This host's terminal session defaults for NEW launches (0.31). A launched home keeps the session it recorded.",
|
|
71
|
+
"properties": {
|
|
72
|
+
"tmuxSession": { "type": "string", "pattern": "^[A-Za-z0-9_-]{1,64}$", "description": "The tmux session new tmux instances open their windows in. Absent: OATS_TMUX_SESSION, else PI_AGENTS_TMUX_SESSION (pre-0.31), else oats-agents." }
|
|
73
|
+
}
|
|
74
|
+
},
|
|
67
75
|
"host": {
|
|
68
76
|
"type": "object",
|
|
69
77
|
"additionalProperties": false,
|
package/docs/official-catalog.md
CHANGED
|
@@ -11,7 +11,7 @@ or workspace membership alone does not make a package official.
|
|
|
11
11
|
|---|---|---|---|
|
|
12
12
|
| `oats.framework` | `oats-framework/v1.4.1` (this repository) | `oats.core`, `oats.setup`, `oats.knowledge-theory` | `knowledge-theory-expert` |
|
|
13
13
|
| `oats.okf` | `v4.0.5` | `oats.okf` (knowledge), `oats.okf-harvest`, `oats.okf-maintenance` | `knowledge-harvester`, `knowledge-maintainer` |
|
|
14
|
-
| `oats.aweb` | `v1.17.
|
|
14
|
+
| `oats.aweb` | `v1.17.3` | `oats.aweb` (messaging) | |
|
|
15
15
|
| `oats.engineering` | `v1.3.0` | `oats.engineering-expert`, `oats.developer`, `oats.code-review` | `code-reviewer` |
|
|
16
16
|
| `oats.authoring` | `v1.0.3` | `oats.authoring` | |
|
|
17
17
|
| `oats.jira` | `v1.0.1` | `oats.jira` (tasks) | |
|
package/docs/packages.md
CHANGED
|
@@ -76,7 +76,7 @@ members:
|
|
|
76
76
|
packages:
|
|
77
77
|
oats.framework: v1.4.1
|
|
78
78
|
oats.okf: v4.0.5
|
|
79
|
-
oats.aweb: v1.17.
|
|
79
|
+
oats.aweb: v1.17.3
|
|
80
80
|
teams:
|
|
81
81
|
platform: { team: "platform:acme.aweb.ai", description: Platform engineering }
|
|
82
82
|
defaults:
|
|
@@ -134,7 +134,7 @@ Declaring a package in the workspace's `packages:` is the trust decision
|
|
|
134
134
|
## `oats package add | remove`
|
|
135
135
|
|
|
136
136
|
```bash
|
|
137
|
-
oats package add oats.aweb v1.17.
|
|
137
|
+
oats package add oats.aweb v1.17.3 # a catalog version
|
|
138
138
|
oats package add acme.tools git:github.com/acme/tools@v0.4.0
|
|
139
139
|
oats package remove acme.tools
|
|
140
140
|
```
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# OATS 0.30.3
|
|
2
|
+
|
|
3
|
+
## Changed
|
|
4
|
+
|
|
5
|
+
- **Desktop: the whole app works from the keyboard, with a Linux-sane keymap.**
|
|
6
|
+
Changed Linux and Windows defaults: the command palette is now Ctrl+Shift+P
|
|
7
|
+
on Linux and Windows; close tab Ctrl+Shift+W; split Ctrl+Shift+E /
|
|
8
|
+
Ctrl+Shift+O (close the split Ctrl+Shift+Alt+W); Spawn instance
|
|
9
|
+
Ctrl+Shift+N; the theme cycle has no default chord (on macOS too; the palette
|
|
10
|
+
keeps it). No default chord takes a key a program in the terminal reads:
|
|
11
|
+
plain Ctrl+W, Ctrl+K, Ctrl+\, Ctrl+P and Ctrl+B, F6, Alt+digit and
|
|
12
|
+
Ctrl+PgUp/PgDn (and ⌃digits on macOS) always reach the program, and nothing
|
|
13
|
+
binds Super. New: go to tab (⌥⌘1–⌥⌘9 / Alt+1–Alt+9), Ctrl+PgDn / Ctrl+PgUp,
|
|
14
|
+
⌘3 / Ctrl+3 for Automations, and F6 / Shift+F6 to move between the sidebar,
|
|
15
|
+
the instances, the main area and the instance panel; from a terminal,
|
|
16
|
+
⇧⌘F6 / Ctrl+Shift+F6 leaves it for the next region. Your own rebinds are
|
|
17
|
+
kept; one that now clashes with another shortcut is flagged in the shortcuts
|
|
18
|
+
editor, never changed for you. Quick Open (⌘P / Ctrl+P)
|
|
19
|
+
now opens the spawn dialog for the soul you pick, and Esc takes you back to
|
|
20
|
+
where you were; ⌘↵ / Ctrl+Enter spawns from any field, and Tab walks the
|
|
21
|
+
form in the order you see it. Keyboard gaps found in an audit are closed:
|
|
22
|
+
roster rows of unknown state, Independent nodes in the Active overview, the
|
|
23
|
+
Automations row menu, the schedule form and focus lost after switching tabs
|
|
24
|
+
or views. The keymap and the audit are in
|
|
25
|
+
`packages/desktop/docs/desktop-keyboard.md`.
|
|
26
|
+
- **Desktop: the spawn dialog says why each capability is there.** In "What
|
|
27
|
+
will be created", each Capabilities row shows a muted reason tag beside its
|
|
28
|
+
source: **Soul**, **Workspace default**, or, for a workspace default that
|
|
29
|
+
fills a core slot, **Workspace default · messaging** (knowledge, messaging or
|
|
30
|
+
tasks). It is the preview's `composedFrom`, read only from a CLI that reports
|
|
31
|
+
`preview-composed-from`; with an older CLI the rows show no tag, never a
|
|
32
|
+
guess. The Core capabilities table is unchanged.
|
|
33
|
+
- **Desktop: clearer overview lines, a centred rail, pinned Workspace controls.**
|
|
34
|
+
The Active overview draws parent links as smooth curves from a parent's
|
|
35
|
+
bottom to its child's top, with dashed arcs between siblings, in a colour
|
|
36
|
+
that is visible in every theme. The collapsed instance panel's icons sit
|
|
37
|
+
on its centre line. In Workspace, the Capabilities section pills and search
|
|
38
|
+
and the Teams header stay in view while the content scrolls, and scrolling
|
|
39
|
+
to the end of a list no longer moves the whole window.
|
|
40
|
+
|
|
41
|
+
## Fixes
|
|
42
|
+
|
|
43
|
+
- **Plain `oats` inside an instance is the kernel that launched it.** On a
|
|
44
|
+
machine with two kernels side by side (a global 0.24 for classic
|
|
45
|
+
deployments and a 0.30 prefix install), an agent typing `oats` got whatever
|
|
46
|
+
`PATH` found first: `oats aweb teams` answered `E_UNKNOWN_COMMAND` in a 0.30
|
|
47
|
+
home. Every launch (spawn, `session start`, `session restart`) now writes
|
|
48
|
+
`<home>/.oats/bin/oats`, a link to the launching kernel, and runs the harness
|
|
49
|
+
with `<home>/.oats/bin` first on `PATH`. A restart by another kernel
|
|
50
|
+
re-points it. The recipe records the target as `launch.kernelBin`, and
|
|
51
|
+
`oats status` shows it (`kernel:`) when it is not the running `oats`. A
|
|
52
|
+
launch that cannot write the link fails with `E_LAUNCH_SHIM`. Existing homes
|
|
53
|
+
get the link at their next start or restart.
|
|
54
|
+
- **`oats spawn` refuses an argument it does not read.** A positional after
|
|
55
|
+
the soul, or a flag spawn does not know, is `E_BAD_ARGS` naming it, before
|
|
56
|
+
anything is resolved or created. `oats spawn <soul> join=oats` used to be
|
|
57
|
+
accepted and the bare `join=oats` ignored, so the instance joined nothing;
|
|
58
|
+
the refusal now names the form that was meant, `--provider <capability>
|
|
59
|
+
key=value`. A routed spawn (`--server`) is refused on this machine, before
|
|
60
|
+
the server is contacted.
|
|
61
|
+
- **Herdr 0.9 spawns work.** A new Herdr session was always opened at protocol
|
|
62
|
+
20, so `oats spawn --backend herdr` against Herdr 0.9, which speaks protocol
|
|
63
|
+
22, failed with "Herdr snapshot does not match selected protocol 20". A new
|
|
64
|
+
session now records the protocol its server reports when it is one OATS
|
|
65
|
+
supports (20 or 22), and refuses any other by name. A recorded session is
|
|
66
|
+
still checked against its recorded protocol on every call and is never
|
|
67
|
+
renegotiated. The Desktop attaches to protocol-22 sessions too; it accepted
|
|
68
|
+
only protocol 20 before. An instance recorded at protocol 20 is unreachable
|
|
69
|
+
after an in-place Herdr 0.8 → 0.9 upgrade until it is respawned.
|
|
70
|
+
- **A Herdr launch no longer arrives cut.** OATS typed the launch command into
|
|
71
|
+
the new pane before its shell had started. The terminal's line buffer
|
|
72
|
+
(1024 bytes on macOS) dropped the rest of the longer command, so the harness
|
|
73
|
+
never started: the shell waited on an unclosed quote. On Herdr 0.9, 0 of 5
|
|
74
|
+
fresh panes ran a 2000-character command intact. A launch now waits, up to
|
|
75
|
+
10 s, until the pane has drawn its prompt, then types; 5 of 5 ran intact.
|