@awebai/oats 0.22.12 → 0.22.16

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.
@@ -44,7 +44,7 @@ const jsonFail = (code, message) => { process.stdout.write(JSON.stringify({ sche
44
44
  // --help/-h never runs a command here either (the kernel answers it from the
45
45
  // manifest since 0.22.6; this keeps an older kernel from spawning a harvester).
46
46
  if (process.argv.slice(2).some((a) => a === "--help" || a === "-h")) {
47
- process.stdout.write("oats okf harvest [--json] [--from-record] [--force] promote this instance's pending notes (and record windows) into its soul by spawning a memory-harvest worker; --help never spawns\noats okf status [--json]\n");
47
+ process.stdout.write("oats okf harvest [--json] [--from-record] [--force] promote this instance's pending notes (and record windows) into its soul by spawning a memory-harvest worker; --help never runs it\noats okf inspect [--json] answer this instance's working knowledge (STATE.md, log.md, pending notes) as labeled documents\n");
48
48
  process.exit(0);
49
49
  }
50
50
  const event = process.env.OATS_EVENT || process.argv[2];
@@ -473,6 +473,30 @@ _(the single next action — keep this current; a fresh session on any model res
473
473
  if (JSON_MODE) jsonFail(e.code || "E_HARVEST_FAILED", `harvest spawn failed (notes are safe on disk): ${e.message || e}`);
474
474
  warnFail(`harvest spawn failed (notes are safe on disk): ${e.message || e}`);
475
475
  }
476
+ } else if (event === "inspect") {
477
+ // VIEW OPERATION (kernel contract, docs/design/operations-contract.md):
478
+ // the instance's working knowledge as labeled documents, read from the
479
+ // home this command runs in. Text only; paths are provenance for the
480
+ // reader. Answers the JSON-v1 envelope regardless of --json.
481
+ try {
482
+ const CAP = 256 * 1024;
483
+ const doc = (label, file) => {
484
+ if (!existsSync(file)) return null;
485
+ const bytes = readFileSync(file);
486
+ const truncated = bytes.length > CAP;
487
+ let text = truncated ? bytes.subarray(0, CAP).toString("utf8") : bytes.toString("utf8");
488
+ if (truncated && text.endsWith("\uFFFD")) text = text.slice(0, -1);
489
+ return { label, kind: "markdown", path: file, text, ...(truncated ? { truncated: true, bytes: bytes.length } : {}) };
490
+ };
491
+ const documents = [doc("Working state (STATE.md)", join(home, "STATE.md")), doc("Log (log.md)", join(home, "log.md"))].filter(Boolean);
492
+ const notesDir = join(home, "notes");
493
+ const notes = existsSync(notesDir) ? readdirSync(notesDir).filter((f) => f.endsWith(".md")).sort() : [];
494
+ for (const f of notes) { const d = doc(`Pending note: ${f}`, join(notesDir, f)); if (d) documents.push(d); }
495
+ const summary = documents.length ? `${documents.length} document${documents.length === 1 ? "" : "s"}: ${existsSync(join(home, "STATE.md")) ? "state" : "no state"}, ${existsSync(join(home, "log.md")) ? "log" : "no log"}, ${notes.length} pending note${notes.length === 1 ? "" : "s"}` : "no working memory in this home yet (STATE.md, log.md and notes/ are written by the instance)";
496
+ process.stdout.write(JSON.stringify({ schemaVersion: 1, ok: true, result: { summary, documents } }) + "\n"); process.exit(0);
497
+ } catch (e) {
498
+ process.stdout.write(JSON.stringify({ schemaVersion: 1, ok: false, error: { code: "E_INSPECT_FAILED", message: String(e.message || e).slice(0, 300) } }) + "\n"); process.exit(1);
499
+ }
476
500
  } else if (event === "retire") {
477
501
  // Retirement is intentionally a no-op for knowledge (for now): promotion happens
478
502
  // continuously via agent-initiated harvest. Uncommitted notes die with the home —
@@ -480,5 +504,5 @@ _(the single next action — keep this current; a fresh session on any model res
480
504
  // before finishing.
481
505
  out({ meta: {} });
482
506
  } else {
483
- warn(`unknown event "${event}" (expected soul-scaffold|spawn|retire)`);
507
+ warn(`unknown event "${event}" (expected soul-scaffold|spawn|retire|harvest|inspect)`);
484
508
  }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "capability": "oats.okf",
3
3
  "command": "okf",
4
- "version": "1.5.2",
4
+ "version": "1.6.0",
5
5
  "compatibility": {
6
6
  "oats": ">=0.22.3"
7
7
  },
8
8
  "layer": "knowledge",
9
- "description": "Knowledge layer via OKF: soul bundles, instance memory (STATE.md/log.md/notes/), continuous post-commit harvest into the soul (commit, PR, or direct-edit for local souls), craft + memory skills, validator.",
9
+ "description": "Knowledge layer via OKF: soul bundles, instance memory (STATE.md/log.md/notes/), continuous post-commit harvest into the soul (commit, PR, or direct-edit for local souls), craft + memory skills, validator; declares the operations a GUI or schedule may run (inspect, harvest).",
10
10
  "requires": [],
11
11
  "settings": {
12
12
  "harvest-runtime": {
@@ -29,11 +29,26 @@
29
29
  "skills"
30
30
  ],
31
31
  "commands": {
32
- "harvest": "bin/oats-okf.mjs harvest"
32
+ "harvest": "bin/oats-okf.mjs harvest",
33
+ "inspect": "bin/oats-okf.mjs inspect"
33
34
  },
34
35
  "inject": "injects/okf.md",
35
36
  "hooks": {
36
37
  "soul-scaffold": "bin/oats-okf.mjs soul-scaffold",
37
38
  "spawn": "bin/oats-okf.mjs spawn"
39
+ },
40
+ "operations": {
41
+ "inspect": {
42
+ "kind": "view",
43
+ "command": "inspect",
44
+ "context": "home",
45
+ "description": "Show this instance's working knowledge: STATE.md, log.md and pending notes"
46
+ },
47
+ "harvest": {
48
+ "kind": "action",
49
+ "command": "harvest",
50
+ "context": "home",
51
+ "description": "Promote this instance's pending notes (or captured record) into its soul by spawning a memory-harvest worker"
52
+ }
38
53
  }
39
54
  }
@@ -503,3 +503,10 @@ The source packages live under `capabilities/`. Acquired packages live under
503
503
  `<level>/.agents/capabilities/installed/` (gitignored, restorable); packages
504
504
  authored at a scope live under `<level>/.agents/capabilities/owned/`
505
505
  (committed where the scope is a git repo). Within one scope `owned/` overrides `installed/` on ID collision.
506
+
507
+ ## Operations a capability declares
508
+
509
+ A manifest may declare `operations` (named actions or views delegating to
510
+ its own commands) that a GUI or a schedule invokes through `oats operation
511
+ run <layer>:<name>`; `oats inspect --json` reports them with availability.
512
+ See [docs/design/operations-contract.md](design/operations-contract.md).
@@ -150,6 +150,38 @@
150
150
  "minLength": 1
151
151
  }
152
152
  },
153
+ "operations": {
154
+ "description": "Named operations a GUI or scheduler may invoke through `oats operation run`, each delegating to one of this manifest's commands. kind \"view\" answers { documents: [{label, kind, path, text}] }; \"action\" (default) runs something. context \"home\" (default) runs in an instance home, \"scope\" in the config scope.",
155
+ "type": "object",
156
+ "propertyNames": {
157
+ "pattern": "^[a-z][a-z0-9-]*$"
158
+ },
159
+ "additionalProperties": {
160
+ "type": "object",
161
+ "required": ["command"],
162
+ "additionalProperties": false,
163
+ "properties": {
164
+ "command": { "type": "string", "minLength": 1 },
165
+ "kind": { "enum": ["action", "view"] },
166
+ "context": { "enum": ["home", "scope"] },
167
+ "description": { "type": "string" },
168
+ "args": {
169
+ "type": "array",
170
+ "items": {
171
+ "type": "object",
172
+ "required": ["name"],
173
+ "additionalProperties": false,
174
+ "properties": {
175
+ "name": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$" },
176
+ "flag": { "type": "string", "pattern": "^--[a-z][a-z0-9-]*$" },
177
+ "required": { "type": "boolean" },
178
+ "description": { "type": "string" }
179
+ }
180
+ }
181
+ }
182
+ }
183
+ }
184
+ },
153
185
  "hooks": {
154
186
  "type": "object",
155
187
  "properties": {
@@ -0,0 +1,131 @@
1
+ # Architecture reassessment: usable agents with replaceable services
2
+
3
+ Assessment of main `76c0ea4`, September 7, 2026. Requested by Juan after
4
+ operating the Desktop; incorporates Pepe's terminal, shortcut, split and soul
5
+ management feedback. This records the direction and implementation gaps, not a
6
+ claim that every item below has shipped.
7
+
8
+ The requirements authority for this assessment is Juan's September 3
9
+ “Architecture simplification and generlization” in his OATS project KB:
10
+ souls carry instructions and capabilities; a harvester converts ephemeral
11
+ state into knowledge accessible through the selected knowledge capability;
12
+ packages distribute souls and capabilities; OATS constructs and operates
13
+ instances across runtimes and platforms. The private Bookshelf README points
14
+ to September 1's adoption/sovereignty strategy. Its relevant constraint is that
15
+ changing a runtime or service provider must not erase the team's relationships
16
+ or working knowledge. The older August proposals about genomes, clothes and
17
+ turn-record experiments are background, not reasons to expand this release.
18
+
19
+ ## Decision
20
+
21
+ Keep the existing package and capability-layer mechanism. Correct the places
22
+ where the CLI and GUI bypass it. The architecture is broadly right; the
23
+ operator experience and some service boundaries are incomplete. More
24
+ abstractions will not fix a terminal that cannot accept a screenshot.
25
+
26
+ | Component | Owns | Must not assume |
27
+ |---|---|---|
28
+ | OATS kernel | Soul/instance construction, configuration, lifecycle, host placement, scheduling, capability resolution | A particular knowledge provider, messaging service, or GUI |
29
+ | Session backend | Durable terminal, attach/detach, resize, literal input, observation | OATS soul/package semantics or task success |
30
+ | Knowledge capability | Knowledge access and representation; its harvester and promotion policy | Every installation uses OKF or stores memory in the same files |
31
+ | Messaging capability / aweb | Durable messages, identities, event subscriptions and delivery policy | A particular model harness or an open Desktop window |
32
+ | Task capability | Durable work and task semantics | A particular terminal backend |
33
+ | Desktop | Inspect effective configuration; explicit operator actions; terminal input, files, layout | Provider names, SSH commands, or a second lifecycle implementation |
34
+
35
+ Scheduling belongs to OATS, and a scheduled harvest is one use of scheduling.
36
+ Harvesting behavior belongs to the knowledge capability. Starting an agent,
37
+ writing a prompt, and producing reviewed knowledge are different outcomes.
38
+ The UI must retain those distinctions.
39
+
40
+ ## What already fits, and what does not
41
+
42
+ `lib/core.mjs` already selects exclusive knowledge/messaging/tasks layers by
43
+ manifest, resolves scoped capability settings, dispatches lifecycle hooks, and
44
+ materializes runtime instructions. Jira and Linear demonstrate that a layer
45
+ can have alternative implementations. OKF's harvester is already an exported
46
+ capability agent. There is no reason to replace this machinery.
47
+
48
+ The remaining coupling is concrete:
49
+
50
+ - The retire receipt reads `hookResults.meta["oats.okf"].harvested`, although
51
+ current OKF does not supply a retire hook. Remove the dead provider-specific
52
+ inference; do not invent successful harvesting at retirement.
53
+ - Remote capability routing recognizes `okf harvest` specifically in
54
+ `bin/oats.mjs` and `lib/servers.mjs`.
55
+ - Desktop harvest actions and scheduled-harvest definitions construct
56
+ `oats okf harvest`; the editor recognizes that exact argv.
57
+ - The “brain” view presents `STATE.md`, `log.md` and `notes/` as universal
58
+ knowledge structure. These are conventions of the current setup.
59
+
60
+ The next service contract should expose the **effective knowledge provider and
61
+ its supported operations for a specific soul/home**. Discovering a capability
62
+ command namespace alone is insufficient: it does not promise a `harvest` verb
63
+ or a shared file layout. A provider may offer harvest, different operations,
64
+ or read-only access. Desktop must show only declared operations and route
65
+ execution through the selected CLI capability. The same resolution must apply
66
+ locally, remotely, and when a scheduled operation runs.
67
+
68
+ Keep that change small: explicit operation metadata, scoped discovery, and one
69
+ invocation route using the existing capability engine. Do not add a plugin
70
+ framework, generic workflow language, or a second knowledge store. Demonstrate
71
+ replaceability with a tiny alternative-provider fixture that uses a different
72
+ command and storage layout; a full second product is unnecessary.
73
+
74
+ ## tmux and Herdr
75
+
76
+ The current kernel defaults to a shared tmux session (`pi-agents`) with a
77
+ window per instance. An agent does not require another tmux server. The GUI
78
+ creates a temporary session linking only the selected window. That isolates
79
+ viewers: switching a terminal elsewhere cannot redirect a GUI tab to another
80
+ agent, and an agent exiting cannot silently expose a sibling under its label.
81
+ The `oatsdesk-*` name in Juan's screenshot is this viewer. Its status bar can
82
+ be hidden with a viewer-local setting. Do not alter global tmux settings or
83
+ merge/move live agent sessions to solve a display defect.
84
+
85
+ Herdr 0.8.2 is a separate terminal runtime, not a tmux-compatible superset.
86
+ Its documented direct terminal attachment, socket API, events and SSH support
87
+ are useful. Its semantic agent state comes from detection and/or integrations;
88
+ it is richer evidence, not proof that a particular message was consumed.
89
+ The [socket API](https://herdr.dev/docs/socket-api/) explicitly distinguishes
90
+ agent-state waits from arbitrary command completion. The
91
+ [remote documentation](https://herdr.dev/docs/persistence-remote/) also
92
+ separates a local thin client from running a client entirely on the server;
93
+ only the former can directly bridge the local desktop clipboard.
94
+
95
+ Keep one OATS session contract and both existing adapters for now. Do not add
96
+ another supervisor above them. Qualify Herdr's actual literal multi-line
97
+ input, exact occupant checks, detach, resize, process exit and remote behavior
98
+ before selecting it as the default for new instances. Inspect `pane run`
99
+ implementation before replacing it merely because its name sounds like shell
100
+ execution. Removing tmux is a later deployment choice, not a prerequisite for
101
+ consistent UI or remote agents. Existing tmux agents stay where they are.
102
+
103
+ ## Desktop correction sequence
104
+
105
+ 1. **Terminal essentials.** Hide viewer chrome, accept dropped files and pasted
106
+ images without pressing Enter, upload remote files to the execution host,
107
+ preserve the destination tab across async work, and show transfer failures.
108
+ Keep a single GUI and bounded viewers. This is the immediate implementation.
109
+ 2. **Keyboard and splits.** Restore Ctrl+Tab navigation inside Mac terminals;
110
+ let an already-open terminal fill an empty split without a second attach;
111
+ expose draggable and keyboard-operable separators. Follow up specific
112
+ keyboard reports with real input tests, especially terminal editing keys
113
+ and non-US layouts. App shortcuts must not silently steal terminal edits.
114
+ 3. **Souls & capabilities.** Replace the launch-centric roster with a management
115
+ surface showing souls, installed capabilities, effective layer providers,
116
+ source/version, scoped activation and runtime defaults. Inspect and launch
117
+ are distinct actions. Edits use existing CLI operations with the exact scope
118
+ visible; installing a capability must not silently activate it. This is not
119
+ a marketplace or Team Builder project.
120
+ 4. **Provider-neutral operations.** Introduce the scoped operation contract
121
+ above, then use it for manual harvest, schedules and knowledge inspection.
122
+ No second hardcoded default is accepted as a generalization.
123
+ 5. **Operating rollout.** Enable schedules per team with the owner's learning
124
+ policy. Capture-lock recovery is a separate reliability issue affecting
125
+ unattended harvesting; it does not block arbitrary scheduled wakes.
126
+
127
+ Acceptance must include real Electron file objects, actual terminal bytes,
128
+ remote transfer hashes, split focus/resize without extra PTYs, and a provider
129
+ replacement fixture. Unit tests of mocked argv alone do not establish these
130
+ boundaries. Reuse the existing agents and GUI sparingly; no model is needed to
131
+ exercise attachment transport or terminal layout.
@@ -0,0 +1,50 @@
1
+ # Souls and capabilities in Desktop
2
+
3
+ Selecting a soul opens its details. Launch and Schedule are explicit actions;
4
+ Quick Open and Enter inspect instead of launching. The existing local Files
5
+ browser remains available. It is separate from provider knowledge inspection.
6
+
7
+ The inspector reads the kernel's `oats inspect --json` answer on selection,
8
+ Refresh, or after an explicit mutation. The roster's eight-second poll never
9
+ rescans capabilities or replaces an editor. Workspace changes invalidate old
10
+ responses. Same-named souls are addressed by name plus agents root; instances
11
+ are addressed by their exact home.
12
+
13
+ The Capabilities button inspects workspace defaults, with a member-scope
14
+ selector where a workspace contains several roots. Installed version, source
15
+ and health are separate from effective activation, provenance and settings.
16
+ Enable, explicit disable and return to inheritance call `oats use`; layer-wide
17
+ disable is distinct from excluding a single capability, and is available only
18
+ when inspecting a workspace or member scope, never an individual soul. These changes apply to
19
+ future instances. Existing homes retain their captured bindings and settings.
20
+
21
+ Authored souls expose only the fields the kernel reports as editable. Desktop
22
+ edits runtime, model, backend, YOLO, description and instructions through
23
+ `oats soul set`. Packaged souls remain read-only and explain where their source
24
+ must be changed. Instructions use a private temporary file; the CLI owns remote
25
+ transfer and mutation. Desktop does not modify YAML or resolve capabilities.
26
+
27
+ An instance's action menu opens Knowledge & capabilities. The kernel supplies
28
+ its snapshot, differences from current configuration, and declared provider
29
+ operations. View operations return labeled documents; Desktop renders their
30
+ text and treats remote paths as provenance, never as local files to open. Actions
31
+ without required arguments can run here. Operations requiring arguments explain
32
+ that they need the CLI. No provider is assumed to support harvesting.
33
+
34
+ Schedules store an operation address and exact home with the kernel's generic
35
+ `operation` job kind. The form discovers declared, available actions on demand.
36
+ The server verifies that declaration again at save time, and the kernel resolves
37
+ and validates the provider at execution time. Existing command schedules remain
38
+ visible and runnable, but the GUI does not reverse-parse their argv to edit them.
39
+
40
+ Every capability request requires an exact advertised workspace. Remote requests
41
+ require its saved server registration and the CLI's operations API feature; all
42
+ routing stays in OATS. The consumer never performs SSH or silently substitutes a
43
+ local workspace. The proxy allows the CLI's bounded operation to return its
44
+ receipt before timing out.
45
+
46
+ Validation: scope/identity and remote-route refusal; private instructions and
47
+ failure cleanup; declared schedule actions; stale inspection/save responses;
48
+ provider text rendering; explicit launch and existing runtime flows. Native
49
+ Electron rendering is checked with a temporary fixture frame in the existing
50
+ GUI, without starting a model, agent, or another application instance.
@@ -0,0 +1,123 @@
1
+ # Provider operations and inspection contract
2
+
3
+ Implemented 2026-09-07 on the existing capability engine. The kernel
4
+ resolves providers; a GUI reads one answer and calls the commands below.
5
+ Nothing here names a provider: what a knowledge, messaging or tasks
6
+ capability offers is what its manifest declares.
7
+
8
+ ## Manifest: operations
9
+
10
+ ```json
11
+ "operations": {
12
+ "harvest": { "kind": "action", "command": "harvest", "context": "home", "description": "Promote this instance's notes into its soul" },
13
+ "inspect": { "kind": "view", "command": "inspect", "context": "home", "description": "Show this instance's working knowledge" }
14
+ }
15
+ ```
16
+
17
+ `command` names one of the manifest's `commands`. `kind` is `action`
18
+ (default) or `view`. `context` is `home` (default; runs in an instance
19
+ home) or `scope` (runs in the config scope). Optional `args` declare
20
+ `{name, flag, required, description}`; the runner passes `--arg name=value`
21
+ pairs as those flags and refuses unknown or missing required ones. A view
22
+ must answer `{ documents: [{ label, kind: "markdown"|"text", path?, text? }],
23
+ summary? }`; the kernel validates that shape and relays it. Paths are
24
+ provenance for the reader; the kernel reads nothing for a view. Validation
25
+ happens when the manifest loads (`docs/capability-manifest.schema.json`).
26
+
27
+ ## oats inspect
28
+
29
+ `oats inspect [--dir <scope>] [--soul <name> [--agents-root <abs>]] [--home
30
+ <abs>] [--server <id>] --json` answers, in one envelope: `scope` (context,
31
+ workspace, team, chain, agentsRoots); `souls` (persistent, local and
32
+ packaged, each with runtime defaults, `editable {fields, instructions,
33
+ reason}`, instances, and for the selected soul its `instructions {file,
34
+ text, sha256, bytes, truncated, error}` capped at 256 KiB of bytes on a
35
+ character boundary); `layers` (effective provider per layer); `capabilities`
36
+ (installed state and `health` from the package engine, `missingRequires`,
37
+ and separately `activation {enabled, source, target, level, provenance,
38
+ settings, declaredAt}` plus `operations` with `available` and a `reason`);
39
+ `knowledge` (the effective knowledge provider's operations); `snapshot` and
40
+ `currentConfig` with `--home`; `problems`.
41
+
42
+ A `--home` answer is authoritative for that home: activation, settings,
43
+ layers and operation availability come from the home's captured bindings
44
+ with the currently acquired manifests and current trust, marked `source:
45
+ "snapshot"`; the live config is `currentConfig`, and `snapshot.drift`
46
+ lists activation, settings and integrity differences. The home selects its
47
+ own soul under its own agents root (its recorded work repository may be
48
+ another repository); `--dir`, if given, must be the recorded repository or
49
+ the workspace of that root, and `--agents-root` must be that root
50
+ (`E_HOME_MISMATCH`). Without a home, `--dir` is the config context and
51
+ same-named souls under two member roots need `--agents-root`
52
+ (`E_SOUL_AMBIGUOUS`). The ambient `PI_AGENTS_ROOT` never redirects these
53
+ commands. Integrity scanning happens only in this command.
54
+
55
+ ## oats operation run
56
+
57
+ `oats operation run <layer>:<name> (--home <abs> | --soul <name> [--dir
58
+ <scope>] [--agents-root <abs>]) [--arg k=v ...] --json` resolves the
59
+ provider that fills `<layer>` for the home (captured bindings and settings)
60
+ or for the soul in the scope (config), requires the operation to be declared
61
+ (`E_OPERATION_UNKNOWN`), a provider to exist (`E_OPERATION_UNAVAILABLE`,
62
+ also for a home-context operation without `--home`), the executable surface
63
+ to be trusted (`E_CAPABILITY_BLOCKED`) and its `requires` to be on PATH
64
+ (`E_CAPABILITY_REQUIRES`), then runs the provider's own command exactly as
65
+ `oats <ns> <cmd>` would, with cwd and identity set to the selected target
66
+ (`OATS_HOME`, `OATS_INSTANCE`, `OATS_AGENT`, `OATS_SOUL`, `OATS_ROOT`,
67
+ `OATS_CONTEXT`, `OATS_WORKSPACE`, `OATS_OPERATION`, `OATS_SETTINGS`,
68
+ `OATS_CLI_BIN`, team variables) and every ambient identity of the invoking
69
+ process removed. The answer is `{ operation, capability, version, argv,
70
+ cwd, target: {home, instance}|null, result, instance?, home? }`; top-level
71
+ `instance`/`home` appear only when the provider's answer names something it
72
+ launched, never the source home.
73
+
74
+ The receipt must be exactly one JSON-v1 envelope on stdout from a process
75
+ that exits 0. Otherwise the outcome is unconfirmed: `E_OPERATION_TIMEOUT`
76
+ (240 s, below every wrapper) or `E_OPERATION_RESULT` (no valid envelope,
77
+ contaminated output, or a success envelope contradicted by the exit
78
+ status), with `error.details {unconfirmed: true, exit, envelope?, stderr?}`
79
+ carrying what was observed. A provider's own `ok: false` is relayed with
80
+ its code.
81
+
82
+ ## Schedules
83
+
84
+ Kind `operation` `{operation: "<layer>:<name>", home}` runs `oats operation
85
+ run <op> --home <home>` as a command job: same admission, tracking and
86
+ reconciliation. An unconfirmed outcome keeps the slot as unknown and any
87
+ name the provider answered is kept for `oats schedule reconcile`.
88
+
89
+ ## Mutations
90
+
91
+ `oats use ... --json` answers `{ capability, action: enable|disable|
92
+ layer-none|inherit, target, layer, level, file, settings, before, after
93
+ {..., effective}, remaining?, note?, missingRequires }`. `--inherit`
94
+ removes only the addressed target at this level; other bindings stay and
95
+ are listed. `use none --layer l` is a level statement and takes no soul or
96
+ type. A layer bound to another capability at a level is never overwritten
97
+ (`E_LAYER_BOUND` with the exact remedy).
98
+
99
+ `oats soul set <name> [--dir] [--agents-root] [--runtime] [--model |
100
+ --no-model] [--yolo | --no-yolo] [--backend] [--description |
101
+ --no-description] [--instructions-file <path>] --json` edits only the given
102
+ `soul.yaml` lines and replaces `AGENTS.md`; packaged souls are refused
103
+ (`E_SOUL_READONLY`). The receipt carries before/after and sha256s.
104
+
105
+ ## Remote
106
+
107
+ `inspect`, `operation`, `use` and `soul` route with `--server <id>` through
108
+ the saved route. The gate is the destination's `features` list containing
109
+ `operations` and its `operationsApi: 1` (`E_REMOTE_INCOMPATIBLE` before
110
+ anything is sent): `features` describes what a kernel can do locally, which
111
+ is what runs on the host. The probe's `remote` list describes what a CLI
112
+ can ROUTE to a server and is what a GUI checks on the local CLI before
113
+ offering remote actions; it is not a gate on the destination. An explicit `--dir` is the exact member context and
114
+ travels as is; `--home` is its own context; otherwise the registered
115
+ workspace is the scope. Soul instructions travel as bytes on the ssh stdin
116
+ (`--instructions-stdin` on the host), never as a local path.
117
+
118
+ ## Replaceability
119
+
120
+ `test/inspect.test.mjs`, `test/operation.test.mjs` and
121
+ `test/operations-routing.test.mjs` use an owned alternative knowledge
122
+ provider (namespace `notes`, one `MEMORY.md`, operations `harvest` and
123
+ `inspect`) and never mention the official provider.
package/docs/desktop.md CHANGED
@@ -211,3 +211,19 @@ certificate auto-discovery disabled) and
211
211
  marked build-verify mode (inventory + strict codesign verification +
212
212
  node-pty ABI, no GUI launch); a local
213
213
  interactive run may also exercise the launch phase.
214
+
215
+ ### Attach files and screenshots
216
+
217
+ Drop a file onto an agent terminal to insert its path into that agent's draft.
218
+ Pasting an image from the clipboard uses the same attachment path. Neither
219
+ operation presses Enter. Text paste continues to use the terminal's normal
220
+ paste behavior. A drop targets the pane under the pointer, including a visible
221
+ pane in a split.
222
+
223
+ Local files are referenced in place. Clipboard images are saved privately in
224
+ Desktop's application-data `attachments` directory and retained so an agent can
225
+ read them later. For remote terminals, Desktop calls the installed CLI's
226
+ `session upload` operation; it inserts the returned path only after the file
227
+ has reached the execution host. Both CLI installations must advertise
228
+ `session-upload`. A failed transfer leaves the draft unchanged and shows an
229
+ error in the terminal. Each drop/paste accepts up to 16 files totaling 25 MB.
@@ -181,6 +181,27 @@ pane in that exact window. Herdr additionally verifies the original terminal ID.
181
181
  The broker owns busy/approval policy and must not interpret `submitted` as
182
182
  processing acknowledgement.
183
183
 
184
+ ### Attachments
185
+
186
+ A viewer that drops a file or pastes an image gives the agent a path, never
187
+ terminal input. `oats session upload --file <local> --home <abs>` stores a
188
+ copy as a private file under `<home>/.oats-attachments/` (directory 0700,
189
+ file 0600, `name-2` on collision) and answers `{path, bytes, sha256}`; the
190
+ caller pastes `path` into the still-live session itself. With `--server <id>`
191
+ and `--instance <name>` (or `--home`), the same saved route as attach is
192
+ resolved, the remote must list `session-upload` in both its `remote` and
193
+ `features` probe arrays, and the bytes travel on ssh stdin into `oats session
194
+ receive --home <abs> --name <file>` on the execution host. Each side holds
195
+ the whole file in memory up to the 64 MiB kernel bound (this is a bounded
196
+ transfer, not end-to-end streaming); the receiver reads stdin event-driven,
197
+ refuses above the bound before writing, and allocates the destination
198
+ exclusively (`name-2`, `name-3` when taken), so simultaneous uploads of one
199
+ name never overwrite each other and a planted symlink is never followed. The
200
+ attachments directory must be a real directory inside the home. The local
201
+ side refuses the result unless the remote's size and sha256 equal the local
202
+ file's. A remote file is never a local path over SSH. Attachments live and
203
+ die with the home.
204
+
184
205
  Capability spawn hooks register a pending home before runtime allocation;
185
206
  inspection becomes available once its receipt is persisted. Retire hooks
186
207
  unregister after quiescence. The broker must tolerate this lifecycle order and
@@ -0,0 +1,44 @@
1
+ # OATS v0.22.13
2
+
3
+ Terminal essentials for the Desktop and one kernel operation behind them:
4
+ attachments reach the agent as a path, never as typed input.
5
+
6
+ ## Attachments (kernel)
7
+
8
+ `oats session upload --file <local> --home <abs>` copies a file into the
9
+ instance home's private `.oats-attachments/` directory (0700, file 0600,
10
+ `name-2` when the name is taken) and answers `{path, bytes, sha256}`. With
11
+ `--server <id> --instance <name>` (or `--home`), the same saved route as
12
+ `session attach` is resolved, the remote must advertise the new
13
+ `session-upload` feature, and the bytes travel on ssh stdin into
14
+ `oats session receive --home <abs> --name <file>` on the execution host,
15
+ which reads stdin event-driven, enforces the 64 MiB kernel bound before
16
+ writing anything, allocates the destination exclusively so simultaneous
17
+ uploads never overwrite each other, refuses a symlinked or redirected
18
+ attachments directory, and reports the path only after the bytes are
19
+ synced. The local side refuses the answer unless size and sha256 equal the
20
+ local file's. Each side buffers the whole file up to the bound; a remote
21
+ file is never a local path over SSH. Upload never sends terminal input.
22
+ `oats version --json` lists `session-upload` in `remote` and `features`.
23
+ The CLI's temporary tmux viewer session hides its status line; the agents'
24
+ session and the operator's tmux settings are untouched.
25
+
26
+ ## Desktop
27
+
28
+ Drop files or paste clipboard images onto an agent terminal: the paths are
29
+ inserted into the draft with bracketed paste and no Enter, local files in
30
+ place, clipboard images saved privately under the app's data directory, and
31
+ remote terminals uploaded through the installed CLI first (both CLIs must
32
+ advertise `session-upload`; a failed transfer leaves the draft unchanged and
33
+ never inserts a local path). Up to 16 files and 25 MB per drop. The viewer's
34
+ tmux status bar is hidden. Ctrl+Tab stays tab navigation inside terminals
35
+ on macOS while other Ctrl chords stay with the program. An already-open
36
+ terminal fills an empty split without a second attach; separators resize by
37
+ pointer or keyboard. Guide: docs/desktop.md, "Attach files and screenshots".
38
+
39
+ ## Design
40
+
41
+ docs/design/2026-09-07-architecture-reassessment.md records the direction:
42
+ keep the package and capability-layer machinery, fix the places where the
43
+ CLI and GUI bypass it, one session contract with both tmux and Herdr
44
+ adapters until Herdr is qualified, and the Desktop correction sequence.
@@ -0,0 +1,48 @@
1
+ # OATS v0.22.14
2
+
3
+ The same reviewed content as the unpublished v0.22.13 tag, whose hosted
4
+ run failed in one Desktop test pin before anything was published; the
5
+ test now checks the behaviour instead of the source text.
6
+
7
+ Terminal essentials for the Desktop and one kernel operation behind them:
8
+ attachments reach the agent as a path, never as typed input.
9
+
10
+ ## Attachments (kernel)
11
+
12
+ `oats session upload --file <local> --home <abs>` copies a file into the
13
+ instance home's private `.oats-attachments/` directory (0700, file 0600,
14
+ `name-2` when the name is taken) and answers `{path, bytes, sha256}`. With
15
+ `--server <id> --instance <name>` (or `--home`), the same saved route as
16
+ `session attach` is resolved, the remote must advertise the new
17
+ `session-upload` feature, and the bytes travel on ssh stdin into
18
+ `oats session receive --home <abs> --name <file>` on the execution host,
19
+ which reads stdin event-driven, enforces the 64 MiB kernel bound before
20
+ writing anything, allocates the destination exclusively so simultaneous
21
+ uploads never overwrite each other, refuses a symlinked or redirected
22
+ attachments directory, and reports the path only after the bytes are
23
+ synced. The local side refuses the answer unless size and sha256 equal the
24
+ local file's. Each side buffers the whole file up to the bound; a remote
25
+ file is never a local path over SSH. Upload never sends terminal input.
26
+ `oats version --json` lists `session-upload` in `remote` and `features`.
27
+ The CLI's temporary tmux viewer session hides its status line; the agents'
28
+ session and the operator's tmux settings are untouched.
29
+
30
+ ## Desktop
31
+
32
+ Drop files or paste clipboard images onto an agent terminal: the paths are
33
+ inserted into the draft with bracketed paste and no Enter, local files in
34
+ place, clipboard images saved privately under the app's data directory, and
35
+ remote terminals uploaded through the installed CLI first (both CLIs must
36
+ advertise `session-upload`; a failed transfer leaves the draft unchanged and
37
+ never inserts a local path). Up to 16 files and 25 MB per drop. The viewer's
38
+ tmux status bar is hidden. Ctrl+Tab stays tab navigation inside terminals
39
+ on macOS while other Ctrl chords stay with the program. An already-open
40
+ terminal fills an empty split without a second attach; separators resize by
41
+ pointer or keyboard. Guide: docs/desktop.md, "Attach files and screenshots".
42
+
43
+ ## Design
44
+
45
+ docs/design/2026-09-07-architecture-reassessment.md records the direction:
46
+ keep the package and capability-layer machinery, fix the places where the
47
+ CLI and GUI bypass it, one session contract with both tmux and Herdr
48
+ adapters until Herdr is qualified, and the Desktop correction sequence.
@@ -0,0 +1,48 @@
1
+ # OATS v0.22.15
2
+
3
+ Souls and capabilities become something you inspect and manage, through
4
+ one kernel contract, and knowledge providers declare what they can do.
5
+
6
+ ## Provider operations and inspection (kernel)
7
+
8
+ `oats inspect --json` answers everything a GUI needs in one envelope for a
9
+ scope, a selected soul or a running home: souls with runtime defaults,
10
+ editability and instructions; installed capabilities with health from the
11
+ package engine, separately from their effective activation, provenance and
12
+ settings; effective layer bindings; and the operations each provider
13
+ declares, with availability and the reason when unavailable. For a home the
14
+ answer is its captured bindings (with current manifests and trust), the live
15
+ config beside it, and the drift between them. Same-named souls in member
16
+ repositories are addressed by name plus agents root; a home selects its own
17
+ soul under its own root.
18
+
19
+ `oats operation run <layer>:<name>` resolves the provider that fills a layer
20
+ for a home or a soul, checks declaration, trust and host requirements, runs
21
+ the provider's own command in the right place with the right identity, and
22
+ relays its receipt; a view answers labeled documents. Unconfirmed outcomes
23
+ carry what was observed and a scheduled operation keeps its slot until
24
+ reconciled. Manifests declare `operations`. Schedules gain kind
25
+ `operation`. `oats use --json` answers receipts and `--inherit` returns a
26
+ level to inheritance; `oats soul set` edits an editable soul's defaults and
27
+ instructions in place. All four route to a registered server through the
28
+ saved route; the probe advertises `operations` and `operationsApi: 1`. The
29
+ retire receipt no longer implies a harvest. See
30
+ docs/design/operations-contract.md.
31
+
32
+ ## oats.okf 1.6.0
33
+
34
+ The official knowledge provider declares `inspect` (a view of STATE.md,
35
+ log.md and pending notes) and `harvest` (the existing action); the catalog
36
+ pins v1.6.0. Existing scopes keep their locked 1.5.2 until their owners
37
+ update them; the GUI then shows no operations for those providers, which is
38
+ the truthful state.
39
+
40
+ ## Desktop
41
+
42
+ Souls & capabilities replaces the launch-centric roster: select a soul to
43
+ inspect it, Launch and Schedule are explicit, defaults and instructions are
44
+ editable where the kernel says so, installed capabilities are shown apart
45
+ from activation with enable, disable and inherit at an exact scope, an
46
+ instance's menu opens Knowledge & capabilities, provider views render as
47
+ text, and schedules run declared provider operations. See
48
+ docs/design/2026-09-07-desktop-souls-capabilities.md.