@awebai/oats 0.22.3 → 0.22.4

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "capability": "oats.aweb",
3
3
  "command": "aweb",
4
- "version": "1.10.0",
4
+ "version": "1.10.1",
5
5
  "compatibility": {
6
6
  "oats": ">=0.22.3"
7
7
  },
@@ -42,6 +42,18 @@
42
42
  "why": "an ambient aweb pi extension, if one is installed, must honour AWEB_DELIVERY=session (0.3.10 and later); an older one would open a second event stream beside the wake broker; no extension at all is fine",
43
43
  "install": "pi install npm:@awebai/pi@latest",
44
44
  "ifInstalled": true
45
+ },
46
+ {
47
+ "runtime": "claude",
48
+ "package": "aweb-channel@awebai-marketplace",
49
+ "marketplace": "awebai/claude-plugins",
50
+ "minVersion": "1.7.9",
51
+ "when": {
52
+ "delivery": "session"
53
+ },
54
+ "why": "an ambient aweb-channel plugin for Claude Code, if one is installed, must honour AWEB_DELIVERY=session (1.7.9 and later); an older one starts its own channel server beside the wake broker and can fetch and acknowledge a message before the broker delivers it; no plugin at all is fine",
55
+ "install": "update the aweb-channel plugin from the awebai marketplace in Claude Code",
56
+ "ifInstalled": true
45
57
  }
46
58
  ],
