@awebai/oats 0.30.3 → 0.32.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 +216 -79
- package/docs/configuration.md +68 -8
- package/docs/desktop-cli-api.md +233 -27
- package/docs/desktop-instance-start.md +3 -1
- package/docs/desktop.md +36 -0
- package/docs/execution-targets.md +53 -36
- package/docs/implementation.md +59 -1
- package/docs/integrations.md +1 -1
- package/docs/oats-local.schema.json +10 -1
- package/docs/official-catalog.md +1 -1
- package/docs/packages.md +2 -2
- package/docs/plans/0.30-close-out.md +7 -4
- package/docs/release-notes/v0.31.0.md +130 -0
- package/docs/release-notes/v0.32.0.md +137 -0
- package/docs/schedules.md +4 -1
- package/docs/servers.md +94 -25
- package/docs/souls-and-instances.md +2 -2
- package/lib/attachments.mjs +2 -1
- package/lib/automations.mjs +5 -1
- package/lib/core.mjs +241 -238
- package/lib/errors.mjs +17 -0
- package/lib/instance-inspect.mjs +13 -4
- package/lib/instance-resolution.mjs +3 -3
- package/lib/local-inputs.mjs +46 -0
- package/lib/materialize.mjs +3 -2
- package/lib/packages.mjs +26 -6
- package/lib/remote.mjs +792 -36
- package/lib/resolve.mjs +23 -7
- package/lib/schedule.mjs +21 -8
- package/lib/servers.mjs +272 -45
- package/lib/session-input.mjs +9 -23
- package/lib/session-viewer.mjs +0 -5
- package/lib/triggers.mjs +10 -8
- package/lib/workspace.mjs +163 -56
- package/package-catalog.json +1 -1
- package/package.json +1 -1
- package/lib/herdr.mjs +0 -143
package/docs/configuration.md
CHANGED
|
@@ -34,6 +34,8 @@ souls:
|
|
|
34
34
|
|
|
35
35
|
host:
|
|
36
36
|
name: ana-laptop # which workspace triggers and schedules run here
|
|
37
|
+
session: # terminal defaults for NEW launches on this host (0.31)
|
|
38
|
+
tmuxSession: oats-agents # the tmux session new tmux instances open in
|
|
37
39
|
triggers:
|
|
38
40
|
disabled: [platform/nightly-review]
|
|
39
41
|
schedules:
|
|
@@ -48,6 +50,11 @@ launch-configs: # named ways this host starts a har
|
|
|
48
50
|
CLAUDE_CONFIG_DIR: { fromEnv: PERSONAL_CLAUDE_DIR }
|
|
49
51
|
model: opus
|
|
50
52
|
yolo: false
|
|
53
|
+
mine:
|
|
54
|
+
harness: claude
|
|
55
|
+
default: true # this host's baseline for every claude launch (0.32)
|
|
56
|
+
env:
|
|
57
|
+
CLAUDE_CONFIG_DIR: /home/ana/.claude-personal
|
|
51
58
|
```
|
|
52
59
|
|
|
53
60
|
Schema: [`oats-local.schema.json`](oats-local.schema.json). Unknown keys are
|
|
@@ -64,10 +71,11 @@ refused (`E_WORKSPACE_SCHEMA`).
|
|
|
64
71
|
| `souls.teams` | Which teams each soul joins here: `"*"` applies to every soul; a soul's own entry (its name, or `<package>/<soul>`) adds to it. Every soul is also in its default team. Written by `oats soul teams <soul>\|'*' --add … --remove …`. |
|
|
65
72
|
| `souls.default` | A per-soul override of `defaultTeam`; it must be one of that soul's teams here (`E_TEAM_NOT_ELIGIBLE`). Written by `oats soul teams <soul> --default <label>`. |
|
|
66
73
|
| `souls.disabled` | Souls not run on this machine; a spawn is refused with `E_SOUL_DISABLED`. A bare name disables every soul of that name; `<package>/<soul>` or `<member>/<soul>` disables one. |
|
|
74
|
+
| `session.tmuxSession` | The tmux session new tmux instances open their windows in (0.31). Absent: `OATS_TMUX_SESSION`, else `PI_AGENTS_TMUX_SESSION` (the pre-0.31 variable), else `oats-agents`. `session: { tmuxSession: pi-agents }` keeps the pre-0.31 layout. `oats inspect --json` reports it as `session`. |
|
|
67
75
|
| `host.name` | This machine's name. A workspace trigger or schedule runs only on the host named by its `runsOn` ([schedules.md](schedules.md)). |
|
|
68
76
|
| `automations.trust` | The workspace triggers and schedules (`<member>/<id>`) this host agrees to run, or `"*"` for every one the workspace places here (0.30). Absent or empty: none runs. See [Who runs workspace automations](#who-runs-workspace-automations). |
|
|
69
77
|
| `triggers.disabled`, `schedules.disabled` | Workspace triggers and schedules (`<member>/<id>`) this host does not run, without a commit. Written by `oats trigger disable` / `oats schedule disable`. |
|
|
70
|
-
| `launch-configs.<name>` | A named way to start a harness on this host, chosen at spawn or session start, never by the soul. See [Launch configurations](#launch-configurations). |
|
|
78
|
+
| `launch-configs.<name>` | A named way to start a harness on this host, chosen at spawn or session start, never by the soul. `default: true` makes it this host's baseline for its harness (0.32). See [Launch configurations](#launch-configurations). |
|
|
71
79
|
| `souls.launch` | This machine's launch preference per soul (0.30): `"*"` for every soul, a soul's own entry (its name, or `<package>/<soul>`) over it. A value is a `launch-configs` name or an inline `{ harness, model? }`. It overrides the soul's own `launch:`; explicit spawn flags win over both. See [Launch preferences](#launch-preferences). |
|
|
72
80
|
|
|
73
81
|
How teams are resolved, and what a messaging provider does with them, is in
|
|
@@ -78,8 +86,9 @@ How teams are resolved, and what a messaging provider does with them, is in
|
|
|
78
86
|
An entry has `harness` (`pi` \| `claude` \| `codex`, required), `executable`
|
|
79
87
|
(a bare name looked up on `PATH`, or a path relative to this deployment
|
|
80
88
|
directory), `args` (literal, no shell), `env` (a literal string, or
|
|
81
|
-
`{ fromEnv: NAME }` resolved on the host at start), `model
|
|
82
|
-
|
|
89
|
+
`{ fromEnv: NAME }` resolved on the host at start), `model`, `yolo` and
|
|
90
|
+
`default` (0.32; see [the harness default](#the-harness-default)). A launch
|
|
91
|
+
configuration is a host choice: a soul never names one.
|
|
83
92
|
|
|
84
93
|
- Select one with `--launch-config <name>` on `oats spawn`,
|
|
85
94
|
`oats session start` and `oats session restart`. A named configuration is
|
|
@@ -101,6 +110,50 @@ launch configuration is a host choice: a soul never names one.
|
|
|
101
110
|
- The old key `runtime` is still read as `harness`, with a
|
|
102
111
|
`deprecated-runtime-name` warning.
|
|
103
112
|
|
|
113
|
+
### The harness default
|
|
114
|
+
|
|
115
|
+
`default: true` makes a configuration this host's baseline for its harness
|
|
116
|
+
(0.32, feature `launch-config-default`). Use it for what every launch of a
|
|
117
|
+
harness on this machine needs, whatever soul or preference chose it: an
|
|
118
|
+
account directory (`CLAUDE_CONFIG_DIR`), a wrapper `executable`, an argument.
|
|
119
|
+
|
|
120
|
+
- **When it applies:** a new launch that picks the harness without naming a
|
|
121
|
+
configuration: a soul's `launch:`, an inline `souls.launch` preference,
|
|
122
|
+
`--harness` (on a spawn, or on `session start|restart` of an existing
|
|
123
|
+
home), `--reselect-launch`, and the host default (`pi`). It supplies the
|
|
124
|
+
executable, args, env and `yolo`. A `yolo` recorded from a default stays
|
|
125
|
+
with it: a later `--launch-config none` or another harness does not carry
|
|
126
|
+
it over.
|
|
127
|
+
- **The model** comes from whatever picked the harness (`--model`, then the
|
|
128
|
+
preference); the default's `model` is the last fallback, before the
|
|
129
|
+
harness's own.
|
|
130
|
+
- **A named configuration runs as declared**: `--launch-config <name>` or a
|
|
131
|
+
`souls.launch` name never inherits from the default. `--launch-config none`
|
|
132
|
+
(or a `souls.launch` entry of `none`) asks for the bare harness and
|
|
133
|
+
bypasses it.
|
|
134
|
+
- **One per harness.** A second `default: true` for the same harness is
|
|
135
|
+
refused (`E_LAUNCH_CONFIG_INVALID`, naming both); move it by clearing the
|
|
136
|
+
old one first.
|
|
137
|
+
- **Existing homes keep their launch** until `--reselect-launch` or a
|
|
138
|
+
respawn, like any change of preference. Declaring a default is such a
|
|
139
|
+
change: `oats readiness --home` warns `launch-changed` on each existing
|
|
140
|
+
home the default would now apply to, until it is restarted with
|
|
141
|
+
`--reselect-launch` or respawned.
|
|
142
|
+
- **It is visible.** `oats launch-config list` marks it; `spawn --preview`,
|
|
143
|
+
`launch-config preview`, `instance.json` and `oats inspect --home` say when
|
|
144
|
+
a launch's configuration came from the default (`launchConfigDefault`).
|
|
145
|
+
A default with `yolo: true` turns yolo on for every launch of that harness
|
|
146
|
+
here: the preview shows it.
|
|
147
|
+
- **Every kernel that reads the deployment needs OATS 0.32+.** OATS 0.31
|
|
148
|
+
and older refuse the whole `oats-local.yaml` (`E_WORKSPACE_SCHEMA`) once a
|
|
149
|
+
configuration declares `default`.
|
|
150
|
+
|
|
151
|
+
`oats-claude-config` (a one-line file naming the claude binary, found walking
|
|
152
|
+
up from the deployment) is no longer read. A new claude launch with one in
|
|
153
|
+
reach is refused (`E_CLAUDE_CONFIG_REMOVED`) naming the file: declare the
|
|
154
|
+
name it holds as the claude default (`executable: <name>`, `default: true`)
|
|
155
|
+
and delete the file. Homes launched with it keep their recorded executable.
|
|
156
|
+
|
|
104
157
|
### Launch preferences
|
|
105
158
|
|
|
106
159
|
A soul says what its role should run on, and each machine may override it
|
|
@@ -125,9 +178,11 @@ souls:
|
|
|
125
178
|
harness and replaces only its model.
|
|
126
179
|
- A **launch configuration** name runs that configuration's full recipe. An
|
|
127
180
|
**inline or soul preference** runs its harness the way this host starts it
|
|
128
|
-
without a configuration
|
|
129
|
-
|
|
130
|
-
|
|
181
|
+
without a configuration: [the harness default](#the-harness-default) if
|
|
182
|
+
one is declared, else the executable on `PATH` with no args and no env,
|
|
183
|
+
with the preference's `model`. A preference without `model` uses the
|
|
184
|
+
harness default's model, else the harness's own; it never borrows a lower
|
|
185
|
+
layer's.
|
|
131
186
|
- **A missing harness is refused**, never replaced: `E_HARNESS_UNAVAILABLE`
|
|
132
187
|
names the layer that chose it and the fix (install the harness, or override
|
|
133
188
|
it here in `souls.launch`). `oats souls` still lists the soul, with the
|
|
@@ -271,5 +326,10 @@ oats spawn <soul> --preview # the exact modules, teams and provider payloads
|
|
|
271
326
|
oats doctor # this deployment's files and the lock
|
|
272
327
|
```
|
|
273
328
|
|
|
274
|
-
Environment: `OATS_REMOTE_CACHE` relocates the fetch cache
|
|
275
|
-
|
|
329
|
+
Environment: `OATS_REMOTE_CACHE` relocates the fetch cache (which also holds
|
|
330
|
+
the bounded parsed-read cache and the observations `--max-age` reuses; all of
|
|
331
|
+
it is safe to delete); `OATS_PACKAGE_CATALOG` names an alternative package
|
|
332
|
+
catalog file. The read verbs (`status`, `workspace status`, `souls`,
|
|
333
|
+
`capabilities`, `inspect`, and the read forms of `teams` and `soul teams`)
|
|
334
|
+
take `--max-age <seconds>` to reuse a remote head observed that recently
|
|
335
|
+
([Observation reuse](desktop-cli-api.md#observation-reuse-feature-observe-max-age-oats-0311)).
|
package/docs/desktop-cli-api.md
CHANGED
|
@@ -30,14 +30,15 @@ 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",
|
|
38
39
|
"workspace-v2","instance-modules","spawn-provider-payload","served-identity","packages-no-approval","spawn-name","settings-origins",
|
|
39
40
|
"team-model-2","settings-declared","capabilities-private","layers-from","harness","package-souls","triggers","automations","desktop-facts","launch-preference",
|
|
40
|
-
"preview-composed-from"],
|
|
41
|
+
"preview-composed-from","observe-max-age"],
|
|
41
42
|
"automationsApi":1,"workspaceApi":2,"instanceGitApi":1,"spawnApplyApi":1,"soulsApi":2,"lifecycleApi":1,
|
|
42
43
|
"readinessApi":2,"spawnPreviewApi":2,"eventsApi":2,"scheduleHistoryApi":3,"scheduleApi":2,"operationsApi":2}
|
|
43
44
|
```
|
|
@@ -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
|
|
@@ -90,6 +95,7 @@ canonical (`github.com/<org>/<repo>`, or `local/<abs-path>`). Examples use
|
|
|
90
95
|
| `desktop-facts` | the facts under [Desktop facts](#desktop-facts-feature-desktop-facts-oats-0290) | |
|
|
91
96
|
| `launch-preference` | soul and local launch preferences; `launch`, `launchCurrent`, `launchFrom`; `--reselect-launch`; `key` on soul and agent rows ([Launch preferences](#soul-launch-preferences-feature-launch-preference-oats-0300)) | |
|
|
92
97
|
| `preview-composed-from` | `composedFrom` on preview `modules[]` ([Composition](#the-preview)) | |
|
|
98
|
+
| `observe-max-age` | `--max-age <s>` on the read verbs and their `observation` block ([Observation reuse](#observation-reuse-feature-observe-max-age-oats-0311)) | |
|
|
93
99
|
|
|
94
100
|
Payload-only integers, never in the probe: `onboardApi: 2`, `syncApi: 1`,
|
|
95
101
|
`workspaceStatusApi: 1`, `capabilitiesApi: 1`, the `oats souls` document's
|
|
@@ -149,6 +155,20 @@ string for this: to support older kernels, use the spaced form.
|
|
|
149
155
|
| `E_LOCAL_MISSING` | No `oats-local.yaml` in reach of `--dir` or the working directory |
|
|
150
156
|
| `E_UNSUPPORTED_MODE` | A home or selector the kernel no longer runs (below) |
|
|
151
157
|
|
|
158
|
+
<a id="ssh-failures-e_ssh"></a>
|
|
159
|
+
### ssh failures (`E_SSH`)
|
|
160
|
+
|
|
161
|
+
A routed command (`--server`, and `oats server check`) reports ssh's own
|
|
162
|
+
failure as `E_SSH`, message `ssh to <host> failed: …`:
|
|
163
|
+
|
|
164
|
+
- `error.details` is `{"sshStarted": false}` when ssh never started on this
|
|
165
|
+
machine (not installed, not executable): nothing reached the host, and
|
|
166
|
+
retrying cannot help.
|
|
167
|
+
- No `details`: ssh ran and the link failed (unreachable host, refused key,
|
|
168
|
+
lost connection, timeout); a retry may succeed.
|
|
169
|
+
|
|
170
|
+
(0.31.0; before it `E_SSH` never carried details.)
|
|
171
|
+
|
|
152
172
|
Capability dispatch inside a home uses the home's module copies; from a
|
|
153
173
|
deployment it resolves the module as `oats spawn --soul <x>` would and runs it
|
|
154
174
|
with the soul's merged payload. `oats <namespace> --help --json` answers
|
|
@@ -162,6 +182,83 @@ an inherited `OATS_DEPLOYMENT` or `OATS_RESOLUTION` (`details.inherited`).
|
|
|
162
182
|
homes in `problems[]`: `legacy-captured-home {code, instances, homes,
|
|
163
183
|
message}` and `legacy-local-agents {code, dirs, instances, message}`.
|
|
164
184
|
|
|
185
|
+
<a id="observation-reuse-feature-observe-max-age-oats-0311"></a>
|
|
186
|
+
### Observation reuse (feature `observe-max-age`, OATS 0.32.0)
|
|
187
|
+
|
|
188
|
+
Every read asks each remote for its current head (`git ls-remote`). With
|
|
189
|
+
`--max-age <seconds>` a read verb reuses a head this machine observed at most
|
|
190
|
+
that many seconds ago instead, so a refresh right after another costs no
|
|
191
|
+
network round trip. Gate the flag on the feature: an older kernel may ignore
|
|
192
|
+
it and answer live, without the block.
|
|
193
|
+
|
|
194
|
+
```text
|
|
195
|
+
oats status | workspace status | souls | capabilities | inspect --soul|--home
|
|
196
|
+
| teams | soul teams <soul> … --max-age <seconds> --json
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
- **Values:** whole seconds, `0` to `86400`. `0` is live: it reuses nothing.
|
|
200
|
+
Anything else is `E_BAD_ARGS` (`--max-age needs a value: whole seconds from 0
|
|
201
|
+
to 86400`, `--max-age takes whole seconds from 0 to 86400, got "<v>"`).
|
|
202
|
+
- **The block:** with the flag (`0` included) the document gains one key,
|
|
203
|
+
`observation: {observedAt, reused, localRevision}`: in the result of an
|
|
204
|
+
envelope, at the top level of the roster (after `agents`). `observedAt` is the
|
|
205
|
+
OLDEST remote head the answer used, so the answer is at least that fresh
|
|
206
|
+
everywhere; `reused` is `true` when any head came from an earlier observation.
|
|
207
|
+
A command that read no remote head reports the time it started and
|
|
208
|
+
`reused: false`. Without the flag the key is absent and every document is
|
|
209
|
+
exactly as before.
|
|
210
|
+
- **`localRevision`:** 24 lowercase hex characters, opaque. It digests every
|
|
211
|
+
piece of local configuration the kernel read for this answer:
|
|
212
|
+
`oats-local.yaml` (and each closer `oats-local.yaml` it looked for and did
|
|
213
|
+
not find), `oats-lock.json`, an `OATS_PACKAGE_CATALOG` file, and the
|
|
214
|
+
automations snapshot. Only what the verb actually read counts. The same inputs
|
|
215
|
+
give the same revision; any byte change, or one of those files appearing or
|
|
216
|
+
disappearing, gives another. It names no path and no content. Different verbs
|
|
217
|
+
read different inputs (`workspace status` also reads the automations
|
|
218
|
+
snapshot; `inspect --home` reads no lock), so compare revisions of the same
|
|
219
|
+
verb and arguments only. Keep what you
|
|
220
|
+
hold (catalogs, inspect results) keyed on it: a different revision means the
|
|
221
|
+
deployment's configuration changed outside you (a `teams` edit, a sync, a
|
|
222
|
+
hand edit). A kernel upgrade shows through the probe (`oats version --json`),
|
|
223
|
+
not through `localRevision`: the bundled catalog is not an input. Instance
|
|
224
|
+
homes, member clones and tmux are not inputs either, because the answer
|
|
225
|
+
itself reports them.
|
|
226
|
+
- **What is reused:** only remote heads (the commit a branch or tag named),
|
|
227
|
+
never local state. Instances, `oats-local.yaml` and the lock are read afresh
|
|
228
|
+
by every command. A member's backlink (`oats-membership.yaml`) is read at
|
|
229
|
+
the member's observed head, which may be a reused one: a backlink removed
|
|
230
|
+
less than `<s>` seconds ago can still show the member `confirmed` under
|
|
231
|
+
`--max-age <s>`. Only the backlink's comparison with this workspace is made
|
|
232
|
+
afresh. A reused head's
|
|
233
|
+
`observedAt` (for example `workspace.observedAt` in `workspace status`) is
|
|
234
|
+
the time it was observed, not now.
|
|
235
|
+
- **When a head is not reused:** it is older than the flag allows (or dated
|
|
236
|
+
more than 5 s in the future); it was observed through a different URL
|
|
237
|
+
spelling of the same repository (ssh vs https) or for a different ref; its
|
|
238
|
+
commit can no longer be fetched. Each is observed live, as without the flag.
|
|
239
|
+
A live observation that fails is the usual error, never an older head.
|
|
240
|
+
- **Refusals:** every other command, every edit form (`teams add|remove|default`,
|
|
241
|
+
`soul teams --add|--remove|--default|--clear-default`) and any `--server`
|
|
242
|
+
invocation refuse the flag before reading or writing anything, with
|
|
243
|
+
`E_BAD_ARGS` "--max-age is not accepted by \`oats <form>\`: only the read
|
|
244
|
+
verbs reuse observations (status, workspace status, souls, capabilities,
|
|
245
|
+
inspect --soul|--home, and the read forms of teams and soul teams)" and,
|
|
246
|
+
with `--server`, "--max-age cannot be combined with --server: observation
|
|
247
|
+
reuse is local to this machine".
|
|
248
|
+
A capability command's argv (`oats <namespace> …`) is its provider's: the
|
|
249
|
+
kernel neither reads nor refuses `--max-age` there. The same holds for
|
|
250
|
+
`capture`, `recall`, `setup` and `experimental`, which parse their own argv:
|
|
251
|
+
`capture`, `setup` and `experimental` refuse it as an unknown argument (not
|
|
252
|
+
`E_BAD_ARGS`), and `recall` ignores unknown flags.
|
|
253
|
+
|
|
254
|
+
The observations are kept under the remote cache
|
|
255
|
+
(`$OATS_REMOTE_CACHE`, default `~/.cache/oats/remotes`), in `.observed/`,
|
|
256
|
+
beside the bounded parsed-read cache in `.parsed/`. An observation record
|
|
257
|
+
keeps a digest of the fetch URL, never the URL. A parsed entry keeps repository
|
|
258
|
+
content as committed (member refs included), and a value that carries a
|
|
259
|
+
credential-bearing URL (userinfo on http(s), or `user:password@` on any
|
|
260
|
+
scheme) is never written. Deleting either is always safe.
|
|
261
|
+
|
|
165
262
|
<a id="inspect-readiness-and-operation-run-on-the-workspace-model-operationsapi-2-soulsapi-2-readinessapi-2-oats-0260"></a>
|
|
166
263
|
## Inspect, readiness and operation run
|
|
167
264
|
|
|
@@ -195,7 +292,7 @@ A module's origin (`from`) is `{kind: "member", repoKey, commit}` or `{kind:
|
|
|
195
292
|
### `oats inspect`
|
|
196
293
|
|
|
197
294
|
```text
|
|
198
|
-
oats inspect (--home <abs> | --soul <name> [--dir <d>]) --json
|
|
295
|
+
oats inspect (--home <abs> | --soul <name> [--dir <d>]) [--max-age <s>] --json
|
|
199
296
|
```
|
|
200
297
|
|
|
201
298
|
An instance subject, abridged:
|
|
@@ -578,7 +675,7 @@ discovers the workspace over the network to check. Other errors: `E_USAGE`,
|
|
|
578
675
|
### `oats workspace status`
|
|
579
676
|
|
|
580
677
|
```text
|
|
581
|
-
oats workspace status [--dir <d>] --json
|
|
678
|
+
oats workspace status [--dir <d>] [--max-age <s>] --json
|
|
582
679
|
```
|
|
583
680
|
|
|
584
681
|
Read-only (it writes no lock):
|
|
@@ -627,8 +724,8 @@ Read-only (it writes no lock):
|
|
|
627
724
|
### `oats capabilities` and `oats souls`
|
|
628
725
|
|
|
629
726
|
```text
|
|
630
|
-
oats capabilities [--dir <d>] --json
|
|
631
|
-
oats souls [--dir <d>] --json
|
|
727
|
+
oats capabilities [--dir <d>] [--max-age <s>] --json
|
|
728
|
+
oats souls [--dir <d>] [--max-age <s>] --json
|
|
632
729
|
```
|
|
633
730
|
|
|
634
731
|
Every item of every confirmed member, the external souls, and the locked
|
|
@@ -816,7 +913,7 @@ soul subject), `""` when unknown.
|
|
|
816
913
|
### `oats teams`
|
|
817
914
|
|
|
818
915
|
```text
|
|
819
|
-
oats teams [--dir <d>] --json
|
|
916
|
+
oats teams [--dir <d>] [--max-age <s>] --json
|
|
820
917
|
oats teams add <label> --team <id> [--description <d>] --json
|
|
821
918
|
oats teams remove <label> --json
|
|
822
919
|
oats teams default <label> --json
|
|
@@ -855,6 +952,7 @@ oats teams default <label> --json
|
|
|
855
952
|
|
|
856
953
|
```text
|
|
857
954
|
oats soul teams <soul>|'*' [--add a,b] [--remove a,b] [--default <label> | --clear-default] [--dir <d>] --json
|
|
955
|
+
oats soul teams <soul>|'*' [--dir <d>] [--max-age <s>] --json (the read form only)
|
|
858
956
|
```
|
|
859
957
|
|
|
860
958
|
```json
|
|
@@ -1116,6 +1214,12 @@ it to a temporary copy (`soulFetched: true`).
|
|
|
1116
1214
|
(absent when nothing sets it) are the resolved selection.
|
|
1117
1215
|
`backendStatus` is `{name, installed, started: false}`, `null` with
|
|
1118
1216
|
`--no-launch`. `executable` is the resolved harness binary.
|
|
1217
|
+
- `launchConfigDefault` (0.32, feature `launch-config-default`) is `true`
|
|
1218
|
+
when `launchConfig` is this host's default for the harness (its
|
|
1219
|
+
executable, args, env and `yolo` apply without being chosen), `false`
|
|
1220
|
+
otherwise. Show it, and `yolo`, whenever it is `true`. An explicit
|
|
1221
|
+
`--launch-config none` asks for the bare harness and bypasses the default;
|
|
1222
|
+
to run the host's default, omit `--launch-config`.
|
|
1119
1223
|
- `modelSource` is `"explicit"`, `"soul default"`, `"launch-config <name>"`,
|
|
1120
1224
|
`"native default"` or `"native default (explicit)"` (`--model
|
|
1121
1225
|
@native-default`). Omitting `--model` and asking for the native default are
|
|
@@ -1207,8 +1311,8 @@ with `--expect-decision` records the key and decision in `instance.json`.
|
|
|
1207
1311
|
|
|
1208
1312
|
```json
|
|
1209
1313
|
{"instance":"rm-api","agent":"rm","home":"/w/agents/rm/instances/rm-api","work":"worktree","branch":"agents/rm-api","launched":true,"warnings":[],
|
|
1210
|
-
"tmux":{"session":"
|
|
1211
|
-
"spawnOrigin":"operator","attach":"tmux attach -t
|
|
1314
|
+
"tmux":{"session":"oats-agents","window":"rm-api"},"backend":"tmux","repo":"/w/agents-repo","harness":"pi","model":null,"parent":null,"sibling":null,"relation":null,
|
|
1315
|
+
"spawnOrigin":"operator","attach":"tmux attach -t oats-agents","decision":{"instance":"rm-api","revision":"c557d8ec9a272ba1c1739dc3"},"replayed":false,
|
|
1212
1316
|
"wake":{"requested":false,"saved":null,"error":null},"launchConfig":null,
|
|
1213
1317
|
"launch":{"version":2,"harness":"pi","launchConfig":null,"launchConfigSource":null,"executable":"/usr/local/bin/pi","executableDeclared":null,
|
|
1214
1318
|
"executableResolvedFrom":"PATH","args":[],"env":{},"model":null,"hooks":{"launch":{},"env":{},"contributions":[]},"prompt":{"kind":"task-file","file":"TASK.md"}}}
|
|
@@ -1217,10 +1321,11 @@ with `--expect-decision` records the key and decision in `instance.json`.
|
|
|
1217
1321
|
(`decision` is abridged: it is the full bound decision.)
|
|
1218
1322
|
|
|
1219
1323
|
- Always present: `instance, agent, home, work, branch, launched, warnings
|
|
1220
|
-
(array), tmux ({session, window} | null),
|
|
1324
|
+
(array), tmux ({session, window} | null), backend ("tmux"), repo, harness,
|
|
1325
|
+
model, parent,
|
|
1221
1326
|
sibling, relation, spawnOrigin (operator | instance), attach, launchConfig,
|
|
1222
1327
|
launch` (the redacted recipe).
|
|
1223
|
-
- When they apply: `
|
|
1328
|
+
- When they apply: `yolo`, `decision` and
|
|
1224
1329
|
`replayed` (bound apply), `wake` (keyed apply), `wakeSchedule` and
|
|
1225
1330
|
`wakeScheduleError` (a requested wake).
|
|
1226
1331
|
|
|
@@ -1297,7 +1402,7 @@ workspace-model fields (feature `instance-modules`):
|
|
|
1297
1402
|
```
|
|
1298
1403
|
|
|
1299
1404
|
Abridged: the record also carries the launch recipe and command,
|
|
1300
|
-
composition evidence, the capability runtime, the tmux
|
|
1405
|
+
composition evidence, the capability runtime, the tmux target,
|
|
1301
1406
|
lineage (`parentInstance`, `siblingInstance`, `relation`, `relativeTo`), and
|
|
1302
1407
|
the keyed-spawn fields `decision`, `spawnIdempotencyKey`, `spawnCompleted` and
|
|
1303
1408
|
`wake`; later starts add `restarts` and `restartCount`.
|
|
@@ -1326,10 +1431,11 @@ the keyed-spawn fields `decision`, `spawnIdempotencyKey`, `spawnCompleted` and
|
|
|
1326
1431
|
### The roster (`oats status --json`)
|
|
1327
1432
|
|
|
1328
1433
|
```text
|
|
1329
|
-
oats status [--dir <d>] --json
|
|
1434
|
+
oats status [--dir <d>] [--max-age <s>] --json
|
|
1330
1435
|
```
|
|
1331
1436
|
|
|
1332
|
-
Not an envelope: `{root, agents, workspace?, problems?, warnings?}
|
|
1437
|
+
Not an envelope: `{root, agents, observation?, workspace?, problems?, warnings?}`
|
|
1438
|
+
(`observation` only with [`--max-age`](#observation-reuse-feature-observe-max-age-oats-0311)).
|
|
1333
1439
|
|
|
1334
1440
|
```json
|
|
1335
1441
|
{"root":"/w/agents",
|
|
@@ -1354,8 +1460,13 @@ Not an envelope: `{root, agents, workspace?, problems?, warnings?}`.
|
|
|
1354
1460
|
description, dir, instances}`.
|
|
1355
1461
|
- **Instance rows**: the home's `instance.json` (launch recipe and command
|
|
1356
1462
|
redacted) plus `home` and `instance` (from the directory; a disagreeing
|
|
1357
|
-
claim is kept as `recordedHome`/`recordedInstance`), `running` (
|
|
1358
|
-
|
|
1463
|
+
claim is kept as `recordedHome`/`recordedInstance`), `running` (read from
|
|
1464
|
+
the row's recorded tmux socket and session, never the caller's `$TMUX`;
|
|
1465
|
+
`null` with `runtimeState: "unreachable"` and the tmux error as
|
|
1466
|
+
`runtimeError` when that server cannot be read; `null` for a home a
|
|
1467
|
+
Herdr-era kernel recorded, with `runtimeState: "unsupported"` and
|
|
1468
|
+
`runtimeError: "E_HERDR_REMOVED: …"`, the recorded `sessionTarget` staying
|
|
1469
|
+
in the row),
|
|
1359
1470
|
`identity` when a provider recorded one, `rollbackIncomplete` and
|
|
1360
1471
|
`retirePending` when present, and the Desktop facts below.
|
|
1361
1472
|
- **`modules`** becomes drift rows `{name, from, commit, current, status,
|
|
@@ -1379,6 +1490,82 @@ restart, else `createdAt` for a launched home, else `null`. `modelFrom` is
|
|
|
1379
1490
|
`"harness-default"`, or `null` for an older home. `identityAddress` is the
|
|
1380
1491
|
messaging identity's `address` (else `alias`), or `null`.
|
|
1381
1492
|
|
|
1493
|
+
<a id="the-remote-roster-oats-server-roster---json"></a>
|
|
1494
|
+
### The remote roster (`oats server roster --json`)
|
|
1495
|
+
|
|
1496
|
+
```text
|
|
1497
|
+
oats server roster [--server <id>] [--per-target <ms>] [--budget <ms>] --json
|
|
1498
|
+
```
|
|
1499
|
+
|
|
1500
|
+
An envelope; `result` is `{groups, bounds}` (remote `roster`,
|
|
1501
|
+
[servers.md](servers.md#the-roster-and-harvest)). One group per server id and
|
|
1502
|
+
route target:
|
|
1503
|
+
|
|
1504
|
+
```json
|
|
1505
|
+
{"id":"build:3f2a…","server":"build","label":"Build box","registrationPresent":true,
|
|
1506
|
+
"target":{"sshHost":"build-host","workspace":"/srv/team","oatsPath":"oats"},
|
|
1507
|
+
"probe":{"ok":true},"agentsRoot":"/srv/team/agents",
|
|
1508
|
+
"souls":[{"name":"dev","harness":"claude","work":"worktree","agentsRoot":"/srv/team/agents"}],
|
|
1509
|
+
"instances":[{"server":"build","instance":"dev-a","agent":"dev","home":"/srv/team/agents/dev/instances/dev-a",
|
|
1510
|
+
"agentsRoot":"/srv/team/agents","harness":"claude","backend":"tmux","tmux":{"session":"oats-agents","window":"dev-a"},
|
|
1511
|
+
"running":true,"identity":{"alias":"dev-a","address":"acme/dev-a"},"identityAddress":"acme/dev-a",
|
|
1512
|
+
"teams":[{"label":"default","team":"acme:team"}],"startedAt":"2026-09-29T10:00:00.000Z","createdAt":"2026-09-29T09:58:12.004Z",
|
|
1513
|
+
"model":"opus","runtimeState":null,"parentInstance":"lead","siblingInstance":null,"relation":"child","relativeTo":"lead",
|
|
1514
|
+
"spawnOrigin":"instance","retirePending":false,"rollbackIncomplete":false,
|
|
1515
|
+
"savedRoute":false,"addressable":true,"missingRemotely":false}],
|
|
1516
|
+
"retireFailures":[]}
|
|
1517
|
+
```
|
|
1518
|
+
|
|
1519
|
+
- **Instance rows** relay the host's own `status --json` row: `identity`,
|
|
1520
|
+
`identityAddress`, `teams`, `startedAt`, `createdAt`, `model`,
|
|
1521
|
+
`runtimeState`, `parentInstance`, `siblingInstance`, `relation`,
|
|
1522
|
+
`relativeTo` and `spawnOrigin` are always present, `null` when the host
|
|
1523
|
+
does not supply them (a host before 0.31, a fact it never recorded, or a
|
|
1524
|
+
saved route the host no longer lists). Nothing is derived on this side.
|
|
1525
|
+
- **`addressable`** (0.31): `true` for every row the host reports. Routed
|
|
1526
|
+
session and lifecycle commands reach it by `--home`, or by name when the
|
|
1527
|
+
name is unique on the host ([addressing](servers.md#run-there); a shared
|
|
1528
|
+
name is `E_AMBIGUOUS` with `error.details.candidates: [{agent, home}]`). A
|
|
1529
|
+
saved-route row the host did not list is addressable only while the host's
|
|
1530
|
+
answer is unknown (`missingRemotely: false`).
|
|
1531
|
+
- **`savedRoute`**: the instance was spawned from this machine and has a
|
|
1532
|
+
saved route here. Information only; no action depends on it.
|
|
1533
|
+
- `running` is `null` when unknown; `backend` is `tmux` for a row with a tmux
|
|
1534
|
+
target, else `null`; `tmux`, `sessionTarget` (the recorded target of a home
|
|
1535
|
+
a Herdr-era kernel opened) and `runtimeError` are as the host reports them.
|
|
1536
|
+
|
|
1537
|
+
<a id="routed-reads-and-plans"></a>
|
|
1538
|
+
### Routed reads and plans (`--server`, 0.31)
|
|
1539
|
+
|
|
1540
|
+
The Desktop's per-instance reads and the lifecycle plans run on the
|
|
1541
|
+
instance's own machine: the local command, with `--server <id>` added.
|
|
1542
|
+
|
|
1543
|
+
| Command | `remote` entry | The host must advertise |
|
|
1544
|
+
|---|---|---|
|
|
1545
|
+
| `oats readiness --server <id> (--home <abs> \| --soul <n>) …` | `readiness` | `readiness`, `readinessApi: 2` |
|
|
1546
|
+
| `oats instance events <name> --server <id> …` | `instance-events` | `instance-events-2`, `eventsApi: 2` |
|
|
1547
|
+
| `oats instance git\|diff <name> --server <id> …` | `instance-git` | `instance-git`, `instanceGitApi: 1` |
|
|
1548
|
+
| `oats instance stop <name> --server <id> (--plan \| --apply …)` | `lifecycle-plans` | `lifecycle-plans`, `lifecycleApi: 1` |
|
|
1549
|
+
| `oats retire <name> --server <id> --plan`, and the guarded apply (`--plan-revision`, `--idempotency-key`) | `lifecycle-plans` | `lifecycle-plans`, `lifecycleApi: 1` |
|
|
1550
|
+
|
|
1551
|
+
- The flags are the local command's. The instance is addressed like every
|
|
1552
|
+
routed instance command ([servers.md](servers.md#run-there)): `--home` as
|
|
1553
|
+
given, else the name through its saved route or the host's roster, sent
|
|
1554
|
+
as `--home`. `--dir` names a directory on the host and travels as is;
|
|
1555
|
+
without it the registered workspace is sent (not for `readiness --home`,
|
|
1556
|
+
whose home is its own context). A retire plan and its guarded apply take
|
|
1557
|
+
`--dir` like the rest; an unguarded `retire --server` refuses it.
|
|
1558
|
+
- An instance with a saved route is reached through it, registration or not.
|
|
1559
|
+
A guarded retire apply whose name the host no longer lists is sent by name,
|
|
1560
|
+
so a repeated key gets the host's recorded receipt (or its refusal).
|
|
1561
|
+
- The host's envelope is relayed unchanged, success or failure: the same
|
|
1562
|
+
document the local command answers, with no routing keys added. The
|
|
1563
|
+
guarded retire apply is the routed `retire`, whose result carries
|
|
1564
|
+
`server` and `target` as before.
|
|
1565
|
+
- A host that does not advertise the feature and API number is refused with
|
|
1566
|
+
`E_REMOTE_INCOMPATIBLE`, naming both and the host's version, before
|
|
1567
|
+
anything is sent. A name two homes share on the host is `E_AMBIGUOUS`.
|
|
1568
|
+
|
|
1382
1569
|
<a id="instance-git-state-oats-instance-gitdiff-instancegitapi-1-oats-0247"></a>
|
|
1383
1570
|
## Git and diff
|
|
1384
1571
|
|
|
@@ -1711,26 +1898,45 @@ accept `--server <id>`.
|
|
|
1711
1898
|
{"context":"/w","level":"/w","file":"/w/oats-local.yaml","selected":null,
|
|
1712
1899
|
"configurations":[{"name":"reviewers","harness":"claude","executable":null,"args":["--permission-mode","plan"],
|
|
1713
1900
|
"env":{"ANTHROPIC_API_KEY":{"fromEnv":"REVIEW_KEY"},"REVIEW_MODE":{"redacted":true}},
|
|
1714
|
-
"model":"opus","yolo":null,"source":"/w/oats-local.yaml","shadows":[]}]}
|
|
1901
|
+
"model":"opus","yolo":null,"default":false,"source":"/w/oats-local.yaml","shadows":[]}]}
|
|
1715
1902
|
```
|
|
1716
1903
|
|
|
1717
1904
|
- **list**: `selected` is `null`, `{home, instance}` or `{soul, agentsRoot}`;
|
|
1718
1905
|
`level` and `file` are `null` without an `oats-local.yaml` (the set is then
|
|
1719
1906
|
empty). An environment literal is `{redacted: true}`, a reference
|
|
1720
|
-
`{fromEnv}`; values never leave the file.
|
|
1907
|
+
`{fromEnv}`; values never leave the file. `default` (0.32, feature
|
|
1908
|
+
`launch-config-default`) is always a boolean: `true` marks this host's
|
|
1909
|
+
default for the configuration's harness.
|
|
1721
1910
|
- **set**/**remove**: `{name, action, level, file, before, after,
|
|
1722
1911
|
effective}`. `set --file` takes `{harness, executable?, args?, env?, model?,
|
|
1723
|
-
yolo?}` (`-` reads stdin)
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
`
|
|
1912
|
+
yolo?, default?}` (`-` reads stdin); it replaces the whole entry and refuses
|
|
1913
|
+
a key it does not know, so an editor sends `default` back to keep it.
|
|
1914
|
+
`default: false` is written as its absence. A second `default: true` for a
|
|
1915
|
+
harness is `E_LAUNCH_CONFIG_INVALID` with `details: {harness,
|
|
1916
|
+
configurations: [<the declared one>, <this one>]}` and nothing is written;
|
|
1917
|
+
moving the default is two writes, never an automatic move. `--keep-env`
|
|
1918
|
+
keeps the declared environment when `env` is omitted. Routed with
|
|
1919
|
+
`--server`, a definition with `default: true` to a host that does not
|
|
1920
|
+
advertise `launch-config-default` is `E_REMOTE_INCOMPATIBLE` before
|
|
1921
|
+
anything is sent (`default: false` is dropped). Errors: `E_LOCAL_MISSING`,
|
|
1922
|
+
`E_BAD_ARGS` (including `--home`/`--soul`), `E_LAUNCH_CONFIG_UNKNOWN`,
|
|
1923
|
+
`E_LAUNCH_CONFIG_INVALID`, `E_CONFIG_BROKEN`, `E_HOME_UNKNOWN`,
|
|
1924
|
+
`E_REMOTE_INCOMPATIBLE`.
|
|
1727
1925
|
- **preview** (read-only) answers `{context, selected, selection: {source,
|
|
1728
1926
|
launchConfig, harness, model, yolo}, harness, model, modelSource, yolo,
|
|
1729
|
-
launchConfig, launchConfigSource, executable: {path,
|
|
1730
|
-
resolvedFrom}, argv, environment: [{name, fromEnv} | {name, redacted:
|
|
1927
|
+
launchConfig, launchConfigSource, launchConfigDefault, executable: {path,
|
|
1928
|
+
declared, resolvedFrom}, argv, environment: [{name, fromEnv} | {name, redacted:
|
|
1731
1929
|
true} | {name, reference: true}], command (redacted), prompt, hooks,
|
|
1732
1930
|
preflight: [{check, ok, detail}], ok}`.
|
|
1733
1931
|
|
|
1932
|
+
`launchConfigDefault` (0.32) is `true` when `launchConfig` is this host's
|
|
1933
|
+
default for the harness rather than a chosen configuration; the spawn preview
|
|
1934
|
+
carries the same top-level field, `instance.json` records it as
|
|
1935
|
+
`launch.launchConfigDefault: true`, and `inspect --json` of a home answers
|
|
1936
|
+
`instance.launchConfig` and `instance.launchConfigDefault`. The closed `Launch`
|
|
1937
|
+
object is unchanged: its `effective.launchConfig` names the default
|
|
1938
|
+
configuration.
|
|
1939
|
+
|
|
1734
1940
|
A successful envelope can carry `ok: false`: show the failed `preflight`
|
|
1735
1941
|
checks. The prompt is named, never the task body. A home predating launch
|
|
1736
1942
|
recipes answers its frozen command with `selection.source: "frozen-command"`
|
|
@@ -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,42 @@ 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
|
+
## Instances on servers
|
|
114
|
+
|
|
115
|
+
Every instance a registered server reports shows in its workspace's roster, whoever spawned it. You
|
|
116
|
+
can open its terminal, start, restart, stop and remove it, and read its readiness, activity, Git
|
|
117
|
+
and diffs, as for a local one. Only its pull request is not read here, since the forge reads this
|
|
118
|
+
computer's clones. Every command goes to the server by the instance's home (`--server <id> --home
|
|
119
|
+
<path>`), never by a bare name. Stop and Remove show the plan the server makes, and confirm
|
|
120
|
+
against it.
|
|
121
|
+
|
|
122
|
+
A read waits for the server: the view says "Reading from <server>…", and gives up after about
|
|
123
|
+
45 seconds with "Couldn't reach <server>." When the server refuses, you see its code and message;
|
|
124
|
+
nothing is read from this computer in its place. A row that can't be opened says why on the row:
|
|
125
|
+
Herdr no longer supported, gone from <server>, not reachable on <server>, or <server> not reached.
|
|
126
|
+
For an instance a server no longer lists, the reason names the command that removes it from this
|
|
127
|
+
computer (`oats server forget <server> --instance <name>`).
|
|
128
|
+
|
|
129
|
+
## Remote terminals
|
|
130
|
+
|
|
131
|
+
A terminal for an instance on a registered server is a viewer over ssh
|
|
132
|
+
(`oats session attach --server`). When the link dies, ssh ends the viewer with
|
|
133
|
+
exit 255 within about a minute, and the tab reconnects by itself. It keeps its
|
|
134
|
+
place and scrollback, stops taking input, and shows "Disconnected from
|
|
135
|
+
<server>" with a countdown and a **Reconnect now** button. Attempts wait 1, 2,
|
|
136
|
+
4, 8 and 15 s, then 30 s each for as long as the tab is open. A successful
|
|
137
|
+
attach resets that. Tmux redraws the screen when the viewer attaches again.
|
|
138
|
+
|
|
139
|
+
Reconnecting stops, with a message and "Close this tab", when the server
|
|
140
|
+
answers that the session is gone, the instance is unknown, the terminal limit
|
|
141
|
+
is reached or the app's backend changed, and at once when ssh cannot be run on
|
|
142
|
+
this computer. It stops after four attempts in a
|
|
143
|
+
row in which OATS on this computer gave no answer, since that is more likely
|
|
144
|
+
the local CLI failing than the link. It also stops when the viewer ends with
|
|
145
|
+
any other exit code. Closing the tab ends the reconnecting. Reconnecting
|
|
146
|
+
never stops or restarts the agent on the server: only the local ssh viewer
|
|
147
|
+
ends.
|
|
148
|
+
|
|
113
149
|
## Attach files and screenshots
|
|
114
150
|
|
|
115
151
|
Drop a file onto an agent terminal to insert its path into that agent's draft.
|