@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.
@@ -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","herdr"],"launchOptions":["yolo"],
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. A host without the `harness` feature lists `runtimes` instead.
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":"pi-agents","window":"rm-api"},"repo":"/w/agents-repo","harness":"pi","model":null,"parent":null,"sibling":null,"relation":null,
1208
- "spawnOrigin":"operator","attach":"tmux attach -t pi-agents","decision":{"instance":"rm-api","revision":"c557d8ec9a272ba1c1739dc3"},"replayed":false,
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), repo, harness, model, parent,
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: `sessionTarget` (Herdr), `yolo`, `decision` and
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 removed flags |
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 or Herdr target,
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` (`null` when
1354
- a Herdr session is unreachable, with `runtimeState`/`runtimeError`),
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
- `E_MODEL_UNKNOWN`, `E_UNSUPPORTED_HARNESS`, `E_SESSION_FAILED`.
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. Herdr uses its saved target.
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|herdr` chooses the backend (default `tmux`). The
39
- backend binary must be installed on the execution host. The chosen session
40
- target is recorded twice: in `instance.json` and in an independent lifecycle
41
- receipt. Every session command checks that the two agree
42
- (`E_RUNTIME_AUTHORITY_MISMATCH` otherwise).
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 the tmux session
47
- `pi-agents` (override with `PI_AGENTS_TMUX_SESSION`). The receipt records the
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
- Each instance is a Herdr workspace with one pane. The receipt records the
53
- binary, socket, workspace id, pane id, terminal id and protocol. The terminal
54
- id distinguishes a replacement occupant of the same pane.
55
-
56
- - `--herdr-socket <path>` uses an operator-managed Herdr server. OATS never
57
- starts a different server when that socket cannot be inspected.
58
- - Without it, OATS uses `$XDG_CONFIG_HOME/herdr/sessions/oats/herdr.sock`
59
- (default `~/.config/...`) and starts `herdr --session oats server` if no
60
- server is running there.
61
- - The adapter speaks the Herdr socket API at an explicit protocol version,
62
- with no negotiation. New sessions use protocol 20. A recorded session target
63
- may carry protocol 20 or 22, and each call checks that the server's snapshot
64
- reports the recorded protocol.
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 or Herdr server; a `--no-launch` home starts on the
81
- default tmux server.
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`: the Herdr agent state
116
- when available, `unknown` for a live harness, `shell` for a fallback shell,
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: bracketed paste in tmux, `pane run` in Herdr. The
121
- text is never run by a shell. A fallback shell, a stopped session or a split
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 Herdr terminal
126
- viewer, or a temporary tmux session linked to the agent's window alone.
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
@@ -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
- | `herdr.mjs`, `tmux-config.mjs`, `session-*.mjs` | session backends and terminal input |
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
 
@@ -41,7 +41,7 @@ arrives from.
41
41
  # oats-workspace.yaml: one default per slot, for every soul
42
42
  packages:
43
43
  oats.okf: v4.0.5
44
- oats.aweb: v1.17.1
44
+ oats.aweb: v1.17.3
45
45
  oats.linear: v1.0.1
46
46
  oats.jira: v1.0.1
47
47
  defaults:
@@ -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,
@@ -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.1` | `oats.aweb` (messaging) | |
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.1
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.1 # a catalog version
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.