@awebai/oats 0.22.0 → 0.22.1
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/README.md +30 -47
- package/bin/oats.mjs +11 -6
- package/capabilities/oats-authoring/LICENSE +21 -0
- package/capabilities/oats-authoring/oats-package.json +11 -0
- package/capabilities/oats-authoring/oats.json +4 -4
- package/capabilities/oats-authoring/skills/integration-authoring/SKILL.md +63 -0
- package/capabilities/oats-authoring/skills/skill-craft/SKILL.md +109 -0
- package/capabilities/oats-authoring/skills/soul-craft/SKILL.md +109 -0
- package/capabilities/oats-aweb/oats.json +6 -6
- package/capabilities/oats-aweb/skills/LICENSE +21 -0
- package/capabilities/oats-aweb/skills/VENDORED.md +26 -0
- package/capabilities/oats-aweb/skills/aweb-identity/SKILL.md +201 -0
- package/capabilities/oats-aweb/skills/aweb-messaging/SKILL.md +161 -0
- package/capabilities/oats-aweb/skills/aweb-messaging/references/messaging-scenarios.md +61 -0
- package/capabilities/oats-aweb/skills/aweb-team-membership/SKILL.md +328 -0
- package/capabilities/oats-aweb/skills/aweb-team-membership/references/team-membership-reference.md +74 -0
- package/capabilities/oats-jira/oats.json +1 -1
- package/capabilities/oats-linear/oats.json +1 -1
- package/capabilities/oats-okf/agents/memory-harvest/soul.yaml +6 -0
- package/capabilities/oats-okf/bin/oats-okf.mjs +82 -51
- package/capabilities/oats-okf/oats.json +4 -1
- package/capabilities/oats-review/oats.json +1 -1
- package/docs/2026-09-03-architecture-proposal.md +642 -0
- package/docs/first-team-demo.md +87 -0
- package/docs/first-team.md +179 -0
- package/docs/integrations.md +83 -65
- package/docs/layers.md +356 -80
- package/docs/migration-from-oas.md +80 -116
- package/docs/release-notes/v0.22.1.md +106 -0
- package/lib/core.mjs +255 -363
- package/package.json +1 -1
- package/packages/record/README.md +76 -16
- package/packages/record/docs/turn-record-sot.md +1 -1
- package/packages/record/lib/store.mjs +207 -43
- package/capabilities/oats-aweb/package.json +0 -20
- package/capabilities/oats-jira/package.json +0 -25
- package/capabilities/oats-linear/README.md +0 -234
- package/capabilities/oats-linear/package.json +0 -29
- package/capabilities/oats-linear/test/oats-linear.test.mjs +0 -168
- package/capabilities/oats-okf/package.json +0 -22
- /package/capabilities/oats-okf/agents/{memory-harvest.md → memory-harvest/AGENTS.md} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"capability": "oats.review",
|
|
3
3
|
"version": "1.2.0",
|
|
4
|
-
"compatibility": { "oats": ">=0.
|
|
4
|
+
"compatibility": { "oats": ">=0.19.0" },
|
|
5
5
|
"description": "Post-commit review discipline: a fresh reviewer agent (defined by this capability) reviews each new commit's diff, reports its verdict to its spawner over the deployment's messaging layer (or in its transcript when there is none), and retires — plus the shared developer delivery discipline.",
|
|
6
6
|
"requires": [],
|
|
7
7
|
"agents": ["agents/reviewer"],
|
|
@@ -0,0 +1,642 @@
|
|
|
1
|
+
# OATS architecture proposal: components, contracts, and what may be replaced
|
|
2
|
+
|
|
3
|
+
Status: proposal, for review. Not shipped behavior.
|
|
4
|
+
|
|
5
|
+
Date: 2026-09-03
|
|
6
|
+
|
|
7
|
+
Decision owner: Pepe
|
|
8
|
+
|
|
9
|
+
The component model in this document is Pepe's and Juan's, as
|
|
10
|
+
stated on 2026-09-03. The contract analysis, simplifications, and
|
|
11
|
+
consequences are the oats workspace's first-principles reading of
|
|
12
|
+
that model. Where this document and a shipped doc disagree about
|
|
13
|
+
*current* behavior, the shipped doc is right; where they disagree
|
|
14
|
+
about *direction*, this document is the proposal.
|
|
15
|
+
|
|
16
|
+
The turn record is one capture implementation in this model,
|
|
17
|
+
not its center. The clothes model survives only as an optional
|
|
18
|
+
realization artifact. `docs/layers.md` remains a correct
|
|
19
|
+
description of the shipped five layers; this document
|
|
20
|
+
generalizes it.
|
|
21
|
+
|
|
22
|
+
## Goal
|
|
23
|
+
|
|
24
|
+
An architecture that expands and adapts: new runtimes, new places
|
|
25
|
+
to run them, new knowledge formats, new task trackers, new
|
|
26
|
+
communication systems, new ways to store souls, new soul types,
|
|
27
|
+
each added without changing OATS.
|
|
28
|
+
|
|
29
|
+
The single design rule that produces that property:
|
|
30
|
+
|
|
31
|
+
> Every main component is replaceable by another that offers the
|
|
32
|
+
> same contract, with the exception of OATS itself. OATS knows
|
|
33
|
+
> only contracts.
|
|
34
|
+
|
|
35
|
+
Nothing in the model mentions a repository. A repository is one
|
|
36
|
+
place a soul can be stored and one thing an instance can work
|
|
37
|
+
on. Both are behind contracts. A soul could equally be
|
|
38
|
+
instantiated in a provider of autonomous agents that has no
|
|
39
|
+
filesystem at all.
|
|
40
|
+
|
|
41
|
+
A constraint that holds across every seam (Pepe, 2026-09-04): it
|
|
42
|
+
must remain possible to run everything filesystem-based and
|
|
43
|
+
fully local, meaning with no dependency on a hosted service that
|
|
44
|
+
the operator cannot replace. Real communication needs a server;
|
|
45
|
+
a self-hosted aweb server on localhost satisfies the constraint,
|
|
46
|
+
and that is how the reference deployment runs today. What OATS or
|
|
47
|
+
aweb must hold on *their* servers, and the traffic that must pass
|
|
48
|
+
through them, is to be minimized. Each contract below is read
|
|
49
|
+
with that constraint, and the organizational-sovereignty strategy
|
|
50
|
+
makes the same demand from the other side.
|
|
51
|
+
|
|
52
|
+
An acceptance criterion follows from it (Juan, 2026-09-05): a
|
|
53
|
+
default installation after the migration produces the same
|
|
54
|
+
composed instructions, launch commands, home layout, instance
|
|
55
|
+
metadata, and retirement results as v0.22.0. Everything the new
|
|
56
|
+
architecture adds is additive and off by default, and the golden
|
|
57
|
+
fixtures (step 1) are the proof: a refactor step lands only if
|
|
58
|
+
they are byte-unchanged, and a deliberate change is a re-approved
|
|
59
|
+
golden.
|
|
60
|
+
|
|
61
|
+
## The model
|
|
62
|
+
|
|
63
|
+
### Soul
|
|
64
|
+
|
|
65
|
+
A soul has:
|
|
66
|
+
|
|
67
|
+
- `AGENTS.md`: the operating definition, runtime-neutral by
|
|
68
|
+
construction;
|
|
69
|
+
- optional **finetuning**;
|
|
70
|
+
- optional **clothes**;
|
|
71
|
+
- its **capabilities**.
|
|
72
|
+
|
|
73
|
+
Finetuning and clothes are optimizations that may or may not pay off. They
|
|
74
|
+
are bracketed on purpose (see "Realization artifacts" below).
|
|
75
|
+
|
|
76
|
+
### Capability
|
|
77
|
+
|
|
78
|
+
A capability is a set of scripts, skills, and docs. Skills come
|
|
79
|
+
from capabilities. An OATS installation needs capabilities for
|
|
80
|
+
these contracts, possibly scoped by soul type:
|
|
81
|
+
|
|
82
|
+
- **Knowledge access**;
|
|
83
|
+
- **Task management**;
|
|
84
|
+
- **Communication**;
|
|
85
|
+
- optionally, **capture** of ephemeral state such as notes or conversation
|
|
86
|
+
history, which is also the input from which clothes may be derived.
|
|
87
|
+
|
|
88
|
+
The user selects which capability fills each contract, usually after
|
|
89
|
+
installing it from a package.
|
|
90
|
+
|
|
91
|
+
### Harvester
|
|
92
|
+
|
|
93
|
+
A harvester knows how to convert ephemeral state into organizational
|
|
94
|
+
knowledge, in the format the knowledge-access capability reads.
|
|
95
|
+
|
|
96
|
+
### Package
|
|
97
|
+
|
|
98
|
+
A package groups cohesive souls and capability sets.
|
|
99
|
+
|
|
100
|
+
### OATS
|
|
101
|
+
|
|
102
|
+
OATS knows how to:
|
|
103
|
+
|
|
104
|
+
- create instances for any given (soul, runtime);
|
|
105
|
+
- run the runtimes in supported platforms;
|
|
106
|
+
- install the task, knowledge, and communication capabilities;
|
|
107
|
+
- instantiate and run the harvester;
|
|
108
|
+
- install souls and capabilities from packages;
|
|
109
|
+
- manage all of the above with a clear GUI.
|
|
110
|
+
|
|
111
|
+
## The architecture is its seams
|
|
112
|
+
|
|
113
|
+
A component list says what exists. The architecture is the set of
|
|
114
|
+
contracts between them. The table below names each seam, what
|
|
115
|
+
must be able to vary across it, and the two implementations that
|
|
116
|
+
would prove the contract is real. Where only one implementation
|
|
117
|
+
can be named, the contract is still a description of that one;
|
|
118
|
+
those rows are the work.
|
|
119
|
+
|
|
120
|
+
| Seam | What varies behind it | Implementation today | Second implementation |
|
|
121
|
+
|------------------------|--------------------------------------------------------|-----------------------------------------|-----------------------------------|
|
|
122
|
+
| Soul format | how a specialist is defined | `soul.yaml` + `AGENTS.md` + skills | same format, different store |
|
|
123
|
+
| Soul type | which capabilities and knowledge scope a soul may have | config agent types | (formalize; see below) |
|
|
124
|
+
| Capability manifest | what a capability contributes and requires | `oats.json` | exists, stable |
|
|
125
|
+
| Knowledge contract | format read by instances and written by harvest | `oats.okf` | plain-markdown or wiki capability |
|
|
126
|
+
| Task contract | where shared work state lives | `oats.jira`, `oats.linear` | beads, GitHub Issues |
|
|
127
|
+
| Communication contract | how instances are reached and reach others | `oats.aweb` | Slack, A2A gateway |
|
|
128
|
+
| Capture contract | format of ephemeral state | OKF `notes/` + turn record | either alone |
|
|
129
|
+
| Runtime provider | how a realization bundle becomes a running agent | Pi or Claude Code in local tmux | a hosted agent provider |
|
|
130
|
+
| Soul store | where souls are kept and versioned | git repository under `agents/` | package; provider registry |
|
|
131
|
+
| Work target | what an instance operates on | worktree, checkout, attached, workspace | none (a mail-only agent) |
|
|
132
|
+
| Package | acquisition, version, integrity, trust | git-acquired, hash-locked | local path (exists) |
|
|
133
|
+
| Lifecycle events | when capabilities may act | scaffold, spawn, retire | + harvest |
|
|
134
|
+
|
|
135
|
+
The "Second implementation" column names an implementation that
|
|
136
|
+
would *prove* the contract, not a planned replacement. Today's
|
|
137
|
+
defaults stay the defaults: OKF for knowledge, aweb for
|
|
138
|
+
communication, the git repository for the soul store, the four
|
|
139
|
+
work modes for the work target. `none` is an additional work
|
|
140
|
+
target, not a substitute for any mode.
|
|
141
|
+
|
|
142
|
+
Two seams on this table have one real implementation: runtime
|
|
143
|
+
provider and soul store. They are where expandability is
|
|
144
|
+
currently a promise rather than a property.
|
|
145
|
+
|
|
146
|
+
## The contracts
|
|
147
|
+
|
|
148
|
+
### Soul format
|
|
149
|
+
|
|
150
|
+
A soul declares *which contracts it needs*, never which
|
|
151
|
+
implementation fills them. `AGENTS.md` speaks of "your task
|
|
152
|
+
layer" and "your knowledge"; the capability's injected block says
|
|
153
|
+
what that is in this installation. This is what lets one packaged
|
|
154
|
+
soul run in an installation bound to Jira and another bound to
|
|
155
|
+
Linear, and it is already how injection works.
|
|
156
|
+
|
|
157
|
+
A soul is runtime-neutral as an artifact. Anything
|
|
158
|
+
runtime-specific derived from it is a realization artifact, not
|
|
159
|
+
soul content.
|
|
160
|
+
|
|
161
|
+
### Soul type
|
|
162
|
+
|
|
163
|
+
A soul type is the policy unit. It decides which capabilities a
|
|
164
|
+
soul of that type receives, what knowledge it may read, and
|
|
165
|
+
whether it may write knowledge. Authority lives here, not in a
|
|
166
|
+
permission system.
|
|
167
|
+
|
|
168
|
+
Consequences:
|
|
169
|
+
|
|
170
|
+
- a reviewer is a soul type, not a component;
|
|
171
|
+
- a harvester is a soul type permitted to write knowledge;
|
|
172
|
+
- the GUI's natural organizing axis is type;
|
|
173
|
+
- a type carries the soul's communication **reach**: whom its
|
|
174
|
+
instances may address, and who may address them.
|
|
175
|
+
|
|
176
|
+
The last point is a requirement from Pepe (2026-09-04). In a
|
|
177
|
+
shared team, every engineer's agents can live in one team, and
|
|
178
|
+
each engineer decides whether their agents may talk to agents
|
|
179
|
+
owned by other engineers or only to their own; a further type may
|
|
180
|
+
talk to agents outside the organization. The type expresses the
|
|
181
|
+
policy; the communication capability enforces it. Spawning into
|
|
182
|
+
the correct team is deployment configuration (today the `team:`
|
|
183
|
+
block that the messaging integration reads), and the flow for
|
|
184
|
+
choosing it must be explicit, never inferred from where a command
|
|
185
|
+
was run.
|
|
186
|
+
|
|
187
|
+
The policy is one field, `reach`, whose values form a ladder in
|
|
188
|
+
which each level includes everything below it (names proposed by
|
|
189
|
+
the OAS side, 2026-09-04):
|
|
190
|
+
|
|
191
|
+
```text
|
|
192
|
+
reach: owner # only agents owned by the same human
|
|
193
|
+
reach: team # any agent in the deployment's team
|
|
194
|
+
reach: org # any team in the same organization
|
|
195
|
+
reach: external # agents outside the organization
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
The ladder mirrors aweb's addressing tiers: a plain alias reaches
|
|
199
|
+
the team, a team-qualified alias the organization, a namespace
|
|
200
|
+
address the outside. `owner` maps to a contacts-only inbound mode
|
|
201
|
+
that aweb does not ship yet (`aweb-abhx`; see the open questions).
|
|
202
|
+
"No communication at all" is not a fifth level; that is the
|
|
203
|
+
messaging slot set to `none`, a layer selection rather than a
|
|
204
|
+
policy. `reach` governs both directions by default, with the
|
|
205
|
+
inbound side enforced by the communication capability; if a case
|
|
206
|
+
ever needs asymmetric policy it splits into `reach.out` and
|
|
207
|
+
`reach.in` then, not now.
|
|
208
|
+
|
|
209
|
+
Today this is the config's agent-type targeting. Formalizing it
|
|
210
|
+
means naming the type in the soul, letting packages ship types,
|
|
211
|
+
and letting the knowledge contract read the type for scoping.
|
|
212
|
+
|
|
213
|
+
### Capability manifest and lifecycle events
|
|
214
|
+
|
|
215
|
+
A capability declares: its slot, if it fills one; what it
|
|
216
|
+
contributes (skills, instruction blocks, commands, environment);
|
|
217
|
+
which lifecycle events it hooks; and what it requires from the
|
|
218
|
+
host. The event list is the API that makes capabilities
|
|
219
|
+
composable and should change rarely. Proposed list: `scaffold`,
|
|
220
|
+
`spawn`, `retire`, `harvest`.
|
|
221
|
+
|
|
222
|
+
### The slot contracts
|
|
223
|
+
|
|
224
|
+
These carry the architecture and should be written as contracts,
|
|
225
|
+
not as descriptions of the default packages.
|
|
226
|
+
|
|
227
|
+
**Knowledge access** has two sides. *Read*: an instance can find
|
|
228
|
+
and consult organizational knowledge within its type's
|
|
229
|
+
scope. *Write*: a permitted soul can promote into it. The format
|
|
230
|
+
is the capability's; the two sides are the contract. Custody
|
|
231
|
+
scoping (soul-shared, workspace overlay, repository overlay)
|
|
232
|
+
belongs to this contract so that repository-specific knowledge
|
|
233
|
+
cannot leak to a cross-repository soul.
|
|
234
|
+
|
|
235
|
+
What the write side accepts is doctrine, and Pepe's position
|
|
236
|
+
(2026-09-04) sharpens `docs/knowledge-theory.md`. The line is
|
|
237
|
+
decision versus description. A description of how the code fits
|
|
238
|
+
together goes stale and competes with the code; that is the slop
|
|
239
|
+
automatic memory accumulates, and the write side rejects it. A
|
|
240
|
+
decision, what was chosen, what was rejected, and why, cannot be
|
|
241
|
+
derived from code; without the record an agent will refactor
|
|
242
|
+
toward the rejected alternative, so the write side accepts it.
|
|
243
|
+
Also accepted: inspiration genealogy ("took this from X, rejected
|
|
244
|
+
Y because Z", the strongest case for design souls), process
|
|
245
|
+
lessons, and maintained, timestamped, superseded-on-change slow
|
|
246
|
+
state about an area. Rejected: task residue (PR numbers,
|
|
247
|
+
half-done plans, point-in-time environment facts), which dies
|
|
248
|
+
with the instance. One home per decision; split-brain comes from
|
|
249
|
+
copies. For non-coding specialists (reviewers, coordinators,
|
|
250
|
+
domain experts) none of their knowledge is re-derivable from a
|
|
251
|
+
repository: those souls are almost pure knowledge, and the
|
|
252
|
+
code-is-truth critique does not apply to them. The harvester's
|
|
253
|
+
promotion judgment encodes this.
|
|
254
|
+
|
|
255
|
+
**Task management**: where shared work state lives, and how an
|
|
256
|
+
instance claims, updates, blocks, and completes work. Verdicts
|
|
257
|
+
and review outcomes are task records, which is how verification
|
|
258
|
+
enters the model without a component.
|
|
259
|
+
|
|
260
|
+
**Communication**: how an instance becomes reachable and reaches
|
|
261
|
+
others. The contract must state whether the address can outlive
|
|
262
|
+
the instance. For a durable specialist the answer should be yes,
|
|
263
|
+
realized however the implementation chooses (aweb: a soul-level
|
|
264
|
+
identity served through per-instance grants). Without this, a
|
|
265
|
+
hosted provider cannot host "the specialist you can always write
|
|
266
|
+
to." The contract also carries the fully-local constraint: two
|
|
267
|
+
instances on one machine must be able to exchange messages
|
|
268
|
+
through a server the operator runs, with no hosted dependency.
|
|
269
|
+
The implementation enforces the soul type's `reach` in both
|
|
270
|
+
directions (for aweb: addressing tiers outbound, inbound mode and
|
|
271
|
+
contacts inbound).
|
|
272
|
+
|
|
273
|
+
**Capture**: the format of ephemeral state. Notes are the agent's
|
|
274
|
+
own report of what mattered; a captured session is ground
|
|
275
|
+
truth. Both satisfy the contract; the harvester may consume
|
|
276
|
+
either or both. Clothes are one optional consumer of the same
|
|
277
|
+
contract.
|
|
278
|
+
|
|
279
|
+
### Runtime provider
|
|
280
|
+
|
|
281
|
+
OATS hands a **realization bundle** to a provider and gets back
|
|
282
|
+
an instance handle:
|
|
283
|
+
|
|
284
|
+
```text
|
|
285
|
+
bundle
|
|
286
|
+
instructions (composed AGENTS.md)
|
|
287
|
+
skills (the exact materialized set)
|
|
288
|
+
capability scripts and environment
|
|
289
|
+
task
|
|
290
|
+
realization artifacts for this runtime, if any (finetune ref, compiled clothes)
|
|
291
|
+
|
|
292
|
+
handle
|
|
293
|
+
observe (status, the session where capture can find it)
|
|
294
|
+
message / steer, where the provider supports it
|
|
295
|
+
stop
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
Whether the bundle becomes Pi in tmux, Claude Code in a
|
|
299
|
+
container, or a hosted agent with no filesystem is the provider's
|
|
300
|
+
business. Define this contract from what Pi and Claude Code
|
|
301
|
+
actually need today, and keep it that small. The 2026-08-15
|
|
302
|
+
implementation plan failed by abstracting execution targets
|
|
303
|
+
beyond that before a second provider existed.
|
|
304
|
+
|
|
305
|
+
#### Worked example: today's Pi launch as bundle and handle
|
|
306
|
+
|
|
307
|
+
Nothing below is new behavior; it is what `spawnInstance` does
|
|
308
|
+
now, named by the contract's parts.
|
|
309
|
+
|
|
310
|
+
The **bundle** OATS assembles under the instance home:
|
|
311
|
+
|
|
312
|
+
- instructions: the composed `AGENTS.md` (soul text, kernel
|
|
313
|
+
block, home/work boundary, work-mode block, capability blocks);
|
|
314
|
+
- skills: the exact materialized tree at `.agents/skills/`,
|
|
315
|
+
with `.claude/skills` linking to it;
|
|
316
|
+
- capability environment and launch arguments: what the spawn
|
|
317
|
+
hooks returned, for example `AWEB_IDENTITY_HOME` and the pi or
|
|
318
|
+
claude launch flags the aweb capability contributes;
|
|
319
|
+
- task: `TASK.md`;
|
|
320
|
+
- a resolved model preference;
|
|
321
|
+
- realization artifacts: none today. This slot is where a
|
|
322
|
+
provider-specific derivative would live if one existed, for
|
|
323
|
+
example a compiled native session file (what `oats experimental
|
|
324
|
+
spawn` produces) or a finetune reference, cached per (soul,
|
|
325
|
+
runtime). It is empty by default and the contract works with it
|
|
326
|
+
empty.
|
|
327
|
+
|
|
328
|
+
The **Pi provider** turns that into a process: it resolves the
|
|
329
|
+
`pi` binary, verifies the runtime packages active capabilities
|
|
330
|
+
require (the aweb pi package, for instance), and builds the
|
|
331
|
+
command `pi --no-skills --skill <home>/.agents/skills
|
|
332
|
+
--no-context-files --no-prompt-templates --append-system-prompt
|
|
333
|
+
<home>/AGENTS.md --approve --name <instance> --model <m> @TASK.md
|
|
334
|
+
<hook args>` with `OATS_INSTANCE` and `OATS_INSTANCE_HOME` in the
|
|
335
|
+
environment. The **Claude Code provider** builds `claude --model
|
|
336
|
+
<m> <hook args> -- "$(cat TASK.md)"` and relies on the
|
|
337
|
+
`CLAUDE.md` and `.claude/skills` links instead of flags. Same
|
|
338
|
+
bundle, two providers.
|
|
339
|
+
|
|
340
|
+
The **platform** is tmux: create the session if absent, open a
|
|
341
|
+
window named after the instance with the home as its working
|
|
342
|
+
directory, run the command, drop to a shell when it exits.
|
|
343
|
+
|
|
344
|
+
The **handle** is what comes back and is recorded in
|
|
345
|
+
`instance.json`: today the `tmux` object (session, window,
|
|
346
|
+
socket) and the persisted command line. Read through the
|
|
347
|
+
contract: *observe* is "does the window exist" plus the native
|
|
348
|
+
transcript location capture reads (`~/.pi/agent/sessions/...`);
|
|
349
|
+
*steer* is attaching to the pane or sending keys; *stop* is
|
|
350
|
+
killing the window, which retire does. A hosted provider would
|
|
351
|
+
return a different handle with the same three verbs.
|
|
352
|
+
|
|
353
|
+
Two things follow. Runtime and platform are separable, which is
|
|
354
|
+
why the migration plan extracts them in two steps and why the
|
|
355
|
+
provider must not be entangled with tmux. And the work-mode
|
|
356
|
+
setup script (`work-modes.worktree.setup`, run inside each fresh
|
|
357
|
+
worktree) belongs to the work target, not to the provider.
|
|
358
|
+
|
|
359
|
+
### Soul store and work target
|
|
360
|
+
|
|
361
|
+
These are separate parameters of instantiation. Today one
|
|
362
|
+
filesystem location under `agents/` decides three things at once:
|
|
363
|
+
who the soul is, where its knowledge is kept, and what its
|
|
364
|
+
instances work on. The 2026-07-30 product boundary review named
|
|
365
|
+
this as the foundational gap. Separating the two seams is what
|
|
366
|
+
removes the repository from the architecture.
|
|
367
|
+
|
|
368
|
+
An instance is therefore:
|
|
369
|
+
|
|
370
|
+
```text
|
|
371
|
+
instance = (soul, runtime provider, work target?, task)
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
Any of the four may be substituted; the work target may be
|
|
375
|
+
absent. The four work modes stay exactly as they are; the
|
|
376
|
+
distinction between an isolated worktree and working directly on
|
|
377
|
+
a checked-out branch matters and is kept. `none` is added for
|
|
378
|
+
instances that operate on nothing, such as a mail-only agent; it
|
|
379
|
+
replaces no mode. The per-mode environment setup script remains
|
|
380
|
+
part of the work-target contract.
|
|
381
|
+
|
|
382
|
+
### Package
|
|
383
|
+
|
|
384
|
+
Acquisition, exact version, integrity, dependency closure,
|
|
385
|
+
executable trust. Exists; a package may now also ship soul
|
|
386
|
+
types.
|
|
387
|
+
|
|
388
|
+
## Three simplifications
|
|
389
|
+
|
|
390
|
+
**The harvester is a soul.** Its input is the capture contract
|
|
391
|
+
and its output is the knowledge contract's write side. Only the
|
|
392
|
+
knowledge capability knows the knowledge format, so the harvester
|
|
393
|
+
belongs to the knowledge package. OATS does not run a special
|
|
394
|
+
harvester; it spawns a soul of a type permitted to write
|
|
395
|
+
knowledge, on the `harvest` lifecycle event. This is already how
|
|
396
|
+
the OKF `memory-harvest` agent runs. A new knowledge format
|
|
397
|
+
brings its own judge.
|
|
398
|
+
|
|
399
|
+
**Soul type is the policy unit.** Stated above; repeated here
|
|
400
|
+
because it removes two would-be components (a reviewer, a
|
|
401
|
+
permission model).
|
|
402
|
+
|
|
403
|
+
**Contracts and bootstrap skills in OATS; implementations in packages.**
|
|
404
|
+
OATS ships the slot contracts and the skill that
|
|
405
|
+
teaches an agent the shape of each. Implementations are
|
|
406
|
+
packages. OATS may bundle a minimal default per slot so a fresh
|
|
407
|
+
installation is a complete product with nothing acquired. This
|
|
408
|
+
answers "meta-capabilities or OATS basic skills": both, split by
|
|
409
|
+
that line, and it keeps OATS the only irreplaceable component
|
|
410
|
+
while ensuring it never knows a tracker, a mail system, or a
|
|
411
|
+
knowledge format.
|
|
412
|
+
|
|
413
|
+
## Realization artifacts: finetuning and clothes
|
|
414
|
+
|
|
415
|
+
Both are runtime-specific by nature: a finetune is per provider,
|
|
416
|
+
a compiled session is per harness. Inside the soul they would
|
|
417
|
+
break "any runtime." Attached to a (soul, runtime) realization
|
|
418
|
+
and cached there, they cost nothing and can be dropped if they
|
|
419
|
+
never pay off. That is the property wanted for a bet whose
|
|
420
|
+
outcome is unknown.
|
|
421
|
+
|
|
422
|
+
Two different things have been called clothes and should be named
|
|
423
|
+
apart:
|
|
424
|
+
|
|
425
|
+
- **curated exemplars** shipped and reviewed with a soul, a
|
|
426
|
+
committed artifact needing no selection machinery;
|
|
427
|
+
- **spawn-time selection** from captured history, the
|
|
428
|
+
experimental `oats experimental dress` path.
|
|
429
|
+
|
|
430
|
+
Only the first is a soul-adjacent artifact. The second stays
|
|
431
|
+
experimental until its experiment reads out, and this
|
|
432
|
+
architecture does not depend on it.
|
|
433
|
+
|
|
434
|
+
## Where the turn record fits
|
|
435
|
+
|
|
436
|
+
The turn record is one implementation of the capture contract,
|
|
437
|
+
and a good one: passive, verbatim, content-addressed,
|
|
438
|
+
searchable. `recall` is a tool over it. `dress` is an optional
|
|
439
|
+
consumer. `attend` belongs to the communication contract's
|
|
440
|
+
implementation, not to OATS. The specification and vectors stay
|
|
441
|
+
where they are.
|
|
442
|
+
|
|
443
|
+
What changes is status: the bookshelf's turn-record documents
|
|
444
|
+
should be re-marked from "accepted architecture direction" to
|
|
445
|
+
"capture substrate and experiment." The repository README should
|
|
446
|
+
lead with the soul, capability, and package model and present the
|
|
447
|
+
record as the default capture.
|
|
448
|
+
|
|
449
|
+
## Consequences for the current implementation
|
|
450
|
+
|
|
451
|
+
Already matching the proposal, no change: souls and `AGENTS.md`;
|
|
452
|
+
capability manifests and hooks; packages and locks; the OKF
|
|
453
|
+
harvester as a capability-defined agent; exclusive slots for
|
|
454
|
+
knowledge, messaging, tasks; the Desktop as the management
|
|
455
|
+
surface.
|
|
456
|
+
|
|
457
|
+
Changes, none of which rewrites anything:
|
|
458
|
+
|
|
459
|
+
1. Write the four slot contracts as contracts, replacing the
|
|
460
|
+
package-shaped descriptions in `docs/layers.md` and
|
|
461
|
+
`docs/integrations.md`.
|
|
462
|
+
2. Formalize soul type: named in `soul.yaml`, shippable in
|
|
463
|
+
packages, read by the knowledge contract for scoping.
|
|
464
|
+
3. Add `harvest` as a lifecycle event; route `oats okf harvest`
|
|
465
|
+
through it.
|
|
466
|
+
4. Make capture a slot; `packages/record` becomes its default
|
|
467
|
+
implementation. Capture means session capture: OKF `notes/`
|
|
468
|
+
are the knowledge capability's own instance memory, not a
|
|
469
|
+
capture implementation, and the harvester reads both. Feed
|
|
470
|
+
the harvester from the capture contract (epic `aweb-abfz`).
|
|
471
|
+
5. Define the runtime-provider contract from the current Pi and
|
|
472
|
+
Claude Code launch paths, and put both behind it. No third
|
|
473
|
+
provider until a real one asks.
|
|
474
|
+
6. Separate soul store from work target in instantiation. First
|
|
475
|
+
step: an instance may declare its work target independently of
|
|
476
|
+
where its soul is stored, which the `workspace` mode already
|
|
477
|
+
half-does.
|
|
478
|
+
7. Add a realization cache per (soul, runtime) for finetune
|
|
479
|
+
references and compiled exemplars, empty by default.
|
|
480
|
+
|
|
481
|
+
## The replaceability test
|
|
482
|
+
|
|
483
|
+
For each seam, name two implementations that both satisfy the
|
|
484
|
+
contract and show a soul running unchanged behind each. Where
|
|
485
|
+
that cannot be done, the contract is unfinished. The two seams
|
|
486
|
+
that fail the test today are runtime provider and soul store;
|
|
487
|
+
they should be the first contracts written, and they should be
|
|
488
|
+
written narrowly.
|
|
489
|
+
|
|
490
|
+
## Migration plan
|
|
491
|
+
|
|
492
|
+
The goal of the migration is the functionality OATS has today,
|
|
493
|
+
under the seams above. Each step is one reviewable landing that
|
|
494
|
+
leaves the test suite green and the output fixtures identical,
|
|
495
|
+
except where a step deliberately adds a surface.
|
|
496
|
+
|
|
497
|
+
### Where the seams sit in the code today
|
|
498
|
+
|
|
499
|
+
The kernel is about 10k lines in `lib/core.mjs` and
|
|
500
|
+
`bin/oats.mjs`, with the package engine partly in
|
|
501
|
+
`lib/packages.mjs`.
|
|
502
|
+
|
|
503
|
+
| Seam | Where it lives today | State |
|
|
504
|
+
|---|---|---|
|
|
505
|
+
| Slot contracts | `LAYERS` plus `resolveOatsConfig` | data-driven; capture is one entry away |
|
|
506
|
+
| Soul type | `agent-types` in config, `type:` in `soul.yaml`, `soulTypeOf` | exists; not exported to hooks, not shippable by packages |
|
|
507
|
+
| Capability manifest, hooks | `runLifecycleHooks`, the manifest schema | stable; three events |
|
|
508
|
+
| Harvester | `memory-harvest` capability agent spawned via `oats spawn --json` | already a soul; triggered by an instance command, not an event |
|
|
509
|
+
| Runtime provider | about 150 lines inside `spawnInstance` plus the model, binary, and runtime-package helpers | entangled with tmux and the home layout |
|
|
510
|
+
| Platform | tmux calls in spawn, retire, status, and the Desktop | one implementation, no interface |
|
|
511
|
+
| Soul store | `findAgent`, `listAgents`, `teamAgentRoots`, `findCapabilityAgent` | three lookups, all filesystem |
|
|
512
|
+
| Work target | `resolveWorkMode` plus the mode branches in spawn, retire, baseline, quarantine | four modes; retire safety depends on them |
|
|
513
|
+
| Package | `lib/packages.mjs` and the engine half of core | the most tested seam; not touched |
|
|
514
|
+
|
|
515
|
+
Two things make "same functionality" checkable. The test suite
|
|
516
|
+
is behavioral, and the externally meaningful outputs are few:
|
|
517
|
+
the composed `AGENTS.md`, `instance.json`, `TASK.md`, the launch
|
|
518
|
+
command line, and the retirement outcome. Frozen as golden
|
|
519
|
+
fixtures first, every extraction below is verified against
|
|
520
|
+
bytes rather than against intent.
|
|
521
|
+
|
|
522
|
+
### The sequence
|
|
523
|
+
|
|
524
|
+
1. **Golden fixtures.** For Pi and Claude Code, each work mode,
|
|
525
|
+
knowledge none and okf, messaging none and a stub: snapshot
|
|
526
|
+
the home layout, the composed instructions, instance metadata
|
|
527
|
+
minus timestamps, the launch command, and the retire
|
|
528
|
+
result. This is the contract for everything after it.
|
|
529
|
+
2. **Contracts on paper.** Rewrite `docs/layers.md` and
|
|
530
|
+
`docs/integrations.md` as the four slot contracts, the
|
|
531
|
+
lifecycle events including `harvest`, runtime provider, soul
|
|
532
|
+
store, and work target. Runs in parallel with step 1.
|
|
533
|
+
3. **Split core by responsibility, no behavior change.** Config
|
|
534
|
+
and scopes, package engine, souls, composition, hooks,
|
|
535
|
+
instances. `lib/core.mjs` stays as the re-export facade so
|
|
536
|
+
the Desktop and the tests keep their import. A pure move,
|
|
537
|
+
checked by the fixtures.
|
|
538
|
+
4. **Extract runtime providers.** A registry with one module
|
|
539
|
+
each for Pi and Claude Code: binary resolution, model
|
|
540
|
+
preference, runtime-package verification, the launch command
|
|
541
|
+
from a realization bundle, and the posture record. Spawn asks
|
|
542
|
+
the provider and no longer branches on the runtime name.
|
|
543
|
+
5. **Extract the platform.** A tmux module with launch, alive,
|
|
544
|
+
stop, and list. Spawn, retire, status, and the Desktop's tmux
|
|
545
|
+
target reads go through it. The `tmux` field in
|
|
546
|
+
`instance.json` stays; a `handle` carrying a kind is added
|
|
547
|
+
beside it, never instead of it, so the Desktop keeps working.
|
|
548
|
+
6. **Harvest as a lifecycle event.** Accept `harvest` in
|
|
549
|
+
manifests, add `oats harvest` to run the active capabilities'
|
|
550
|
+
harvest hooks, have oats-okf declare its hook, and update the
|
|
551
|
+
injected instruction. `oats okf harvest` keeps working. This
|
|
552
|
+
spans repositories and touches the frozen package-runtime
|
|
553
|
+
boundary, so it goes through the coordinator to Pepe.
|
|
554
|
+
7. **Soul type export.** Pass the type to hooks and dispatched
|
|
555
|
+
commands (`OATS_SOUL_TYPE`), let packages declare agent
|
|
556
|
+
types, show it in doctor. Knowledge scoping by type then
|
|
557
|
+
becomes okf's work, reading the type it is given. Same
|
|
558
|
+
boundary rule as step 6.
|
|
559
|
+
8. **Capture as a slot.** Add `capture` to the slot list, wrap
|
|
560
|
+
the record package as a bundled framework-trusted capability
|
|
561
|
+
whose spawn hook records the instance-to-session mapping, and
|
|
562
|
+
keep `oats setup`, `oats capture`, and `oats recall` as
|
|
563
|
+
kernel aliases resolving to the active capture
|
|
564
|
+
capability. The record-fed harvester (`aweb-abfz`) becomes
|
|
565
|
+
okf work over this contract.
|
|
566
|
+
9. **Soul store interface.** Unify the three finders behind one
|
|
567
|
+
list of stores with the filesystem as the single
|
|
568
|
+
implementation; the instance home root becomes the store's
|
|
569
|
+
answer. This is what a provider registry or a Library later
|
|
570
|
+
plugs into.
|
|
571
|
+
10. **Extract work targets and add `none`.** One module per
|
|
572
|
+
mode, with retirement baseline and inspection moving
|
|
573
|
+
alongside. Last, because retire safety and quarantine sit on
|
|
574
|
+
it; the retirement fixtures from step 1 exist for this step.
|
|
575
|
+
11. **Docs and release.** The README leads with the model and
|
|
576
|
+
presents the record as the default capture; the bookshelf
|
|
577
|
+
turn-record documents are re-marked; a release whose only
|
|
578
|
+
user-visible additions are `oats harvest`, the capture slot,
|
|
579
|
+
and the `none` work mode.
|
|
580
|
+
|
|
581
|
+
### Deliberately not in the sequence
|
|
582
|
+
|
|
583
|
+
- a second runtime provider, until a real one asks;
|
|
584
|
+
- a realization cache for finetunes or exemplars, until
|
|
585
|
+
something consumes one;
|
|
586
|
+
- minimal bundled defaults per slot;
|
|
587
|
+
- any change to the package engine.
|
|
588
|
+
|
|
589
|
+
The point of the sequence is that each seam ends with one
|
|
590
|
+
implementation behind a real interface and a fixture proving
|
|
591
|
+
it, so the second implementation is a new module rather than a
|
|
592
|
+
refactor.
|
|
593
|
+
|
|
594
|
+
### Size and parallelism
|
|
595
|
+
|
|
596
|
+
Three to four weeks single-threaded. After step 3, the pairs
|
|
597
|
+
(4, 5), (6, 7), and step 8 are independent and can run on
|
|
598
|
+
separate agents. Steps 6 and 7 need the maintainer's ruling on
|
|
599
|
+
the package-runtime boundary before they start.
|
|
600
|
+
|
|
601
|
+
## Open questions
|
|
602
|
+
|
|
603
|
+
- Does the communication contract *require* a soul-level durable
|
|
604
|
+
address, or only permit one?
|
|
605
|
+
- Is capture a fourth exclusive slot, or an additive capability
|
|
606
|
+
that several packages may provide at once?
|
|
607
|
+
- What does a provider registry need from the soul-store contract
|
|
608
|
+
that a git repository does not?
|
|
609
|
+
- What triggers `harvest`: commit, retire, schedule, or the
|
|
610
|
+
capture capability reporting new state?
|
|
611
|
+
- How does a runtime provider without a filesystem receive
|
|
612
|
+
instructions and skills? This decides whether the bundle is
|
|
613
|
+
files or a document.
|
|
614
|
+
- How do config agent types and soul types unify without breaking
|
|
615
|
+
existing configs?
|
|
616
|
+
- Fully local, answered by the aweb coordinator (2026-09-04,
|
|
617
|
+
task `aweb-abhw`): no hop-free path exists; every delivery goes
|
|
618
|
+
through an aweb server, and the self-hosted stack on localhost
|
|
619
|
+
with the reserved `local` namespace is the intended answer. The
|
|
620
|
+
durable mailbox is the point, so hop-free exchange is not on the
|
|
621
|
+
roadmap. The honest gap is weight (aweb plus AWID plus
|
|
622
|
+
PostgreSQL plus Redis); the open decision is whether a
|
|
623
|
+
lightweight single-process local server is needed.
|
|
624
|
+
- `reach: owner`, answered by the aweb coordinator (2026-09-04,
|
|
625
|
+
task `aweb-abhx`, proposal pending Juan's go-ahead): team
|
|
626
|
+
membership is delivery authority, so owner-only reach cannot be
|
|
627
|
+
enforced inside a shared team with today's inbound modes. The
|
|
628
|
+
proposal is `inbound_mode=contacts_only`, exact active contacts
|
|
629
|
+
only with team membership ignored; each engineer adds their own
|
|
630
|
+
agents as mutual contacts and `owner` maps to it directly. No
|
|
631
|
+
per-owner scope in the team model is needed. Until it lands,
|
|
632
|
+
`owner` reads as "contacts_only, pending aweb-abhx".
|
|
633
|
+
|
|
634
|
+
## Related
|
|
635
|
+
|
|
636
|
+
- [Layers](layers.md), [Capabilities](capabilities.md),
|
|
637
|
+
[Souls and instances](souls-and-instances.md),
|
|
638
|
+
[Knowledge theory](knowledge-theory.md)
|
|
639
|
+
- Bookshelf: `product/2026-07-30-oas-aweb-product-boundary-review.md`,
|
|
640
|
+
`oats/2026-08-18-turn-record-and-tools.md`,
|
|
641
|
+
`oats/2026-08-18-oats-runtime-agents-and-clothes.md`,
|
|
642
|
+
`strategy/2026-09-01-aweb-adoption-and-organizational-sovereignty.md`
|