47
59
  "skills": [
@@ -148,8 +148,11 @@ soul through the binding's `settings:` map.
148
148
  - `delivery: channel | session` (default `channel`). `session` hands
149
149
  notification delivery to the host wake broker: `AWEB_DELIVERY=session` in
150
150
  the launch environment (declared by the manifest), no Claude channel flag,
151
- a pi extension that honours the opt-out (`@awebai/pi` 0.3.10 or later,
152
- enforced as a conditional requirement with a version floor), and a briefing
151
+ a pi extension that honours the opt-out (`@awebai/pi` 0.3.10 or later) and
152
+ a Claude Code channel plugin that does too (`aweb-channel` 1.7.9 or later),
153
+ both enforced as conditional requirements with a version floor when
154
+ installed (an older plugin starts its own channel server beside the broker
155
+ and can fetch a message before the broker delivers it), and a briefing
153
156
  and registration of the home with the host wake broker (`aw wake register`).
154
157
  Until an aw that ships `aw wake` exists (aweb-abil), session mode REFUSES
155
158
  to spawn rather than leave an instance that nothing wakes: it is for broker
@@ -27,21 +27,25 @@ Every continuing seat must have a supported OATS launch, composition,
27
27
  status, handover and retirement path. Its outstanding work, knowledge and
28
28
  required skills must survive a change of runtime session; identity/address
29
29
  continuity follows the explicit policy for that seat.
30
- Every remembering role must have a tested learning path; reviewers retain
31
- their explicit exclusion from accumulated memory. Config discovery alone
32
- establishes none of this.
33
-
34
- The installed baseline is OATS 0.22.2, including native Pi/Claude/Codex,
35
- tmux/Herdr, shared `yolo`, remote CLI launch/terminals and deferred retirement.
36
- The Mac Desktop app is installed and passed packaged renderer/PTY launch checks.
37
- Official oats.okf 1.5.0 provides record-fed harvesting. A source candidate for
38
- 0.22.3 adds the retained-authority binding, remote Desktop roster/actions and
39
- retirement corrections; that candidate is not yet a published release.
30
+ Every remembering role must have a tested learning path. Preserve each role's
31
+ explicit policy: Cjr reviewers exclude accumulated memory; Themis uses
32
+ reviewed learning. Config discovery alone establishes none of this.
33
+
34
+ The installed baseline is published OATS 0.22.3 on this Mac and `aweb-agents`,
35
+ including native Pi/Claude/Codex, tmux/Herdr, shared `yolo`, remote Desktop
36
+ roster/actions, retained-authority binding and corrected deferred retirement.
37
+ The downloaded Mac Desktop app passed codesign, packaged renderer and PTY
38
+ launch checks. Official oats.okf 1.5.0 provides record-fed harvesting; each
39
+ deployment must select its authenticated provider. Version 1.5.1, adding
40
+ harvest-runtime selection and detection of unadvanced record plans, remains
41
+ under independent review and is not yet published.
40
42
 
41
43
  No standing seat has transferred yet. Cjr's worker pilot has landed reviewed
42
44
  code and knowledge; ordinary retirement passed using the next-patch candidate.
43
- A real harvester's automatic deferred completion, successor knowledge use and
44
- session-broker delivery remain explicit acceptance checks.
45
+ A real harvester's automatic deferred completion and successor knowledge use
46
+ remain explicit acceptance checks. The reviewed aweb broker candidate passed
47
+ real harness delivery; installation of its published release as the normal
48
+ host service remains a prerequisite for standing cutover.
45
49
 
46
50
  ## Scope inventory
47
51
 
@@ -54,10 +58,10 @@ of continuing seats.
54
58
  | `~/awebai/oats` | Live Claude coordinator and Codex lead; managed review workers also running | Oats owns coordinator handover; lead owns lead handover; preserve established identities |
55
59
  | `~/cjr` | Preparation `5afb3e8b`; developer pilot landed on master `062e2c75`; legacy Merlin and Minerva live | Merlin owns safe handovers; preserve his DID/address; prove automatic harvest completion and successor use |
56
60
  | `~/awebai/aweb` | Live Claude coordinator and frontend in legacy homes | Oats owns coordinator handover; lead coordinates frontend with aweb after its current work; preserve identities and cover child repositories |
57
- | `~/tsm` | Five live seats: Zeus, Prometeo, Argos, Themis on Claude; Hermes on Codex. No OATS config/souls found | Zeus prepared the five-seat handover plan; begin with Themis at a safe boundary, Zeus last; preserve session-local schedules and production authority |
61
+ | `~/tsm` | Five live seats: Zeus, Prometeo, Argos, Themis on Claude; Hermes on Codex. First-seat Themis config/soul packet under owner review | Zeus prepared the five-seat handover plan; begin with Themis at a safe boundary, Zeus last; preserve session-local schedules and production authority |
58
62
  | `~/prj/beadhub-all` | Live Codex session, despite stale offline roster | Beadhub accepted preparation and is at a safe boundary; retain its global identity, native Codex and separate canonical code roots under `~/awebai/beadhub`; billing remains separately gated |
59
63
  | `~/prj/docflow` | Live Claude seat identified itself as local `juan.aweb.ai/alice` on `docflow:juan.aweb.ai` | Owner Juan; finish running mail backfill and register checks before transfer; retain identity, memory and Minerva route; accountant-sync remains deliberately unloaded |
60
- | `ai.aweb` on `aweb-agents` | Athena last seen 53 days ago; remote legacy home exists in inventory | Aweb and oats own archival inspection; do not resurrect as a continuing seat |
64
+ | `ai.aweb` on `aweb-agents` | Aweb confirms Athena intentionally inactive; remote legacy home retained | Aweb and oats own archival inspection; do not resurrect as a continuing seat |
61
65
  | `~/awebai/demo-aweb/bob` | Live Pi demo | Aweb owns safe stop and archival disposition; it is not an operating-team migration |
62
66
  | `~/.turn-record` | Live Pi capture service under launchd | Retain as infrastructure; qualify record capture separately from standing seats |
63
67
 
@@ -101,7 +105,9 @@ uniquely named so no existing address has to be removed for the experiment.
101
105
 
102
106
  Merlin retains his identity; other continuing seats follow their accepted
103
107
  policy. Oats implemented explicit source-authority binding in oats.aweb 1.10.0,
104
- reviewed and pinned for the next kernel patch. A disposable rehearsal verified
108
+ reviewed and shipped with OATS 0.22.3. Published oats.aweb 1.10.1 additionally
109
+ requires an installed ambient Claude channel to be at least 1.7.9 for session
110
+ delivery, matching the existing Pi extension floor of 0.3.10. A disposable rehearsal verified
105
111
  stable identity/address, existing conversations, heartbeat, exclusive holder
106
112
  refusal, rollback and authority-preserving retirement. Aweb supplied this
107
113
  supported handover:
@@ -249,9 +255,14 @@ the shared rollout record.
249
255
  session-local schedules. Production credentials remain solely with the
250
256
  authorized production operator. His plan reserves Zeus's final cutover
251
257
  for Juan's presence; the other seats can prepare in the meantime.
252
- - BeadHub supplied its retained-identity and source-root brief through aweb
253
- mail. It awaits the reviewed declarative binding and cutover recipe.
254
- Its Stripe-account dependency and production cutover gates remain separate.
258
+ - BeadHub configuration/soul commit `3ee13a8` in `awebai/beadhub-saas`
259
+ (`~/awebai/beadhub/beadhub-saas`) was independently ACKed by lead and
260
+ landed on `main`. Its tracked deployment template is materialized at the canonical
261
+ parent workspace, with trusted official capabilities and a clean actual
262
+ doctor result. The soul retains SaaS Git provenance and uses workspace mode
263
+ as a coordinator across the three canonical repositories. Its legacy holder
264
+ remains live; authenticated harvest-model configuration and the published
265
+ broker service precede activation. Stripe and production gates remain separate.
255
266
  - Docflow supplied its own identity and handover through its terminal. Its
256
267
  backfill and register verification define the safe boundary. Preserve its
257
268
  Claude memory and existing credentials in place; verify filesystem/TCC
@@ -264,6 +275,23 @@ the shared rollout record.
264
275
  the cross-team coordinator identity/contact policy explicitly before
265
276
  relying on those routes; do not silently replace retained identities.
266
277
  - Real remote Claude launch, terminal input and detach survival passed.
267
- Remote Desktop projection and exact-home lifecycle are under independent
268
- review for the next patch. Remote harvester completion remains blocked by
269
- provider authentication, and no standing remote seat is declared migrated.
278
+ Remote Desktop projection and exact-home lifecycle shipped in 0.22.3; the
279
+ installed remote CLI serves the real registered roster. Remote harvester
280
+ completion remains blocked by provider authentication, and no standing
281
+ remote seat is declared migrated.
282
+ - The aweb broker candidate `30469e22` ran as a private launchd service against
283
+ published OATS 0.22.3. Real Claude and Codex sessions in tmux and Pi
284
+ in Herdr, with Claude channel 1.7.9 and Pi extension 0.3.10, fetched mail and replied with exact qualification tokens,
285
+ with all GUI viewers closed. Pi also answered a sender-waiting chat. Mail
286
+ sent while the broker was stopped was recovered after restart. After the
287
+ Codex harness stopped, its registration became inactive and a subsequent
288
+ message remained unread. Pause also survived a daemon restart, keeping mail
289
+ unread until resume, after which the agent replied. The candidate does not
290
+ fetch or acknowledge mail.
291
+ Published aw installation and standing-seat acceptance are still separate.
292
+ - Qualification found that tmux output loses tab separators in a minimal
293
+ launchd environment without a UTF-8 locale. Independently reviewed kernel
294
+ fix `a0b0e14` adds tmux UTF-8 mode; until it ships, the host service specifies
295
+ `LC_ALL=en_US.UTF-8`. Existing Claude plugin 1.7.8 also consumed mail before
296
+ the broker wake; updating to 1.7.9 eliminated that competing delivery path.
297
+ The deployed oats.aweb 1.10.1 floor now rejects the incompatible version.
@@ -0,0 +1,40 @@
1
+ # OATS v0.22.4
2
+
3
+ Two fixes found by running the wake broker and the record-fed harvester as
4
+ real host services, the oats.aweb 1.10.1 floor, and the managed lead soul.
5
+
6
+ ## Session commands under a service locale
7
+
8
+ launchd starts services without a UTF-8 locale, and tmux then replaces the
9
+ tab delimiters in its list-panes output with underscores, so every session
10
+ inspection from the wake broker reported an invalid pane. The shared session
11
+ helper now runs tmux in UTF-8 mode (`-u`), which preserves the delimiters
12
+ regardless of the service locale and makes typed input UTF-8-safe.
13
+
14
+ ## Record windows without the search index
15
+
16
+ `recall --thread --json` used to open the record's SQLite search index just
17
+ to extract turn text, and a capture indexing a large session cache could hold
18
+ that database locked for longer than the harvester waits. Window reads now
19
+ come from the journals alone; the search index opens only for indexed
20
+ search, show and reindex.
21
+
22
+ ## Bundled: oats.aweb 1.10.1
23
+
24
+ Session-mode delivery now requires an installed Claude Code channel plugin
25
+ to be `aweb-channel` 1.7.9 or later (as it already required `@awebai/pi`
26
+ 0.3.10): an older plugin starts its own channel server beside the wake
27
+ broker and can fetch a message before the broker delivers it.
28
+
29
+ ## Managed operating-lead soul
30
+
31
+ `agents/lead/soul` is tracked: the operating lead's role instructions and
32
+ two knowledge notes (runtime and messaging ownership; where rollout state
33
+ lives), ready for a retained-identity binding at its cutover.
34
+
35
+ ## Also
36
+
37
+ - `docs/operating-team-migration.md` records the published 0.22.3 rollout and
38
+ the live wake-broker acceptance on Claude, Codex and Pi.
39
+ - oats.okf 1.5.1 (harvest-runtime, promotion exclusions, replan detector) is
40
+ not in this release; it ships when its independent review completes.
@@ -6,7 +6,9 @@ import { inspectHerdr, inputHerdr, herdrCommand } from "./herdr.mjs";
6
6
 
7
7
  const shells = new Set(["sh", "bash", "zsh", "fish", "dash", "ksh", "login"]);
8
8
  function tmux(target, args, { exec = execFileSync, input } = {}) {
9
- return exec("tmux", ["-S", target.socket, ...args], {
9
+ // launchd does not supply a UTF-8 locale. In that environment tmux replaces
10
+ // the tab delimiters in list-panes output with underscores unless forced.
11
+ return exec("tmux", ["-u", "-S", target.socket, ...args], {
10
12
  encoding: "utf8", input, timeout: 10000, maxBuffer: 1024 * 1024,
11
13
  stdio: ["pipe", "pipe", "pipe"],
12
14
  });
@@ -10,7 +10,9 @@ export function prepareSessionViewer(target, { exec = execFileSync } = {}) {
10
10
  delete env.HERDR_SESSION;
11
11
  return { binary: target.binary, args: ["terminal", "attach", target.terminalId], env, cleanup() {} };
12
12
  }
13
- const run = (args) => exec("tmux", ["-S", target.socket, ...args], {
13
+ // UTF-8 mode (-u) like the shared session helper: a service without a
14
+ // UTF-8 locale (launchd) otherwise mangles tmux output.
15
+ const run = (args) => exec("tmux", ["-u", "-S", target.socket, ...args], {
14
16
  encoding: "utf8", timeout: 10000, stdio: ["ignore", "pipe", "pipe"],
15
17
  }).trim();
16
18
  const viewer = `oatsview-${process.pid}-${randomUUID().slice(0, 8)}`;
@@ -28,7 +30,7 @@ export function prepareSessionViewer(target, { exec = execFileSync } = {}) {
28
30
  run(["bind-key", "-T", "oatsview-locked", "WheelUpPane", "if-shell", "-F", "#{||:#{pane_in_mode},#{mouse_any_flag}}", "send-keys -M", "copy-mode -e; send-keys -M"]);
29
31
  run(["set-option", "-t", viewer, "mouse", "on"]);
30
32
  const env = { ...process.env }; delete env.TMUX;
31
- return { binary: "tmux", args: ["-S", target.socket, "attach-session", "-t", `=${viewer}`], env, cleanup };
33
+ return { binary: "tmux", args: ["-u", "-S", target.socket, "attach-session", "-t", `=${viewer}`], env, cleanup };
32
34
  } catch (e) { cleanup(); throw e; }
33
35
  }
34
36
 
@@ -7,7 +7,7 @@
7
7
  },
8
8
  "oats.aweb": {
9
9
  "url": "https://github.com/awebai/oats-aweb.git",
10
- "ref": "v1.10.0",
10
+ "ref": "v1.10.1",
11
11
  "path": "oats-package"
12
12
  },
13
13
  "oats.jira": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@awebai/oats",
3
- "version": "0.22.3",
3
+ "version": "0.22.4",
4
4
  "description": "OATS (Open Agent Team Specification) — durable souls, disposable instances, targetable capability packages, and the runtime-neutral oats CLI/kernel.",
5
5
  "keywords": [
6
6
  "agents",
@@ -23,7 +23,7 @@ import { join } from "node:path";
23
23
  import process from "node:process";
24
24
 
25
25
  import { RecordStore } from "../lib/store.mjs";
26
- import { RecordIndex } from "../lib/index-db.mjs";
26
+ import { extractTurnText, RecordIndex } from "../lib/index-db.mjs";
27
27
 
28
28
  function parseArgs(argv) {
29
29
  const args = { _: [] };
@@ -40,16 +40,19 @@ function parseArgs(argv) {
40
40
  const args = parseArgs(process.argv.slice(2));
41
41
  const root = args.root ?? process.env.TURN_RECORD_ROOT ?? join(homedir(), ".turn-record");
42
42
  const store = new RecordStore(root, {});
43
- const index = new RecordIndex(store);
43
+ let index;
44
+ const getIndex = () => (index ??= new RecordIndex(store));
44
45
 
45
46
  try {
46
47
  if (args.reindex) {
48
+ const index = getIndex();
47
49
  index.rebuild();
48
50
  console.log(JSON.stringify(index.counts()));
49
51
  process.exit(0);
50
52
  }
51
53
 
52
54
  if (args.show) {
55
+ const index = getIndex();
53
56
  const { resolveTurn } = await import("../lib/index-db.mjs");
54
57
  const byId = store.readAll();
55
58
  const turn = resolveTurn(store, index, args.show, byId);
@@ -111,7 +114,7 @@ try {
111
114
  // A window is a bounded read: a consumer that plans one (the OKF
112
115
  // harvester) sizes it with --ids-only first, then reads exactly that.
113
116
  const out = window.map((t) => {
114
- const docs = index.extractText(t);
117
+ const docs = extractTurnText(t);
115
118
  const base = { id: t.id, ts: t.ts, thread: t.thread, kind: t.kind, source: t.provenance?.source ?? null };
116
119
  const full = { ...base, text: docs.map((d) => ({ role: d.role, text: d.text })) };
117
120
  // bytes = what this turn occupies in the pretty-printed --json answer,
@@ -123,6 +126,7 @@ try {
123
126
  process.exit(0);
124
127
  }
125
128
 
129
+ const index = getIndex();
126
130
  const limit = args.limit ? Number(args.limit) : 20;
127
131
  let rows;
128
132
  if (query) {
@@ -164,5 +168,5 @@ try {
164
168
  console.log(` ${r.id}`);
165
169
  }
166
170
  } finally {
167
- index.close();
171
+ index?.close();
168
172
  }
@@ -413,20 +413,7 @@ export class RecordIndex {
413
413
  // Text documents for one turn. Mail/chat: one doc. Session: one doc per
414
414
  // conversational event extracted from the transcript blob.
415
415
  extractText(turn) {
416
- if (turn.kind === "note" && turn.body?.segment) return []; // dedicated role "segment" row
417
- if (turn.kind === "mail" || turn.kind === "chat" || turn.kind === "note") {
418
- const subject = turn.body?.subject ?? "";
419
- const text = turn.body?.text ?? "";
420
- const joined = subject ? subject + "\n" + text : text;
421
- return joined.trim() ? [{ loc: "", role: turn.kind, text: joined }] : [];
422
- }
423
- if (turn.kind === "session" && typeof turn.body?.line === "string") {
424
- const loc = `line:${turn.provenance?.origin?.line ?? 0}`;
425
- return extractSessionTextFor(turn.provenance?.source, Buffer.from(turn.body.line, "utf8")).map(
426
- (d) => ({ ...d, loc }),
427
- );
428
- }
429
- return [];
416
+ return extractTurnText(turn);
430
417
  }
431
418
 
432
419
  // FTS query with optional filters. Returns rows with turn metadata and a
@@ -502,6 +489,24 @@ export class RecordIndex {
502
489
  }
503
490
  }
504
491
 
492
+ // Journal text extraction is independent of the derived search database.
493
+ export function extractTurnText(turn) {
494
+ if (turn.kind === "note" && turn.body?.segment) return []; // dedicated role "segment" row
495
+ if (turn.kind === "mail" || turn.kind === "chat" || turn.kind === "note") {
496
+ const subject = turn.body?.subject ?? "";
497
+ const text = turn.body?.text ?? "";
498
+ const joined = subject ? subject + "\n" + text : text;
499
+ return joined.trim() ? [{ loc: "", role: turn.kind, text: joined }] : [];
500
+ }
501
+ if (turn.kind === "session" && typeof turn.body?.line === "string") {
502
+ const loc = `line:${turn.provenance?.origin?.line ?? 0}`;
503
+ return extractSessionTextFor(turn.provenance?.source, Buffer.from(turn.body.line, "utf8")).map(
504
+ (d) => ({ ...d, loc }),
505
+ );
506
+ }
507
+ return [];
508
+ }
509
+
505
510
  // Claude Code text extraction, re-exported for compatibility; the
506
511
  // per-format extractors live in formats.mjs.
507
512
  export const extractSessionText = extractCcText;