@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
package/docs/layers.md
CHANGED
|
@@ -1,110 +1,386 @@
|
|
|
1
|
-
# The
|
|
1
|
+
# The OATS contracts
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Status: contracts on paper (migration step 2 of
|
|
4
|
+
[the 2026-09-03 architecture proposal](2026-09-03-architecture-proposal.md)).
|
|
5
|
+
Every section says what is **shipped** today and what is **proposed**. A
|
|
6
|
+
proposed clause describes the contract the kernel will be refactored toward;
|
|
7
|
+
it is not a claim about current behavior, and the shipped documents
|
|
8
|
+
([souls and instances](souls-and-instances.md),
|
|
9
|
+
[capabilities](capabilities.md), [implementation](implementation.md)) remain
|
|
10
|
+
authoritative for what the code does now.
|
|
6
11
|
|
|
7
|
-
|
|
8
|
-
implements them directly. The other three are formally defined, exclusive
|
|
9
|
-
contracts: **knowledge**, **messaging**, and **tasks**. An integration is the
|
|
10
|
-
capability package selected to bind one contract to a real tool; general
|
|
11
|
-
capability packages remain additive.
|
|
12
|
+
The rule the contracts serve:
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
> Every main component is replaceable by another that offers the same
|
|
15
|
+
> contract, with the exception of OATS itself. OATS knows only contracts.
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
| **Soul** | Who is this agent, and how does it grow? | Kernel |
|
|
18
|
-
| **Knowledge** | Where does learning live, and how is it promoted? | Integration |
|
|
19
|
-
| **Instances** | How does a soul run work in the world? | Kernel |
|
|
20
|
-
| **Messaging** | How can this instance be reached by the team? | Integration |
|
|
21
|
-
| **Tasks** | Where does shared work state live? | Integration |
|
|
17
|
+
A contract is finished when two implementations satisfy it and a soul runs
|
|
18
|
+
unchanged behind each. Each section ends with that test.
|
|
22
19
|
|
|
23
|
-
##
|
|
20
|
+
## How the pieces fit
|
|
24
21
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
```text
|
|
23
|
+
soul ─────────── declares which contracts it needs, never which implementation
|
|
24
|
+
│
|
|
25
|
+
├── soul type ── the policy unit: capabilities, knowledge scope, reach
|
|
26
|
+
│
|
|
27
|
+
└── capabilities ── implementations bound by configuration
|
|
28
|
+
├── knowledge (exclusive slot)
|
|
29
|
+
├── tasks (exclusive slot)
|
|
30
|
+
├── communication (exclusive slot; called "messaging" in config today)
|
|
31
|
+
├── capture (proposed slot)
|
|
32
|
+
└── additive capabilities (any number)
|
|
28
33
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
many incarnations.
|
|
34
|
+
instance = (soul, runtime provider, work target?, task)
|
|
35
|
+
```
|
|
32
36
|
|
|
33
|
-
The kernel owns
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
The kernel owns the soul format, the soul type, the capability manifest and
|
|
38
|
+
lifecycle events, and instantiation. Everything else is an implementation
|
|
39
|
+
behind one of the contracts below.
|
|
36
40
|
|
|
37
|
-
##
|
|
41
|
+
## Soul format
|
|
38
42
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
**Shipped.** A soul is a directory: `soul.yaml` (name, kind, description,
|
|
44
|
+
repo, work, runtime, model, type), `AGENTS.md` (the operating definition),
|
|
45
|
+
`skills/`, and whatever a knowledge implementation adds. It is committed and
|
|
46
|
+
reviewed like code, and it never runs by itself.
|
|
42
47
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
48
|
+
**Contract.** A soul declares *which contracts it needs*, not which
|
|
49
|
+
implementation fills them. Its `AGENTS.md` speaks of "your knowledge", "your
|
|
50
|
+
task layer", "your messaging"; the bound capability's injected block says
|
|
51
|
+
what those are in this installation. A soul that names a tracker, a mail
|
|
52
|
+
system, or a knowledge format in its own text is not portable and is
|
|
53
|
+
malformed under this contract.
|
|
47
54
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
spawns a memory-harvest agent that judges notes and promotes
|
|
52
|
-
what belongs in the soul.
|
|
55
|
+
A soul is runtime-neutral as an artifact. Anything derived from it for one
|
|
56
|
+
runtime (a compiled native session, a finetune reference) is a realization
|
|
57
|
+
artifact attached to the (soul, runtime) pair, never soul content.
|
|
53
58
|
|
|
54
|
-
|
|
55
|
-
|
|
59
|
+
**Test.** One packaged soul runs in an installation bound to Jira and in one
|
|
60
|
+
bound to Linear with no change to its files.
|
|
56
61
|
|
|
57
|
-
|
|
62
|
+
## Soul type
|
|
58
63
|
|
|
59
|
-
|
|
64
|
+
**Shipped.** Config declares agent types by name under `agent-types:`; a soul
|
|
65
|
+
opts in with `type: <name>` in `soul.yaml`; capability entries target
|
|
66
|
+
`global`, `agent-types`, or `souls`, and settings resolve soul over type over
|
|
67
|
+
global, then by config closeness.
|
|
60
68
|
|
|
61
|
-
|
|
62
|
-
work tree, a task briefing, metadata, and possibly episodic memory.
|
|
69
|
+
**Contract.** The soul type is the policy unit. It decides:
|
|
63
70
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
71
|
+
- which capabilities a soul of that type receives, and with which settings;
|
|
72
|
+
- what knowledge it may read (custody scope) and whether it may write
|
|
73
|
+
knowledge (a harvester is a type permitted to write);
|
|
74
|
+
- its communication **reach**, in both directions.
|
|
67
75
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
(There is no resume command; a retired instance is gone — its session
|
|
71
|
-
transcript survives in the turn record if capture is running.)
|
|
76
|
+
`reach` is one field with a monotone ladder, each level including the ones
|
|
77
|
+
below:
|
|
72
78
|
|
|
73
|
-
|
|
79
|
+
```text
|
|
80
|
+
reach: owner # only agents owned by the same human
|
|
81
|
+
reach: team # any agent in the deployment's team
|
|
82
|
+
reach: org # any team in the same organization
|
|
83
|
+
reach: external # agents outside the organization
|
|
84
|
+
```
|
|
74
85
|
|
|
75
|
-
|
|
86
|
+
"No communication" is not a level; it is the communication slot set to
|
|
87
|
+
`none`. `reach` governs whom an instance may address and who may address it;
|
|
88
|
+
the communication implementation enforces both sides.
|
|
76
89
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
the instance retires.
|
|
90
|
+
**Proposed.** The type is exported to hooks and dispatched commands as
|
|
91
|
+
`OATS_SOUL_TYPE`; packages may ship types; a type may declare `reach`.
|
|
80
92
|
|
|
81
|
-
|
|
82
|
-
|
|
93
|
+
**Test.** Two souls of different types, spawned in one installation, receive
|
|
94
|
+
different capability sets and different knowledge scopes with no per-soul
|
|
95
|
+
configuration.
|
|
83
96
|
|
|
84
|
-
|
|
85
|
-
coordination belongs to layer 5.
|
|
97
|
+
## Capability manifest and lifecycle events
|
|
86
98
|
|
|
87
|
-
|
|
99
|
+
**Shipped.** A capability is a set of scripts, skills, and docs with an
|
|
100
|
+
`oats.json` manifest declaring: `capability` (id), optional `layer`,
|
|
101
|
+
`skills`, `inject`, `commands`, `requires` (host commands and runtime
|
|
102
|
+
packages), `environment` (launch variables it may contribute, vendor-prefixed),
|
|
103
|
+
and `hooks`. Accepted events are `soul-scaffold`, `spawn`, and `retire`. Hooks
|
|
104
|
+
receive `OATS_EVENT`, `OATS_CAPABILITY`, `OATS_LAYER`, `OATS_INSTANCE`,
|
|
105
|
+
`OATS_HOME` (with `OATS_INSTANCE_HOME` as its alias), `OATS_AGENT`,
|
|
106
|
+
`OATS_SOUL`, `OATS_CONTEXT`, `OATS_WORKSPACE`, `OATS_ROOT`, `OATS_LEVEL`,
|
|
107
|
+
`OATS_SETTINGS`, `OATS_META`, and the team variables, and may return `meta`, `brief`, `warning`, runtime-specific
|
|
108
|
+
`launch` arguments, and (spawn only) `env`. Only a spawn hook may be
|
|
109
|
+
`required`. The full contract, including trust and rollback, is in
|
|
110
|
+
[capabilities](capabilities.md) and is not restated here.
|
|
88
111
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
112
|
+
**Contract.** The event list is the API that makes capabilities composable
|
|
113
|
+
and changes rarely. An implementation of any slot below is a capability that
|
|
114
|
+
declares that slot as its `layer`; two active capabilities cannot fill one
|
|
115
|
+
slot for one soul. Packages talk to the kernel only through the structured
|
|
116
|
+
CLI boundary (`oats ... --json`, `OATS_CLI_BIN`), never by importing kernel
|
|
117
|
+
files; see [package-runtime-api](design/package-runtime-api.md).
|
|
92
118
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
119
|
+
**Proposed.** A fourth event, `harvest`, run by `oats harvest` for every
|
|
120
|
+
active capability that declares it, with the same environment as `spawn`
|
|
121
|
+
plus the instance whose ephemeral state is to be promoted. The knowledge
|
|
122
|
+
implementation's harvest hook is how promotion is triggered without the
|
|
123
|
+
kernel knowing the knowledge format.
|
|
96
124
|
|
|
97
|
-
|
|
125
|
+
**Test.** Two capabilities filling the same slot in two installations; the
|
|
126
|
+
kernel's code has no branch that names either.
|
|
98
127
|
|
|
99
|
-
|
|
100
|
-
to specialize.
|
|
128
|
+
## The knowledge contract
|
|
101
129
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
the
|
|
130
|
+
**Shipped.** The `knowledge` slot. The bundled implementation is `oats.okf`:
|
|
131
|
+
an OKF bundle under `soul/knowledge/`, per-instance `STATE.md`, `log.md`, and
|
|
132
|
+
`notes/`, the `okf` and `memory-harvest` skills, and `oats okf harvest`, which
|
|
133
|
+
spawns the capability-defined `memory-harvest` soul attached to the source
|
|
134
|
+
instance's work tree. `knowledge: none` is valid and yields no memory files
|
|
135
|
+
and no harvest.
|
|
106
136
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
137
|
+
**Contract.** Two sides.
|
|
138
|
+
|
|
139
|
+
*Read.* An instance can find and consult organizational knowledge,
|
|
140
|
+
index-first and selectively, and is told how by the implementation's injected
|
|
141
|
+
block and skill. Prior decisions, lessons, and playbooks in scope are binding
|
|
142
|
+
context; re-deriving what the soul already knows is a bug. **Proposed:** the
|
|
143
|
+
scope of what an instance may read is decided by its soul type, which needs
|
|
144
|
+
`OATS_SOUL_TYPE` (step 7) before an implementation can act on it.
|
|
145
|
+
|
|
146
|
+
*Write.* A permitted soul (a harvester type) can promote into the store. The
|
|
147
|
+
format is the implementation's. Delivery matches the soul's custody: a commit
|
|
148
|
+
on the instance's branch for repository-resident souls, a pull request to
|
|
149
|
+
the soul's home repository for workspace-mode souls, direct edits for local
|
|
150
|
+
souls.
|
|
151
|
+
|
|
152
|
+
*Custody, shipped.* Delivery custody is keyed by where the soul resides: a
|
|
153
|
+
commit on the instance's branch for repository-resident souls, a pull request
|
|
154
|
+
to the soul's home repository for workspace-mode souls, direct edits for local
|
|
155
|
+
souls. That is the only custody the kernel and `oats.okf` implement today.
|
|
156
|
+
|
|
157
|
+
*Custody scoping, proposed.* The requirement is that repository-specific
|
|
158
|
+
facts never move into a broader scope by default and that a cross-repository
|
|
159
|
+
soul never reads another repository's specifics. The design that meets it
|
|
160
|
+
belongs to the knowledge package, not the kernel. Custody layers (soul-shared,
|
|
161
|
+
workspace overlay, repository overlay) are one candidate; scoping by soul
|
|
162
|
+
type plus residency is another. Nothing here is settled or shipped.
|
|
163
|
+
|
|
164
|
+
*Promotion doctrine.* What the write side accepts is a decision, not a
|
|
165
|
+
format question. The line is decision versus description. Descriptions of
|
|
166
|
+
how the code fits together go stale and compete with the code; the write
|
|
167
|
+
side rejects them. Decisions, what was chosen, what was rejected, and why,
|
|
168
|
+
cannot be derived from code and are accepted, as are inspiration genealogy
|
|
169
|
+
("took this from X, rejected Y because Z"), process lessons, and maintained,
|
|
170
|
+
timestamped, superseded-on-change slow state about an area. Slow state is
|
|
171
|
+
accepted only with its maintenance discipline: a named owner and an
|
|
172
|
+
update-on-change rule; a slow-state concept nobody maintains is
|
|
173
|
+
indistinguishable from residue and is rejected as such. Task residue
|
|
174
|
+
(pull-request numbers, half-done plans, point-in-time environment facts) dies
|
|
175
|
+
with the instance. One home per decision; split-brain comes from copies. The
|
|
176
|
+
homing rule: architecture facts that several roles need go in repository-
|
|
177
|
+
visible docs and souls point to them; craft decisions scoped to one role go
|
|
178
|
+
in that role's soul; product direction goes in the steward's bundle,
|
|
179
|
+
consulted and never copied. For non-coding specialists none of their
|
|
180
|
+
knowledge is re-derivable from a repository, so those souls are almost pure
|
|
181
|
+
knowledge. See [knowledge theory](knowledge-theory.md) for the derivation.
|
|
182
|
+
|
|
183
|
+
**Proposed.** The harvester's input widens from the agent's own notes to the
|
|
184
|
+
capture contract (below), so lessons reach the soul even when an agent wrote
|
|
185
|
+
no notes; the promotion doctrine is unchanged, only the input channel widens.
|
|
186
|
+
|
|
187
|
+
**Test.** A plain-Markdown or wiki-backed implementation beside `oats.okf`,
|
|
188
|
+
each with its own harvester; a soul's `AGENTS.md` unchanged between them.
|
|
189
|
+
|
|
190
|
+
## The tasks contract
|
|
191
|
+
|
|
192
|
+
**Shipped.** The `tasks` slot. Bundled implementations are `oats.jira`
|
|
193
|
+
(the `jira-tasks` protocol via `acli`) and `oats.linear` (JSON-first
|
|
194
|
+
`oats linear` commands and the `linear-tasks` skill). There is no default;
|
|
195
|
+
`tasks: none` is valid.
|
|
196
|
+
|
|
197
|
+
**Contract.** Where shared work state lives and how an instance claims,
|
|
198
|
+
updates, blocks, hands off, and completes work, taught by the implementation's
|
|
199
|
+
injected block and skill. An instance is identified to the tracker in a way
|
|
200
|
+
that survives the instance (today a label, `agent-<instance-name>`). Task
|
|
201
|
+
state, status, and outcomes live in the tracker; conversation lives in the
|
|
202
|
+
communication slot; the two are not merged even when one tool offers both.
|
|
203
|
+
|
|
204
|
+
Verdicts and review outcomes are task records. That is how verification
|
|
205
|
+
enters the model without a component: a reviewer is a soul type, and what it
|
|
206
|
+
concludes is written where work state lives.
|
|
207
|
+
|
|
208
|
+
**Test.** Jira and Linear already satisfy it; a third (beads, GitHub Issues)
|
|
209
|
+
is the proof that the contract is not a description of either.
|
|
210
|
+
|
|
211
|
+
## The communication contract
|
|
212
|
+
|
|
213
|
+
**Shipped.** The `messaging` slot. The bundled implementation is `oats.aweb`:
|
|
214
|
+
a team-scoped aweb identity minted per instance at spawn (alias = instance
|
|
215
|
+
name) by a required spawn hook and deleted at retire, the `aweb-messaging`,
|
|
216
|
+
`aweb-team-membership`, and `aweb-identity` skills, `oats aweb roster` and
|
|
217
|
+
`oats aweb setup`, and channel-plugin launch arguments so a session is woken
|
|
218
|
+
by incoming mail. `messaging: none` is valid.
|
|
219
|
+
|
|
220
|
+
**Contract.** How an instance becomes reachable and reaches others. The
|
|
221
|
+
implementation supplies:
|
|
222
|
+
|
|
223
|
+
- an address for the instance, discoverable by teammates, and the roster
|
|
224
|
+
that lists them across machines;
|
|
225
|
+
- durable asynchronous mail and synchronous chat, with reply and
|
|
226
|
+
acknowledgement state;
|
|
227
|
+
- a wake-up signal when work arrives, with the decision to resume or launch
|
|
228
|
+
left to the runtime owner;
|
|
229
|
+
- enforcement of the soul type's `reach`, outbound by what the address can
|
|
230
|
+
reach and inbound by who may deliver to it;
|
|
231
|
+
- a statement of whether the address can outlive the instance. For a durable
|
|
232
|
+
specialist the answer should be yes, realized however the implementation
|
|
233
|
+
chooses (for aweb: a soul-level identity served through per-instance
|
|
234
|
+
grants).
|
|
235
|
+
|
|
236
|
+
Communication is only communication. Task coordination lives in the tasks
|
|
237
|
+
slot.
|
|
238
|
+
|
|
239
|
+
*Fully local.* It must remain possible to run everything filesystem-based and
|
|
240
|
+
fully local, meaning with no dependency on a hosted service the operator
|
|
241
|
+
cannot replace. Communication needs a server; a self-hosted one on localhost
|
|
242
|
+
satisfies the constraint. What the implementation must hold on *its*
|
|
243
|
+
servers, and the traffic that must pass through them, is minimized. For aweb
|
|
244
|
+
today every delivery passes through an aweb server, hosted or self-hosted on
|
|
245
|
+
localhost with the reserved `local` namespace (`aweb-abhw` records the open
|
|
246
|
+
decision on a lighter local server). `reach: owner` maps to a contacts-only
|
|
247
|
+
inbound mode that aweb does not ship yet (`aweb-abhx`).
|
|
248
|
+
|
|
249
|
+
**Proposed.** The slot is renamed from `messaging` to `communication` in
|
|
250
|
+
documentation first; the config key stays `messaging` until a release
|
|
251
|
+
decides otherwise.
|
|
252
|
+
|
|
253
|
+
**Test.** aweb and a second implementation (a Slack bridge, an A2A gateway)
|
|
254
|
+
behind the same injected promises; a soul's `AGENTS.md` unchanged between
|
|
255
|
+
them.
|
|
256
|
+
|
|
257
|
+
## The capture contract (proposed)
|
|
258
|
+
|
|
259
|
+
**Shipped, outside the slot model.** On machines where `oats setup` has run,
|
|
260
|
+
`packages/record` captures Claude Code, Pi, and Codex transcripts plus aw
|
|
261
|
+
client logs. It skips sources matched by the local record's ignore list. It
|
|
262
|
+
stores captured turns in an append-only, content-addressed record with a search
|
|
263
|
+
index (`oats setup`, `oats capture`, `oats recall`). It is not a capability and
|
|
264
|
+
no lifecycle hook knows about it.
|
|
265
|
+
|
|
266
|
+
**Contract.** The format of ephemeral state. Two kinds satisfy it: an agent's
|
|
267
|
+
own notes (its report of what mattered, today created by the knowledge
|
|
268
|
+
implementation) and a captured session (ground truth). The harvester may
|
|
269
|
+
consume either or both. Clothes, the optional spawn-time selection of past
|
|
270
|
+
conversation, are one consumer of the same contract and depend on nothing
|
|
271
|
+
else in this document. Capture never mediates the harness and fails visibly;
|
|
272
|
+
a silent capture gap is worse than none.
|
|
273
|
+
|
|
274
|
+
**Proposed.** `capture` becomes a slot; `packages/record` is wrapped as a
|
|
275
|
+
bundled, framework-trusted capability whose spawn hook records the
|
|
276
|
+
instance-to-session mapping; `oats setup`, `oats capture`, and `oats recall`
|
|
277
|
+
become kernel aliases resolving to the active capture implementation.
|
|
278
|
+
Whether capture is exclusive or additive is open.
|
|
279
|
+
|
|
280
|
+
**Test.** The record beside a notes-only implementation; the harvester reads
|
|
281
|
+
both.
|
|
282
|
+
|
|
283
|
+
## The runtime provider contract (proposed)
|
|
284
|
+
|
|
285
|
+
**Shipped.** Two runtimes, `pi` and `claude`, selected by `soul.yaml` or
|
|
286
|
+
`--runtime`, launched in a local tmux window; the branching lives inside
|
|
287
|
+
`spawnInstance`. The worked example in the
|
|
288
|
+
[proposal](2026-09-03-architecture-proposal.md#worked-example-todays-pi-launch-as-bundle-and-handle)
|
|
289
|
+
names today's launch in the contract's terms.
|
|
290
|
+
|
|
291
|
+
**Contract.** OATS hands a provider a realization bundle and receives an
|
|
292
|
+
instance handle:
|
|
293
|
+
|
|
294
|
+
```text
|
|
295
|
+
bundle
|
|
296
|
+
instructions the composed AGENTS.md
|
|
297
|
+
skills the exact materialized tree
|
|
298
|
+
environment, launch args what active capabilities contributed
|
|
299
|
+
task TASK.md
|
|
300
|
+
model preference resolved
|
|
301
|
+
realization artifacts per (soul, runtime); empty by default
|
|
302
|
+
|
|
303
|
+
handle
|
|
304
|
+
observe is it running; where the session transcript is
|
|
305
|
+
steer attach or send input, where supported
|
|
306
|
+
stop
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
The provider decides how the bundle becomes a running agent. It knows
|
|
310
|
+
nothing of tmux; the **platform** (today tmux: session, window, working
|
|
311
|
+
directory) is a separate module with launch, alive, stop, and list. The
|
|
312
|
+
handle is recorded in `instance.json` with a kind; the existing `tmux` field
|
|
313
|
+
is kept beside it.
|
|
314
|
+
|
|
315
|
+
A provider declares which runtime packages the active capabilities require
|
|
316
|
+
of it and verifies them before launch; it never installs them. A provider
|
|
317
|
+
without a filesystem receives the bundle as a document rather than files;
|
|
318
|
+
how is open.
|
|
319
|
+
|
|
320
|
+
**Test.** Pi and Claude Code behind one interface with `spawnInstance` free of
|
|
321
|
+
runtime names, proven by the golden fixtures (step 1). A hosted provider is
|
|
322
|
+
the second real implementation and is not built until one asks.
|
|
323
|
+
|
|
324
|
+
## The soul store contract (proposed)
|
|
325
|
+
|
|
326
|
+
**Shipped.** Souls live under `agents/` (committed) or `local-agents/`
|
|
327
|
+
(never committed) at a scope, and capability packages may ship souls under
|
|
328
|
+
`agents:` in their manifest. Three lookups find them; instance homes live in
|
|
329
|
+
the soul-owning repository's primary checkout.
|
|
330
|
+
|
|
331
|
+
**Contract.** A store lists souls, finds one by name, and says where its
|
|
332
|
+
instances live. The filesystem is the single implementation; a package and a
|
|
333
|
+
provider registry are the candidates that would prove the contract.
|
|
334
|
+
Separating the store from the work target is what removes the repository
|
|
335
|
+
from the architecture: today one path decides who the soul is, where its
|
|
336
|
+
knowledge lives, and what it works on.
|
|
337
|
+
|
|
338
|
+
**Test.** A soul found through a second store, instantiated with the same
|
|
339
|
+
bundle.
|
|
340
|
+
|
|
341
|
+
## The work target contract
|
|
342
|
+
|
|
343
|
+
**Shipped.** Four modes decide what `<instance-home>/work` is and what
|
|
344
|
+
discipline the instance follows: `worktree` (an isolated branch), `checkout`
|
|
345
|
+
(the shared current branch), `attached` (another instance's tree), and
|
|
346
|
+
`workspace` (the whole team scope, read-only). A config may run a setup
|
|
347
|
+
script inside each fresh worktree. Retirement preserves ordinary work,
|
|
348
|
+
quarantines incomplete cleanup, and never removes a shared tree. The
|
|
349
|
+
generated instructions state the home/work boundary before the mode block.
|
|
350
|
+
|
|
351
|
+
**Contract.** The work target is a parameter of instantiation independent of
|
|
352
|
+
where the soul is stored. Each mode is a module that prepares the view,
|
|
353
|
+
states its discipline, and knows how to retire it safely, with the
|
|
354
|
+
retirement baseline and inspection alongside. The four modes stay exactly as
|
|
355
|
+
they are.
|
|
356
|
+
|
|
357
|
+
**Proposed.** A fifth target, `none`, for instances that operate on nothing
|
|
358
|
+
(a mail-only agent). It replaces no mode.
|
|
359
|
+
|
|
360
|
+
**Test.** An instance of one soul spawned with each target, the same soul
|
|
361
|
+
files throughout.
|
|
362
|
+
|
|
363
|
+
## The package contract
|
|
364
|
+
|
|
365
|
+
**Shipped, and not touched by the migration.** Acquisition, exact version and
|
|
366
|
+
commit, payload and artifact integrity, dependency closure, executable trust,
|
|
367
|
+
and transactional restore; see [packages](packages.md),
|
|
368
|
+
[capabilities](capabilities.md), and the
|
|
369
|
+
[package-engine contract](design/package-engine-contract.md).
|
|
370
|
+
|
|
371
|
+
**Proposed.** A package may also ship soul types.
|
|
372
|
+
|
|
373
|
+
## The replaceability test, summarized
|
|
374
|
+
|
|
375
|
+
| Contract | Implementations today | Second implementation |
|
|
376
|
+
| --- | --- | --- |
|
|
377
|
+
| Knowledge | `oats.okf` | plain Markdown or wiki |
|
|
378
|
+
| Tasks | `oats.jira`, `oats.linear` | beads, GitHub Issues |
|
|
379
|
+
| Communication | `oats.aweb` | Slack bridge, A2A gateway |
|
|
380
|
+
| Capture | `packages/record`, OKF notes | either alone |
|
|
381
|
+
| Runtime provider | Pi, Claude Code (entangled) | a hosted provider |
|
|
382
|
+
| Soul store | filesystem | package, provider registry |
|
|
383
|
+
| Work target | worktree, checkout, attached, workspace | `none` |
|
|
384
|
+
|
|
385
|
+
Where only one implementation exists, the contract is still a description of
|
|
386
|
+
that one; those rows are the work.
|