@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 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
@@ -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.7","ref":"v4.0.7"}}],
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.7","kind":"package","package":"oats.okf",
786
- "version":"4.0.7","repoKey":"github.com/awebai/oats-okf","commit":"e460b29a…","teams":null,"defaultTeam":null,"private":false,
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.7",
876
- "commit":"e460b29a…","path":"oats-package/capabilities/oats-okf",
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":"e460b29a…",
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":"HEAD","oid":"66566512…"},
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":"HEAD","oid":"66566512…"},"worktree":"/w/agents/rm/instances/rm-api/work",
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` (default `HEAD`) resolved to `oid`. `E_BRANCH_EXISTS` and
1419
- `E_BASE_UNKNOWN` refuse preview and apply alike.
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","launched":true,"warnings":[],
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, launched, warnings
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","harness":"pi","modelFrom":"harness-default","spawnOrigin":"operator",
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` for a
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
@@ -40,7 +40,7 @@ arrives from.
40
40
  ```yaml
41
41
  # oats-workspace.yaml: one default per slot, for every soul
42
42
  packages:
43
- oats.okf: v4.0.7
43
+ oats.okf: v4.1.0
44
44
  oats.aweb: v1.17.7
45
45
  oats.linear: v1.0.1
46
46
  oats.jira: v1.0.1
package/docs/knowledge.md CHANGED
@@ -26,7 +26,7 @@ The workspace pins the package and fills the slot for every soul by default:
26
26
  ```yaml
27
27
  # oats-workspace.yaml (excerpt)
28
28
  packages:
29
- oats.okf: v4.0.7
29
+ oats.okf: v4.1.0
30
30
  defaults:
31
31
  knowledge: { oats.okf: { from: package } }
32
32
  stores:
@@ -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.7` | `oats.okf` (knowledge), `oats.okf-harvest`, `oats.okf-maintenance` | `knowledge-harvester`, `knowledge-maintainer` |
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.7`); `oats sync` resolves it through the
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.7 # bare version → the official catalog
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.7`, `4.0.7`, `1.0.0-rc.1`): the id is looked up in
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.7` or `oats-framework/v1.4.1`) and the payload path. An id
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.7
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.7 ✓ (@ e460b29a)
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.7",
164
- "commit": "e460b29aaf23db5728d7c64f7b5fb63f5014546b",
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.7", "path": "oats-package" },
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.7", "commit": "e460b29a…", "integrity": "sha256-…", "repoKey": "github.com/awebai/oats-okf" },
156
- "commit": "e460b29a…", "digest": "sha256-…", "materializedAt": "2026-09-24T10:12:44.201Z"
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:
@@ -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.7
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