@awebai/oats 0.34.3 → 0.35.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 +8 -2
- package/docs/desktop-cli-api.md +32 -16
- package/docs/integrations.md +1 -1
- package/docs/knowledge.md +1 -1
- package/docs/official-catalog.md +2 -2
- package/docs/packages.md +8 -8
- package/docs/release-notes/v0.34.4.md +51 -0
- package/docs/release-notes/v0.35.0.md +53 -0
- package/docs/souls-and-instances.md +27 -2
- package/docs/workspaces.md +1 -1
- package/lib/core.mjs +147 -51
- package/lib/instance-resolution.mjs +23 -9
- package/lib/remote.mjs +3 -1
- package/package-catalog.json +1 -1
- package/package.json +1 -1
- package/packages/record/README.md +55 -0
- package/packages/record/bin/capture.mjs +204 -27
- package/packages/record/lib/capture-cc.mjs +10 -4
- package/packages/record/lib/sessions-for-home.mjs +3 -1
- package/skills/oats-getting-started/SKILL.md +1 -1
package/bin/oats.mjs
CHANGED
|
@@ -2256,6 +2256,8 @@ async function spawnCmd() {
|
|
|
2256
2256
|
if (e?.code === "E_REQUIREMENT_INACTIVE") { bail(e.code, e.message, { soul: e.soul, capabilities: e.capabilities, context: e.context, remedy: e.remedy }); throw e; }
|
|
2257
2257
|
if (e?.code === "E_CHILD_SPAWNS_DISABLED") { bail(e.code, e.message, { parent: e.parent, policy: e.policy }); throw e; }
|
|
2258
2258
|
if (["E_BRANCH_EXISTS", "E_BASE_UNKNOWN"].includes(e?.code)) { bail(e.code, e.message); throw e; }
|
|
2259
|
+
// The observed base could not be fetched into the clone: the clone, the repository and the commit travel along.
|
|
2260
|
+
if (e?.code === "E_REMOTE_UNREADABLE" && e.details?.commit) { bail(e.code, e.message, e.details); throw e; }
|
|
2259
2261
|
// K6b: the confirmed decision drifted — the fresh decision travels with the refusal so a GUI re-previews.
|
|
2260
2262
|
if (e?.code === "E_DECISION_STALE") { bail(e.code, e.message, { decision: e.decision }); throw e; }
|
|
2261
2263
|
if (e?.code === "E_IDEMPOTENCY_CONFLICT") { bail(e.code, e.message, { instance: e.instance, home: e.home }); throw e; }
|
|
@@ -2283,7 +2285,7 @@ async function spawnCmd() {
|
|
|
2283
2285
|
// Desktop CLI API v1 spawn result — a FIXED shape (see docs/desktop-cli-api.md).
|
|
2284
2286
|
jsonOk({
|
|
2285
2287
|
instance: r.instance, agent: r.agent, home: r.home, work: r.work,
|
|
2286
|
-
branch: r.branch || null, launched: r.launched, warnings: r.warnings || [],
|
|
2288
|
+
branch: r.branch || null, base: r.base ?? null, launched: r.launched, warnings: r.warnings || [],
|
|
2287
2289
|
...(wakeSchedule ? { wakeSchedule } : {}), ...(wakeScheduleError ? { wakeScheduleError } : {}),
|
|
2288
2290
|
tmux: r.tmux || null, backend: "tmux", repo: r.repo || null, harness: r.harness || null,
|
|
2289
2291
|
model: r.model || null, parent: r.parentInstance || null,
|
|
@@ -2299,6 +2301,7 @@ async function spawnCmd() {
|
|
|
2299
2301
|
}
|
|
2300
2302
|
console.log(`Spawned ${r.instance} (${r.work}${r.branch ? `, branch ${r.branch}` : ""})${r.launched ? ` — tmux window "${r.tmux.window}"` : " — not launched"}`);
|
|
2301
2303
|
console.log(` home: ${shortPath(r.home)}`);
|
|
2304
|
+
if (r.base) console.log(` base: ${r.base.oid.slice(0, 12)} (${r.base.ref === r.workspace?.soul?.repoKey ? `observed head of ${r.base.ref}` : r.base.ref})`);
|
|
2302
2305
|
if (wakeSchedule) console.log(` wake: schedule ${wakeSchedule.id} (${wakeSchedule.cron} ${wakeSchedule.tz}), next ${wakeSchedule.nextRun || "disabled"}`);
|
|
2303
2306
|
if (wakeScheduleError) console.error(` wake: NOT saved — ${wakeScheduleError.message} (the instance is created and launched; add the wake by hand with oats schedule add)`);
|
|
2304
2307
|
if (!r.launched) console.log(` launch: oats session start --home ${shellQuote(r.home)}`);
|
|
@@ -3056,7 +3059,7 @@ function versionCmd() {
|
|
|
3056
3059
|
// Phase B: `instance-modules` and `spawn-provider-payload` are advertised only once spawn
|
|
3057
3060
|
// runs on resolve/materialize (contract §6); a feature the binary does not implement is
|
|
3058
3061
|
// never listed.
|
|
3059
|
-
console.log(JSON.stringify({ schemaVersion: 1, name: "@awebai/oats", version: OATS_VERSION, desktopApi: 1, harnesses: ["pi", "claude", "codex"], sessionBackends: ["tmux"], launchOptions: ["yolo"], remote: ["spawn", "retire", "status", "session", "session-start", "session-restart", "launch-config", "roster", "harvest", "schedule", "session-upload", "operations", "readiness", "instance-events", "instance-git", "lifecycle-plans"], features: ["retire-home", "session-start", "session-restart", "launch-config", "schedule", "session-upload", "operations", "instance-git", "instance-git-remote", "souls-declarations", "lifecycle-plans", "retire-retention", "readiness", "spawn-preview", "instance-events", "instance-events-2", "schedule-history", "schedule-read-2", "spawn-preview-2", "spawn-idempotency", "spawn-idempotency-2", "spawn-apply-2", "workspace-v2", "instance-modules", "spawn-provider-payload", "served-identity", "packages-no-approval", "spawn-name", "settings-origins", "team-model-2", "settings-declared", "capabilities-private", "layers-from", "harness", "package-souls", "triggers", "automations", "desktop-facts", "launch-preference", "preview-composed-from", "observe-max-age", "spawn-preview-max-age", "launch-config-default", "capability-show"], automationsApi: A.AUTOMATIONS_API, workspaceApi: 2, instanceGitApi: 1, spawnApplyApi: 1, soulsApi: 2, lifecycleApi: 1, readinessApi: 2, spawnPreviewApi: 2, eventsApi: 2, scheduleHistoryApi: 3, scheduleApi: SCHEDULE_API, operationsApi: 2, capabilityShowApi: 1 }));
|
|
3062
|
+
console.log(JSON.stringify({ schemaVersion: 1, name: "@awebai/oats", version: OATS_VERSION, desktopApi: 1, harnesses: ["pi", "claude", "codex"], sessionBackends: ["tmux"], launchOptions: ["yolo"], remote: ["spawn", "retire", "status", "session", "session-start", "session-restart", "launch-config", "roster", "harvest", "schedule", "session-upload", "operations", "readiness", "instance-events", "instance-git", "lifecycle-plans"], features: ["retire-home", "session-start", "session-restart", "launch-config", "schedule", "session-upload", "operations", "instance-git", "instance-git-remote", "souls-declarations", "lifecycle-plans", "retire-retention", "readiness", "spawn-preview", "instance-events", "instance-events-2", "schedule-history", "schedule-read-2", "spawn-preview-2", "spawn-idempotency", "spawn-idempotency-2", "spawn-apply-2", "workspace-v2", "instance-modules", "spawn-provider-payload", "served-identity", "packages-no-approval", "spawn-name", "settings-origins", "team-model-2", "settings-declared", "capabilities-private", "layers-from", "harness", "package-souls", "triggers", "automations", "desktop-facts", "launch-preference", "preview-composed-from", "observe-max-age", "spawn-preview-max-age", "launch-config-default", "capability-show", "capture-file"], automationsApi: A.AUTOMATIONS_API, workspaceApi: 2, instanceGitApi: 1, spawnApplyApi: 1, soulsApi: 2, lifecycleApi: 1, readinessApi: 2, spawnPreviewApi: 2, eventsApi: 2, scheduleHistoryApi: 3, scheduleApi: SCHEDULE_API, operationsApi: 2, capabilityShowApi: 1 }));
|
|
3060
3063
|
return;
|
|
3061
3064
|
}
|
|
3062
3065
|
console.log(`@awebai/oats ${OATS_VERSION} (desktop API v1)`);
|
|
@@ -3775,6 +3778,9 @@ The turn record (core — every conversation captured, searchable, replicated):
|
|
|
3775
3778
|
oats capture [--watch|--status] land Claude Code/pi/codex sessions and aw
|
|
3776
3779
|
[--owner <name>] [--root <dir>] client logs in the record; reconciliation
|
|
3777
3780
|
is the capture
|
|
3781
|
+
oats capture --file <path> --format cc|pi|codex --home <instance home> [--json]
|
|
3782
|
+
one session file (an archived session),
|
|
3783
|
+
captured as --home capture would
|
|
3778
3784
|
oats recall [--kind k] [--thread t] search the whole record — mail, chat,
|
|
3779
3785
|
[--from f] [--show id] <query> sessions — with exact turn provenance
|
|
3780
3786
|
oats setup [--owner <name>] [--dry-run] install capture hooks + background watcher
|
package/docs/desktop-cli-api.md
CHANGED
|
@@ -38,7 +38,7 @@ canonical (`github.com/<org>/<repo>`, or `local/<abs-path>`). Examples use
|
|
|
38
38
|
"instance-events-2","schedule-history","schedule-read-2","spawn-preview-2","spawn-idempotency","spawn-idempotency-2","spawn-apply-2",
|
|
39
39
|
"workspace-v2","instance-modules","spawn-provider-payload","served-identity","packages-no-approval","spawn-name","settings-origins",
|
|
40
40
|
"team-model-2","settings-declared","capabilities-private","layers-from","harness","package-souls","triggers","automations","desktop-facts","launch-preference",
|
|
41
|
-
"preview-composed-from","observe-max-age","spawn-preview-max-age","capability-show"],
|
|
41
|
+
"preview-composed-from","observe-max-age","spawn-preview-max-age","capability-show","capture-file"],
|
|
42
42
|
"automationsApi":1,"workspaceApi":2,"instanceGitApi":1,"spawnApplyApi":1,"soulsApi":2,"lifecycleApi":1,
|
|
43
43
|
"readinessApi":2,"spawnPreviewApi":2,"eventsApi":2,"scheduleHistoryApi":3,"scheduleApi":2,"operationsApi":2,
|
|
44
44
|
"capabilityShowApi":1}
|
|
@@ -99,6 +99,7 @@ canonical (`github.com/<org>/<repo>`, or `local/<abs-path>`). Examples use
|
|
|
99
99
|
| `observe-max-age` | `--max-age <s>` on the read verbs and their `observation` block ([Observation reuse](#observation-reuse-feature-observe-max-age-oats-0311)) | |
|
|
100
100
|
| `spawn-preview-max-age` | `--max-age <s>` on `spawn --preview` and its `observation` block ([Observation reuse](#observation-reuse-feature-observe-max-age-oats-0311), [The preview](#the-preview)) | |
|
|
101
101
|
| `capability-show` | `oats capabilities show <name>` and its `--file` form, OATS 0.34.0 ([`oats capabilities show`](#oats-capabilities-show)) | `capabilityShowApi: 1` |
|
|
102
|
+
| `capture-file` | `oats capture --file <path> --format cc\|pi\|codex --home <instance home> [--json]`: one session file captured as `--home` capture would, with a receipt bound to its bytes, OATS 0.35.0 (the capture USAGE and packages/record/README.md) | |
|
|
102
103
|
|
|
103
104
|
Payload-only integers, never in the probe: `onboardApi: 2`, `syncApi: 1`,
|
|
104
105
|
`workspaceStatusApi: 1`, `capabilitiesApi: 1`, the `oats souls` document's
|
|
@@ -723,7 +724,7 @@ Read-only (it writes no lock):
|
|
|
723
724
|
"souls":["rm"],"capabilities":["nw-house-style"],"publishes":null,"url":"https://github.com/nw/agents/tree/66566512…",
|
|
724
725
|
"membershipFile":{"path":"oats-membership.yaml","url":"https://github.com/nw/agents/blob/66566512…/oats-membership.yaml"}}],
|
|
725
726
|
"packages":[{"id":"oats.okf","version":"3.0.0","source":"catalog:oats.okf","commit":"ab897841…","integrity":"sha256-bada35…",
|
|
726
|
-
"capabilities":["oats.okf"],"souls":[],"latest":{"version":"4.0
|
|
727
|
+
"capabilities":["oats.okf"],"souls":[],"latest":{"version":"4.1.0","ref":"v4.1.0"}}],
|
|
727
728
|
"declaredPackages":["oats.framework","oats.okf"],"unsynced":["oats.framework"],"stale":[],
|
|
728
729
|
"external":[{"source":"git:github.com/oss/experts@3c606e09…","soul":"security-reviewer"}],
|
|
729
730
|
"problems":[],"warnings":[],
|
|
@@ -782,8 +783,8 @@ packages' capabilities and souls, sorted by name, then origin. Both carry
|
|
|
782
783
|
"defaultTeam":{"label":"mine","team":"mine:ana.aweb.ai","from":"deployment"},
|
|
783
784
|
"private":false,"path":"souls/writer","work":"directory","description":"Drafts campaigns.","harness":"pi","model":null,"harnessFrom":"kernel-default",
|
|
784
785
|
"file":{"path":"souls/writer/soul.yaml","url":null},"spawnable":true,"problem":null},
|
|
785
|
-
{"name":"knowledge-maintainer","qualifiedName":"oats.okf/knowledge-maintainer","origin":"package oats.okf v4.0
|
|
786
|
-
"version":"4.0
|
|
786
|
+
{"name":"knowledge-maintainer","qualifiedName":"oats.okf/knowledge-maintainer","origin":"package oats.okf v4.1.0","kind":"package","package":"oats.okf",
|
|
787
|
+
"version":"4.1.0","repoKey":"github.com/awebai/oats-okf","commit":"e331a996…","teams":null,"defaultTeam":null,"private":false,
|
|
787
788
|
"path":"oats-package/souls/knowledge-maintainer","work":"directory","description":"Reviews harvested knowledge.","harness":"pi","model":null,
|
|
788
789
|
"harnessFrom":"kernel-default","file":{"path":"oats-package/souls/knowledge-maintainer/soul.yaml","url":null},
|
|
789
790
|
"spawnable":false,"problem":{"code":"E_TEAM_UNKNOWN","message":"team \"reviewers\" is not declared (oats-local.yaml#/souls/teams/…)"}}],
|
|
@@ -872,8 +873,8 @@ nothing reads a working clone.
|
|
|
872
873
|
**The show:**
|
|
873
874
|
|
|
874
875
|
```json
|
|
875
|
-
{"capabilityShowApi":1,"name":"oats.okf","kind":"package","repoKey":"github.com/awebai/oats-okf","package":"oats.okf","version":"4.0
|
|
876
|
-
"commit":"
|
|
876
|
+
{"capabilityShowApi":1,"name":"oats.okf","kind":"package","repoKey":"github.com/awebai/oats-okf","package":"oats.okf","version":"4.1.0",
|
|
877
|
+
"commit":"e331a996…","path":"oats-package/capabilities/oats-okf",
|
|
877
878
|
"inject":{"path":"injects/okf.md","bytes":2422,"text":"## Knowledge: OKF\n\nYou have two kinds of knowledge. …","binary":false,"truncated":false},
|
|
878
879
|
"skills":[{"name":"okf-consultation","path":"skills/okf-consultation","description":"Consulting your soul's knowledge with the `oats okf` CLI: …",
|
|
879
880
|
"files":[{"path":"skills/okf-consultation/SKILL.md","bytes":6947},{"path":"skills/okf-consultation/references/consult.md","bytes":4465}],
|
|
@@ -899,7 +900,7 @@ nothing reads a working clone.
|
|
|
899
900
|
**The `--file` answer:**
|
|
900
901
|
|
|
901
902
|
```json
|
|
902
|
-
{"capabilityShowApi":1,"name":"oats.okf","kind":"package","commit":"
|
|
903
|
+
{"capabilityShowApi":1,"name":"oats.okf","kind":"package","commit":"e331a996…",
|
|
903
904
|
"file":{"path":"skills/okf-instance-knowledge/SKILL.md","bytes":4787,"text":"---\nname: okf-instance-knowledge\n…","binary":false,"truncated":false}}
|
|
904
905
|
```
|
|
905
906
|
|
|
@@ -1394,13 +1395,13 @@ it to a temporary copy (`soulFetched: true`).
|
|
|
1394
1395
|
"settingsOrigins":{"nw-tools":{},"oats.okf":{"/owns":{"kind":"soul","at":"soul.yaml#/knowledge"}}},
|
|
1395
1396
|
"spawnPreviewApi":2,"preview":true,"agent":"rm","kind":"persistent","instance":"rm-api","home":"/w/agents/rm/instances/rm-api",
|
|
1396
1397
|
"repo":"/w/agents-repo","work":"worktree","subject":{"soul":"rm","agentsRoot":null,"dir":"/w"},
|
|
1397
|
-
"decision":{"instance":"rm-api","home":"/w/agents/rm/instances/rm-api","branch":"agents/rm-api","base":{"ref":"
|
|
1398
|
+
"decision":{"instance":"rm-api","home":"/w/agents/rm/instances/rm-api","branch":"agents/rm-api","base":{"ref":"github.com/nw/agents","oid":"66566512…"},
|
|
1398
1399
|
"effective":{"repo":"/w/agents-repo","work":"worktree","harness":"pi","model":null,"launchConfig":null,"yolo":null,"backend":"tmux",
|
|
1399
1400
|
"childSpawns":true,"relation":null,"providers":{"nw-tools":{},"oats.okf":{"owns":"rm"}}},
|
|
1400
1401
|
"resolution":"abacbdb5a7975098d77007c8","revision":"c557d8ec9a272ba1c1739dc3"},
|
|
1401
1402
|
"preflight":{"status":"complete","budgetMs":20000,"elapsedMs":53},"backendStatus":{"name":"tmux","installed":true,"started":false},
|
|
1402
1403
|
"harness":"pi","model":null,"modelSource":"native default","launchConfig":null,"backend":"tmux",
|
|
1403
|
-
"branch":"agents/rm-api","base":{"ref":"
|
|
1404
|
+
"branch":"agents/rm-api","base":{"ref":"github.com/nw/agents","oid":"66566512…"},"worktree":"/w/agents/rm/instances/rm-api/work",
|
|
1404
1405
|
"relation":null,"parentInstance":null,"policy":{"childSpawns":{"allowed":true,"origin":{"kind":"default","detail":"no spawn option: children allowed"}}},
|
|
1405
1406
|
"executable":"/usr/local/bin/pi",
|
|
1406
1407
|
"capabilities":[{"name":"nw-tools","origin":"member:github.com/nw/agents@66566512…"},{"name":"oats.okf","origin":"package:oats.okf@2.1.3"}],
|
|
@@ -1415,8 +1416,11 @@ it to a temporary copy (`soulFetched: true`).
|
|
|
1415
1416
|
else `null`) are canonical: never derive paths.
|
|
1416
1417
|
- `repo`: `--repo`, else the `clones:` entry, else `<deployment>/<member>`.
|
|
1417
1418
|
- `branch` defaults to `agents/<instance>` (`--branch` overrides); `base` is
|
|
1418
|
-
`--base`
|
|
1419
|
-
`
|
|
1419
|
+
`--base` resolved to `oid`. Without `--base`, when `repo` is a clone of the
|
|
1420
|
+
soul's repository, `base` is `{ref: <repo key>, oid: <the commit the spawn
|
|
1421
|
+
observed>}`, fetched into the clone at apply (`E_REMOTE_UNREADABLE` when it
|
|
1422
|
+
cannot be); otherwise `HEAD`. `E_BRANCH_EXISTS` and `E_BASE_UNKNOWN` refuse
|
|
1423
|
+
preview and apply alike.
|
|
1420
1424
|
- `subject` echoes `{soul, agentsRoot, dir}` byte-exact.
|
|
1421
1425
|
|
|
1422
1426
|
**Launch.**
|
|
@@ -1534,7 +1538,8 @@ with `--expect-decision` records the key and decision in `instance.json`.
|
|
|
1534
1538
|
**Result** (`oats spawn <soul> … --json`):
|
|
1535
1539
|
|
|
1536
1540
|
```json
|
|
1537
|
-
{"instance":"rm-api","agent":"rm","home":"/w/agents/rm/instances/rm-api","work":"worktree","branch":"agents/rm-api",
|
|
1541
|
+
{"instance":"rm-api","agent":"rm","home":"/w/agents/rm/instances/rm-api","work":"worktree","branch":"agents/rm-api",
|
|
1542
|
+
"base":{"ref":"github.com/nw/agents","oid":"66566512…"},"launched":true,"warnings":[],
|
|
1538
1543
|
"tmux":{"session":"oats-agents","window":"rm-api"},"backend":"tmux","repo":"/w/agents-repo","harness":"pi","model":null,"parent":null,"sibling":null,"relation":null,
|
|
1539
1544
|
"spawnOrigin":"operator","attach":"tmux attach -t oats-agents","decision":{"instance":"rm-api","revision":"c557d8ec9a272ba1c1739dc3"},"replayed":false,
|
|
1540
1545
|
"wake":{"requested":false,"saved":null,"error":null},"launchConfig":null,
|
|
@@ -1544,7 +1549,8 @@ with `--expect-decision` records the key and decision in `instance.json`.
|
|
|
1544
1549
|
|
|
1545
1550
|
(`decision` is abridged: it is the full bound decision.)
|
|
1546
1551
|
|
|
1547
|
-
- Always present: `instance, agent, home, work, branch,
|
|
1552
|
+
- Always present: `instance, agent, home, work, branch, base ({ref, oid}
|
|
1553
|
+
the new branch started at; `null` without one), launched, warnings
|
|
1548
1554
|
(array), tmux ({session, window} | null), backend ("tmux"), repo, harness,
|
|
1549
1555
|
model, parent,
|
|
1550
1556
|
sibling, relation, spawnOrigin (operator | instance), attach, launchConfig,
|
|
@@ -1608,7 +1614,8 @@ workspace-model fields (feature `instance-modules`):
|
|
|
1608
1614
|
|
|
1609
1615
|
```json
|
|
1610
1616
|
{"agent":"rm","kind":"persistent","instance":"rm-api","home":"/w/agents/rm/instances/rm-api","soulDir":"/w/agents/rm/souls/66566512168e",
|
|
1611
|
-
"repo":"/w/agents-repo","work":"worktree","branch":"agents/rm-api","
|
|
1617
|
+
"repo":"/w/agents-repo","work":"worktree","branch":"agents/rm-api","base":{"ref":"github.com/nw/agents","oid":"66566512…"},
|
|
1618
|
+
"harness":"pi","modelFrom":"harness-default","spawnOrigin":"operator",
|
|
1612
1619
|
"policy":{"childSpawns":{"allowed":true,"origin":{"kind":"default","detail":"no spawn option: children allowed"}}},
|
|
1613
1620
|
"modules":{"oats.okf":{"from":{"kind":"package","package":"oats.okf","version":"2.1.3","commit":"ab897841…","integrity":"sha256-bada35…","repoKey":"github.com/awebai/oats-okf"},
|
|
1614
1621
|
"commit":"ab897841…","digest":"sha256-9a0e…","materializedAt":"2026-09-28T10:08:01.100Z"}},
|
|
@@ -1635,6 +1642,8 @@ the keyed-spawn fields `decision`, `spawnIdempotencyKey`, `spawnCompleted` and
|
|
|
1635
1642
|
the copy at `<home>/.oats/modules/<cap>/`. Module skills are copied flat to
|
|
1636
1643
|
`<home>/.agents/skills/<skill>/` (homes spawned by 0.30.1 or earlier keep
|
|
1637
1644
|
`<home>/.agents/skills/<cap>/<skill>/`).
|
|
1645
|
+
- `base` (a worktree instance): `{ref, oid}`, the commit its branch started
|
|
1646
|
+
at, as the spawn result states it (see Placement under the spawn preview).
|
|
1638
1647
|
- `providers.<cap>`: the merged payload (`{}` when none).
|
|
1639
1648
|
- `workspace`: `{key, name, deployment, commit, resolution, standalone, soul,
|
|
1640
1649
|
layers}`. `name` is recorded, and every hook, command and operation of the
|
|
@@ -2023,8 +2032,15 @@ A first retire prints the **raw receipt**, not an envelope:
|
|
|
2023
2032
|
|
|
2024
2033
|
- `retention`: `{worktree: "retained" | "removed" | "absent", movedTo?,
|
|
2025
2034
|
branch, detachedAt?, recordedBranch, branchDeleted?,
|
|
2026
|
-
branchDeletionSkipped?: {expected, actual, reason}}`, or `null`
|
|
2027
|
-
non-worktree mode.
|
|
2035
|
+
branchDeletionSkipped?: {expected, actual, reason}}`, or `null` when no
|
|
2036
|
+
worktree step ran: a non-worktree mode, or a worktree kept for the retry.
|
|
2037
|
+
A retire whose hooks left cleanup outstanding keeps the worktree exactly as
|
|
2038
|
+
it was (with `worktreeRemoved: false`) and says why in `rollbackIncomplete`
|
|
2039
|
+
(`git worktree <path>: kept for the retry; outstanding: …`); the retry does
|
|
2040
|
+
the step once nothing else is outstanding. A work directory whose git admin
|
|
2041
|
+
entry is gone is never touched: it is an incomplete item (`git worktree
|
|
2042
|
+
<path>: its admin entry is missing; …`), and `--force` refuses it with
|
|
2043
|
+
`E_WORK_PRESERVATION_FAILED`.
|
|
2028
2044
|
- `--discard-worktree` removes the worktree. `--delete-branch` deletes the
|
|
2029
2045
|
worktree's verified branch (re-verified at deletion time) and implies
|
|
2030
2046
|
discarding; a mismatch deletes nothing and reports
|
package/docs/integrations.md
CHANGED
package/docs/knowledge.md
CHANGED
package/docs/official-catalog.md
CHANGED
|
@@ -10,7 +10,7 @@ or workspace membership alone does not make a package official.
|
|
|
10
10
|
| package | release | capabilities | package souls |
|
|
11
11
|
|---|---|---|---|
|
|
12
12
|
| `oats.framework` | `oats-framework/v1.4.1` (this repository) | `oats.core`, `oats.setup`, `oats.knowledge-theory` | `knowledge-theory-expert` |
|
|
13
|
-
| `oats.okf` | `v4.0
|
|
13
|
+
| `oats.okf` | `v4.1.0` | `oats.okf` (knowledge), `oats.okf-harvest`, `oats.okf-maintenance` | `knowledge-harvester`, `knowledge-maintainer` |
|
|
14
14
|
| `oats.aweb` | `v1.17.7` | `oats.aweb` (messaging) | |
|
|
15
15
|
| `oats.engineering` | `v1.5.0` | `oats.engineering-expert`, `oats.developer`, `oats.code-review` | `code-reviewer` |
|
|
16
16
|
| `oats.authoring` | `v1.0.3` | `oats.authoring` | |
|
|
@@ -27,7 +27,7 @@ no lock and adds nothing to an existing workspace.
|
|
|
27
27
|
## Find and use packages
|
|
28
28
|
|
|
29
29
|
- A workspace pins an official package by **bare version** in its
|
|
30
|
-
`packages:` map (`oats.okf: v4.0
|
|
30
|
+
`packages:` map (`oats.okf: v4.1.0`); `oats sync` resolves it through the
|
|
31
31
|
catalog to an exact commit, fetches it, verifies its integrity and locks it.
|
|
32
32
|
A package outside the catalog is written `git:<repo>@<ref>`. Pinning does
|
|
33
33
|
not join a team or adopt the publisher's workspace. See
|
package/docs/packages.md
CHANGED
|
@@ -44,14 +44,14 @@ whole organisation:
|
|
|
44
44
|
|
|
45
45
|
```yaml
|
|
46
46
|
packages:
|
|
47
|
-
oats.okf: v4.0
|
|
47
|
+
oats.okf: v4.1.0 # bare version → the official catalog
|
|
48
48
|
acme.tools: git:github.com/acme/tools@v0.4.0 # direct ref: git:<repo>@<tag or full OID>
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
- **Bare version** (`v4.0
|
|
51
|
+
- **Bare version** (`v4.1.0`, `4.1.0`, `1.0.0-rc.1`): the id is looked up in
|
|
52
52
|
the official catalog — `package-catalog.json` in the `oats` repo, or the file
|
|
53
53
|
named by `OATS_PACKAGE_CATALOG` — which supplies the repo url, the tag
|
|
54
|
-
convention (`v4.0
|
|
54
|
+
convention (`v4.1.0` or `oats-framework/v1.4.1`) and the payload path. An id
|
|
55
55
|
the catalog does not know is `E_PACKAGE_MISSING` ("use `git:<repo>@<ref>` for
|
|
56
56
|
a package outside the catalog"). The catalog is the reviewed official list
|
|
57
57
|
([official-catalog.md](official-catalog.md)) and the only way a
|
|
@@ -75,7 +75,7 @@ members:
|
|
|
75
75
|
- git:github.com/acme/platform
|
|
76
76
|
packages:
|
|
77
77
|
oats.framework: v1.4.1
|
|
78
|
-
oats.okf: v4.0
|
|
78
|
+
oats.okf: v4.1.0
|
|
79
79
|
oats.aweb: v1.17.7
|
|
80
80
|
teams:
|
|
81
81
|
platform: { team: "platform:acme.aweb.ai", description: Platform engineering }
|
|
@@ -105,7 +105,7 @@ decision recorded in the lock.
|
|
|
105
105
|
$ oats sync
|
|
106
106
|
workspace acme (github.com/acme/agents @ 3f2a9c1e)
|
|
107
107
|
members agents ✓↔ (@ 3f2a9c1e) platform ✓↔ (@ 77c0a1b2) billing ✗ (no-backlink)
|
|
108
|
-
packages acme.tools 0.4.0 ✓ (@ 47f4b816) oats.okf 4.0
|
|
108
|
+
packages acme.tools 0.4.0 ✓ (@ 47f4b816) oats.okf 4.1.0 ✓ (@ e331a996)
|
|
109
109
|
changed acme.tools — → 0.4.0 (@ 47f4b816)
|
|
110
110
|
souls 9 discovered (6 members, 1 external, 2 package, 0 disabled here) · 0 private capabilities
|
|
111
111
|
teams platform (shared) · this deployment's: oats teams
|
|
@@ -160,8 +160,8 @@ same workspace commit hold identical locks.
|
|
|
160
160
|
"source": "catalog:oats.okf",
|
|
161
161
|
"url": "https://github.com/awebai/oats-okf.git",
|
|
162
162
|
"path": "oats-package",
|
|
163
|
-
"version": "4.0
|
|
164
|
-
"commit": "
|
|
163
|
+
"version": "4.1.0",
|
|
164
|
+
"commit": "e331a9969d10aabddaa5824991f1846c7dedb388",
|
|
165
165
|
"integrity": "sha256-…",
|
|
166
166
|
"capabilities": ["oats.okf", "oats.okf-harvest", "oats.okf-maintenance"]
|
|
167
167
|
},
|
|
@@ -331,7 +331,7 @@ A soul that names one of the package's capabilities with
|
|
|
331
331
|
{
|
|
332
332
|
"policy": "docs/official-catalog.md",
|
|
333
333
|
"packages": {
|
|
334
|
-
"oats.okf": { "url": "https://github.com/awebai/oats-okf.git", "ref": "v4.0
|
|
334
|
+
"oats.okf": { "url": "https://github.com/awebai/oats-okf.git", "ref": "v4.1.0", "path": "oats-package" },
|
|
335
335
|
"oats.framework": { "url": "https://github.com/awebai/oats.git", "ref": "oats-framework/v1.4.1", "path": "oats-package" }
|
|
336
336
|
}
|
|
337
337
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# OATS 0.34.4
|
|
2
|
+
|
|
3
|
+
## Fixed
|
|
4
|
+
|
|
5
|
+
- **A worktree spawn branches from the member commit it observed, not from
|
|
6
|
+
the clone's stale local branch** (awebai/oats#445). When a member clone
|
|
7
|
+
(`clones:`, the convention path or `--repo`) was a human's checkout or a
|
|
8
|
+
shared reference, `oats spawn` cut the instance branch from whatever that
|
|
9
|
+
clone had checked out, often far behind the head the spawn had just
|
|
10
|
+
resolved the soul at, and nobody was told. Now:
|
|
11
|
+
- the branch starts at the commit the spawn observed for its decision. The
|
|
12
|
+
spawn fetches that commit by id into the clone, from the remote that names
|
|
13
|
+
the soul's repository;
|
|
14
|
+
- the clone's own branches, remote-tracking refs and work tree are never
|
|
15
|
+
moved;
|
|
16
|
+
- a commit that cannot be fetched refuses the spawn with
|
|
17
|
+
`E_REMOTE_UNREADABLE`, naming the clone and the commit. Nothing is created
|
|
18
|
+
and nothing falls back to the clone's branch;
|
|
19
|
+
- the spawn result states the start point: `base: <oid> (observed head of
|
|
20
|
+
<repo>)` in text and `base: {ref, oid}` in `--json`. `instance.json`
|
|
21
|
+
records it too.
|
|
22
|
+
|
|
23
|
+
`--base <ref>` still names an explicit start point in the clone, and a
|
|
24
|
+
`--repo` that is not a clone of the soul's repository still starts at its
|
|
25
|
+
`HEAD`.
|
|
26
|
+
|
|
27
|
+
- **A retire whose hook reports incomplete cleanup leaves the worktree as it
|
|
28
|
+
was** (awebai/oats#444). The worktree used to be moved or removed before
|
|
29
|
+
the home was quarantined, so its git admin entry could be gone by the time
|
|
30
|
+
the retry needed it. The retry's work inspection then failed, and the hook
|
|
31
|
+
that asked to be retried could never run again. Now:
|
|
32
|
+
- the home is quarantined before any worktree step: the worktree, its admin
|
|
33
|
+
entry and the branch stay exactly as they were. `retire --json` reports
|
|
34
|
+
`retention: null` and `worktreeRemoved: false`, and `rollbackIncomplete`
|
|
35
|
+
says `git worktree <path>: kept for the retry; outstanding: …`;
|
|
36
|
+
- the retry does the worktree step only once nothing else is outstanding:
|
|
37
|
+
retain by default, remove with `--discard-worktree` or `--delete-branch`.
|
|
38
|
+
Only a failed spawn's quarantine that owes the worktree removes it;
|
|
39
|
+
- `--force` removes the home regardless, so it does the worktree step first
|
|
40
|
+
and leaves no admin entry pointing into a removed home;
|
|
41
|
+
- a work directory whose admin entry is gone is reported as incomplete, the
|
|
42
|
+
hooks still run, and the directory is never removed. `--force` refuses it
|
|
43
|
+
(`E_WORK_PRESERVATION_FAILED`) until you move it out or delete it by hand.
|
|
44
|
+
Upgrade before forcing: an older kernel's `--force` still removes such
|
|
45
|
+
a directory along with the home.
|
|
46
|
+
|
|
47
|
+
- **The spawn's fetch of its base reads remote names safely** (follow-up to
|
|
48
|
+
#445): the remote is passed after `--end-of-options`, so a remote whose
|
|
49
|
+
name reads like an option is never taken as one, and remote urls are read
|
|
50
|
+
NUL-separated (`git config -z`), so a newline in one url cannot forge
|
|
51
|
+
another remote.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# OATS 0.35.0
|
|
2
|
+
|
|
3
|
+
## Added
|
|
4
|
+
|
|
5
|
+
- **oats.okf 4.1.0** (catalog and workspace pin, and the bundled mirrors):
|
|
6
|
+
`oats okf harvest --once`, a one-shot reviewed harvest of one seat from an
|
|
7
|
+
explicit record set (awebai/oats-okf#37). A seat that moved (classic to v2)
|
|
8
|
+
or was spawned with harvest off had no way to get its notes into the
|
|
9
|
+
knowledge base. The operator now runs, from the deployment:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
oats okf harvest --once --home <seat home> --records <manifest> --soul <its soul> [--override-opt-out]
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
- The manifest lists note files, each with its sha256, in the seat's home
|
|
16
|
+
or a listed archive directory. Each file is checked against the bytes
|
|
17
|
+
used, with no symlinks, directories or globbing. A bad entry refuses
|
|
18
|
+
everything before anything is stored.
|
|
19
|
+
- The harvester judges and opens a PR that the knowledge-maintainer
|
|
20
|
+
reviews, as for every harvest. It writes only to the soul's own nodes.
|
|
21
|
+
- Nothing is registered: no schedule and no capture. Rerunning the same
|
|
22
|
+
command continues a large set run by run (each run says how many inputs
|
|
23
|
+
remain), or answers `already-delivered`.
|
|
24
|
+
- A soul's opt-out is refused unless `--override-opt-out`, which the PR
|
|
25
|
+
records. The host's harvest switch does not apply.
|
|
26
|
+
- Archived session records come in a later oats.okf, through `oats capture
|
|
27
|
+
--file` (below).
|
|
28
|
+
|
|
29
|
+
- **`oats capture --file <path> --format cc|pi|codex --home <instance home> [--json]`**
|
|
30
|
+
(feature `capture-file`). It captures one session file, such as an
|
|
31
|
+
archived session the `--home` sweep can no longer find, exactly as
|
|
32
|
+
`--home` capture of that instance would. It is for oats.okf's one-shot
|
|
33
|
+
reviewed harvest of archived sessions (awebai/oats-okf#37).
|
|
34
|
+
- The owner is explicit (`--owner` or `TURN_RECORD_OWNER`, never the
|
|
35
|
+
hostname), and `--home` must be an instance home.
|
|
36
|
+
- The stream identity is the one `--home` capture writes, so capturing the
|
|
37
|
+
same session either way, or again, appends nothing.
|
|
38
|
+
- The format is stated and checked against the file's session header,
|
|
39
|
+
never sniffed.
|
|
40
|
+
- Only one regular file is read, once, from its descriptor: a symlink,
|
|
41
|
+
FIFO or directory is refused.
|
|
42
|
+
- The receipt binds to the bytes: `{thread, firstTurnId, lastTurnId,
|
|
43
|
+
turns, ignored, sha256, ...}`.
|
|
44
|
+
- An outcome that binds nothing is an error code: `E_IGNORED`,
|
|
45
|
+
`E_NO_TURNS`, `E_FORMAT`, `E_NOT_REGULAR_FILE`, `E_FILE_UNREADABLE`,
|
|
46
|
+
`E_USAGE`, and `E_CAPTURE_FAILED` for a pass that failed (`appended:
|
|
47
|
+
null`). See packages/record/README.md.
|
|
48
|
+
|
|
49
|
+
## Changed
|
|
50
|
+
|
|
51
|
+
- **The Desktop accepts OATS CLIs `>=0.25.8 <0.36.0`**, so it runs against
|
|
52
|
+
this release's kernel. Install the CLI and the Desktop 0.35.0 together: the
|
|
53
|
+
Desktop 0.34.x refuses a 0.35 CLI.
|
|
@@ -152,8 +152,8 @@ composed skills and instructions, a spawn records:
|
|
|
152
152
|
"commit": "3f2a9c1e…", "digest": "sha256-…", "materializedAt": "2026-09-24T10:12:44.118Z"
|
|
153
153
|
},
|
|
154
154
|
"oats.okf": {
|
|
155
|
-
"from": { "kind": "package", "package": "oats.okf", "version": "4.0
|
|
156
|
-
"commit": "
|
|
155
|
+
"from": { "kind": "package", "package": "oats.okf", "version": "4.1.0", "commit": "e331a996…", "integrity": "sha256-…", "repoKey": "github.com/awebai/oats-okf" },
|
|
156
|
+
"commit": "e331a996…", "digest": "sha256-…", "materializedAt": "2026-09-24T10:12:44.201Z"
|
|
157
157
|
}
|
|
158
158
|
},
|
|
159
159
|
"providers": {
|
|
@@ -432,6 +432,16 @@ retained home (plus the usual quarantine marker when hooks reported incomplete
|
|
|
432
432
|
cleanup), shows in `oats status` and the Desktop as a failed deferred
|
|
433
433
|
retirement, and is retried and cleared with `oats retire <instance>`.
|
|
434
434
|
|
|
435
|
+
When a retire hook reports incomplete cleanup, the home is quarantined before
|
|
436
|
+
any worktree step: the worktree, its git admin entry and the branch stay
|
|
437
|
+
exactly as they were, so the retry can reach the hook and the work it needs.
|
|
438
|
+
The retry does the worktree step only once nothing else is outstanding:
|
|
439
|
+
retain by default, remove with `--discard-worktree` or `--delete-branch`.
|
|
440
|
+
`--force` removes the home regardless, so it does the worktree step first. A
|
|
441
|
+
work directory whose git admin entry is gone is never removed: the hooks still
|
|
442
|
+
run, the home is kept, and `--force` refuses it until you move the directory
|
|
443
|
+
out or delete it by hand.
|
|
444
|
+
|
|
435
445
|
Retire never deletes a branch unless you pass `--delete-branch`, and then
|
|
436
446
|
only the verified branch: not on a quarantine, its retry or `--force`. A
|
|
437
447
|
spawn that fails deletes the branch it created only while the branch's tip
|
|
@@ -472,6 +482,21 @@ as `--repo`, then `oats-local.yaml` `clones:`, then `<deployment>/<member name>`
|
|
|
472
482
|
(`E_CLONE_MISSING` / `E_CLONE_MISMATCH` otherwise — see
|
|
473
483
|
[configuration.md](configuration.md)).
|
|
474
484
|
|
|
485
|
+
The branch starts at the commit of the soul's repository that the spawn
|
|
486
|
+
observed (the one it resolved the soul at), not at what the clone has checked
|
|
487
|
+
out: the clone may be a human's checkout or a shared reference, far behind.
|
|
488
|
+
The spawn fetches that commit by id into the clone from the remote that names
|
|
489
|
+
the repository, and never moves the clone's own branches, remote-tracking refs
|
|
490
|
+
or work tree. A commit that cannot be fetched refuses the spawn
|
|
491
|
+
(`E_REMOTE_UNREADABLE`, naming the clone and the commit); it never falls back
|
|
492
|
+
to the clone's branch. The fetch never prompts (ssh runs in BatchMode, askpass
|
|
493
|
+
is refused). A server that serves only its advertised refs (protocol v0 without
|
|
494
|
+
`allowAnySHA1InWant`) refuses a commit its branches have moved past; `--base`
|
|
495
|
+
is then the way on. `--base <ref>` names another start point in the clone;
|
|
496
|
+
a `--repo` that is not a clone of the soul's repository starts at its `HEAD`.
|
|
497
|
+
The spawn result and `instance.json` record the start point as
|
|
498
|
+
`base: {ref, oid}`.
|
|
499
|
+
|
|
475
500
|
Use this for agents that will edit code or docs independently.
|
|
476
501
|
|
|
477
502
|
Rules:
|
package/docs/workspaces.md
CHANGED
|
@@ -55,7 +55,7 @@ members: # repo refs, NO @revision (E_WORKSPAC
|
|
|
55
55
|
|
|
56
56
|
packages: # the ONLY versioned things
|
|
57
57
|
oats.framework: v1.4.1 # bare version → resolves through the official catalog
|
|
58
|
-
oats.okf: v4.0
|
|
58
|
+
oats.okf: v4.1.0
|
|
59
59
|
acme.tools: git:github.com/acme/tools@v0.4.0 # outside the catalog → git:<repo>@<tag|OID>; still a package
|
|
60
60
|
|
|
61
61
|
teams: # SHARED teams: the same provider team for everyone
|