@awebai/oats 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +380 -0
- package/bin/oats.mjs +3294 -0
- package/capabilities/oats-authoring/oats.json +12 -0
- package/capabilities/oats-aweb/bin/oats-aweb.mjs +297 -0
- package/capabilities/oats-aweb/injects/aweb.md +55 -0
- package/capabilities/oats-aweb/oats.json +47 -0
- package/capabilities/oats-aweb/package.json +20 -0
- package/capabilities/oats-jira/bin/oats-jira.mjs +40 -0
- package/capabilities/oats-jira/injects/jira.md +10 -0
- package/capabilities/oats-jira/oats.json +22 -0
- package/capabilities/oats-jira/package.json +25 -0
- package/capabilities/oats-jira/skills/jira-tasks/SKILL.md +176 -0
- package/capabilities/oats-linear/README.md +234 -0
- package/capabilities/oats-linear/bin/oats-linear-hook.mjs +32 -0
- package/capabilities/oats-linear/bin/oats-linear.mjs +344 -0
- package/capabilities/oats-linear/injects/linear.md +8 -0
- package/capabilities/oats-linear/oats.json +24 -0
- package/capabilities/oats-linear/package.json +29 -0
- package/capabilities/oats-linear/skills/linear-tasks/SKILL.md +217 -0
- package/capabilities/oats-linear/test/oats-linear.test.mjs +168 -0
- package/capabilities/oats-okf/agents/memory-harvest.md +25 -0
- package/capabilities/oats-okf/bin/oats-okf.mjs +283 -0
- package/capabilities/oats-okf/injects/okf.md +62 -0
- package/capabilities/oats-okf/oats.json +20 -0
- package/capabilities/oats-okf/package.json +22 -0
- package/capabilities/oats-okf/skills/memory-harvest/SKILL.md +100 -0
- package/capabilities/oats-okf/skills/okf/SKILL.md +107 -0
- package/capabilities/oats-okf/skills/okf/scripts/okf-validate.mjs +123 -0
- package/capabilities/oats-review/agents/reviewer/AGENTS.md +53 -0
- package/capabilities/oats-review/agents/reviewer/soul.yaml +6 -0
- package/capabilities/oats-review/injects/review.md +68 -0
- package/capabilities/oats-review/oats.json +10 -0
- package/capabilities/oats-review/skills/code-review/SKILL.md +44 -0
- package/capabilities/oats-review/skills/security-review/SKILL.md +59 -0
- package/docs/capabilities.md +505 -0
- package/docs/capability-manifest.schema.json +223 -0
- package/docs/configuration.md +482 -0
- package/docs/conventions.md +73 -0
- package/docs/design/desktop-ux-plan.md +362 -0
- package/docs/design/package-engine-contract.md +813 -0
- package/docs/design/package-runtime-api.md +414 -0
- package/docs/desktop-cli-api.md +89 -0
- package/docs/desktop-succession.md +51 -0
- package/docs/desktop.md +187 -0
- package/docs/implementation.md +282 -0
- package/docs/integrations.md +123 -0
- package/docs/knowledge-theory.md +97 -0
- package/docs/knowledge.md +139 -0
- package/docs/layers.md +110 -0
- package/docs/migration-from-oas.md +122 -0
- package/docs/oats-config.schema.json +140 -0
- package/docs/oats-lock.schema.json +175 -0
- package/docs/oats-package.schema.json +129 -0
- package/docs/packages.md +442 -0
- package/docs/release-lane.md +132 -0
- package/docs/release-notes/v0.18.2.md +79 -0
- package/docs/release-notes/v0.18.3.md +63 -0
- package/docs/release-notes/v0.18.4.md +65 -0
- package/docs/release-notes/v0.18.5.md +66 -0
- package/docs/release-notes/v0.18.6.md +87 -0
- package/docs/release-notes/v0.19.0.md +186 -0
- package/docs/release-notes/v0.19.1.md +24 -0
- package/docs/release-notes/v0.19.2.md +32 -0
- package/docs/release-notes/v0.19.3.md +16 -0
- package/docs/release-notes/v0.19.4.md +12 -0
- package/docs/release-notes/v0.20.0.md +89 -0
- package/docs/release-notes/v0.22.0.md +180 -0
- package/docs/souls-and-instances.md +344 -0
- package/injects/framework-workspace.md +7 -0
- package/injects/instance-boundary.md +43 -0
- package/injects/local-soul.md +19 -0
- package/injects/oats.md +11 -0
- package/injects/work-attached.md +16 -0
- package/injects/work-checkout.md +12 -0
- package/injects/work-workspace.md +22 -0
- package/injects/work-worktree.md +13 -0
- package/lib/core.mjs +6792 -0
- package/lib/packages.mjs +1375 -0
- package/lib/tmux-config.mjs +35 -0
- package/package-catalog.json +44 -0
- package/package.json +55 -0
- package/packages/record/README.md +151 -0
- package/packages/record/bin/capture.mjs +256 -0
- package/packages/record/bin/recall.mjs +102 -0
- package/packages/record/bin/setup.mjs +281 -0
- package/packages/record/bin/turn-record.mjs +47 -0
- package/packages/record/docs/turn-record-sot.md +350 -0
- package/packages/record/lib/canonical.mjs +151 -0
- package/packages/record/lib/capture-aw.mjs +179 -0
- package/packages/record/lib/capture-cc.mjs +322 -0
- package/packages/record/lib/formats.mjs +296 -0
- package/packages/record/lib/ignore.mjs +155 -0
- package/packages/record/lib/index-db.mjs +524 -0
- package/packages/record/lib/project-aweb.mjs +251 -0
- package/packages/record/lib/segments.mjs +186 -0
- package/packages/record/lib/store.mjs +447 -0
- package/packages/record/lib/tags.mjs +114 -0
- package/packages/record/package.json +45 -0
- package/packages/record/test/vectors/README.md +34 -0
- package/packages/record/test/vectors/aweb-projection-v1.json +231 -0
- package/packages/record/test/vectors/journal-merge-v1.json +261 -0
- package/packages/record/test/vectors/turn-id-v1.json +152 -0
- package/packages/record/test/vectors/validate.mjs +391 -0
- package/skills/integration-authoring/SKILL.md +76 -0
- package/skills/oats/SKILL.md +151 -0
- package/skills/oats-config/SKILL.md +162 -0
- package/skills/oats-getting-started/SKILL.md +159 -0
- package/skills/oats-packages/SKILL.md +180 -0
- package/skills/oats-support/SKILL.md +79 -0
- package/skills/skill-craft/SKILL.md +109 -0
- package/skills/soul-craft/SKILL.md +109 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# What belongs in a soul, and what belongs in an instance
|
|
2
|
+
|
|
3
|
+
The knowledge layer's *format* is pluggable in OATS. The ideas below are not.
|
|
4
|
+
They come from asking what memory means for an agent that outlives its
|
|
5
|
+
sessions, and they apply whatever format or tooling you bind — OKF, plain
|
|
6
|
+
markdown, or something else entirely.
|
|
7
|
+
|
|
8
|
+
## The derivation
|
|
9
|
+
|
|
10
|
+
A **soul** is identity across incarnations. So soul knowledge must be
|
|
11
|
+
**incarnation-invariant** — true and binding for any future instance, on any
|
|
12
|
+
model, in any session. "Durable AND would change what a future instance
|
|
13
|
+
does" is the promotion bar, and it is really an invariance test.
|
|
14
|
+
|
|
15
|
+
An **instance** is one incarnation's work. So instance memory is
|
|
16
|
+
**indexical** — saturated with *I, here, now*. This branch. This blocker.
|
|
17
|
+
This half-done plan. Indexical content cannot live in the soul, because its
|
|
18
|
+
referents die when the instance does.
|
|
19
|
+
|
|
20
|
+
That one distinction decides most placement questions on its own.
|
|
21
|
+
|
|
22
|
+
## Harvest is de-indexicalization
|
|
23
|
+
|
|
24
|
+
Moving knowledge from instance to soul is not copying files. It is
|
|
25
|
+
rephrasing an insight so it survives its author. "The build broke until I
|
|
26
|
+
cleared the cache" is indexical. "The build caches stale schemas — clear
|
|
27
|
+
`.cache/schemas` after model changes" is invariant. Consolidation succeeds
|
|
28
|
+
when the *I, here, now* is gone and the claim still holds.
|
|
29
|
+
|
|
30
|
+
A useful corollary for any implementation: an instance file's format rigor
|
|
31
|
+
should be proportional to its odds of surviving the instance. Working state
|
|
32
|
+
can be loose. Promotion candidates should be written in soul genre from
|
|
33
|
+
birth.
|
|
34
|
+
|
|
35
|
+
## Capture and judgment are different jobs
|
|
36
|
+
|
|
37
|
+
Instances should **capture without judging**. Writing an insight down is
|
|
38
|
+
cheap and best done in the moment, by the one who had it. Judging whether it
|
|
39
|
+
clears the promotion bar is expensive and best done deliberately, by
|
|
40
|
+
something that is not in the middle of a task.
|
|
41
|
+
|
|
42
|
+
Splitting the two has a second benefit. Agents that self-censor against a
|
|
43
|
+
half-remembered bar write less. Agents told "capture everything non-obvious,
|
|
44
|
+
judgment is someone else's job" write more, and the judge applies one
|
|
45
|
+
consistent standard across all of them.
|
|
46
|
+
|
|
47
|
+
## Knowledge consolidates through stages
|
|
48
|
+
|
|
49
|
+
A fresh observation is not yet a lesson. It matures:
|
|
50
|
+
|
|
51
|
+
| Stage | Example | Lives |
|
|
52
|
+
|---|---|---|
|
|
53
|
+
| Working state | "next: fix the failing test" | instance, rewritten freely |
|
|
54
|
+
| Observation | "PATCH with nulls seems to be a no-op" | instance, captured as-is |
|
|
55
|
+
| Lesson | "the API drops nulls — send empty strings" | soul, once verified |
|
|
56
|
+
| Procedure | "steps to clear stuck queues" | soul, as a playbook or skill |
|
|
57
|
+
|
|
58
|
+
The judge's routing question at the last step is one of shape. Facts that
|
|
59
|
+
future instances should **know** become knowledge. Steps they should **run
|
|
60
|
+
the same way** become skills. A correction to existing steps maintains the
|
|
61
|
+
skill it corrects.
|
|
62
|
+
|
|
63
|
+
## Decisions carry jurisdiction by location
|
|
64
|
+
|
|
65
|
+
"We will retry twice, then escalate" can bind one task, or bind every future
|
|
66
|
+
incarnation. The words are the same. The difference is where it is recorded
|
|
67
|
+
— task decisions live and die with the instance's working state, soul
|
|
68
|
+
decisions bind everyone after. Placement, not phrasing, carries the
|
|
69
|
+
authority.
|
|
70
|
+
|
|
71
|
+
## Souls hold slow state, not just timeless truth
|
|
72
|
+
|
|
73
|
+
Not everything in a soul is eternal. A roadmap, a deployment's current
|
|
74
|
+
shape, an open question — these are present-tense facts that tick at project
|
|
75
|
+
speed rather than task speed. Durability is a spectrum. Task-fast state
|
|
76
|
+
belongs to the instance. Project-slow state belongs to the soul and should
|
|
77
|
+
carry dates, because it rots. Timeless lessons belong to the soul and mostly
|
|
78
|
+
do not.
|
|
79
|
+
|
|
80
|
+
## The knowledge structure is itself specialization
|
|
81
|
+
|
|
82
|
+
Ship a minimal core ontology and let each soul grow the rest. An architect
|
|
83
|
+
soul grows a roadmap section. A developer soul grows a codebase-gotchas
|
|
84
|
+
section. A roadmap section in a developer soul is a smell — project
|
|
85
|
+
direction belongs to whoever stewards the project.
|
|
86
|
+
|
|
87
|
+
The test for growing a section is the promotion bar, one level up. Would
|
|
88
|
+
future instances of *this* soul need to navigate this kind of knowledge? If
|
|
89
|
+
yes, grow it and record why. If no, it is one concept, not a section.
|
|
90
|
+
|
|
91
|
+
## Where OATS encodes these ideas
|
|
92
|
+
|
|
93
|
+
In the reference implementation the ideas surface as: the okf integration's
|
|
94
|
+
capture protocol (instances write, no judging), the memory-harvest agent
|
|
95
|
+
(the judge, holding the bar and the routing table), and per-soul knowledge
|
|
96
|
+
bundles that grow role-specific sections. Swap the format and the mechanics
|
|
97
|
+
change. The ideas above should not.
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Knowledge — layer 2
|
|
2
|
+
|
|
3
|
+
Specialization is accumulated judgment. A specialist remembers what worked,
|
|
4
|
+
what failed, what was decided, and which procedures are worth repeating.
|
|
5
|
+
|
|
6
|
+
OATS treats knowledge as a pluggable layer. The kernel does not choose a
|
|
7
|
+
memory format. The default integration, `oats-okf`, uses markdown OKF bundles
|
|
8
|
+
for soul knowledge and simple files for instance state.
|
|
9
|
+
|
|
10
|
+
> **Status and relationship to the turn record (2026-08-21).** This layer is
|
|
11
|
+
> current and stays. It is the *semantic* memory of an agent team — reviewed,
|
|
12
|
+
> de-indexicalized truths that travel with the soul — and is distinct from the
|
|
13
|
+
> *episodic* memory provided by the turn record (`packages/record`: every
|
|
14
|
+
> session captured verbatim, automatically). Today the harvester's input is
|
|
15
|
+
> `notes/*.md`, the working agent's own in-session notes; the planned upgrade
|
|
16
|
+
> (epic `aweb-abfz`) feeds the harvester from the captured record as well, so
|
|
17
|
+
> lessons reach the soul even when an agent wrote no notes and never ran
|
|
18
|
+
> harvest. The judgment machinery described here — the promotion bar, the
|
|
19
|
+
> capture/judge split, the routing between knowledge and skills — is unchanged
|
|
20
|
+
> by that upgrade; only the input channel widens.
|
|
21
|
+
|
|
22
|
+
## What the kernel does not own
|
|
23
|
+
|
|
24
|
+
The kernel is memory-agnostic. It provides lifecycle events:
|
|
25
|
+
|
|
26
|
+
- `soul-scaffold`
|
|
27
|
+
- `spawn`
|
|
28
|
+
- `retire`
|
|
29
|
+
|
|
30
|
+
A knowledge integration decides what to do with those events. If config
|
|
31
|
+
resolves `knowledge: none`, the kernel creates no `STATE.md`, no `notes/`, no
|
|
32
|
+
knowledge bundle, and no harvest flow.
|
|
33
|
+
|
|
34
|
+
The ideas behind any of this — what belongs in a soul vs an instance,
|
|
35
|
+
capture vs judgment, consolidation stages — are format-independent and live
|
|
36
|
+
in [knowledge theory](knowledge-theory.md).
|
|
37
|
+
|
|
38
|
+
## The default: oats-okf
|
|
39
|
+
|
|
40
|
+
With `knowledge: okf`, the integration creates two memory spaces.
|
|
41
|
+
|
|
42
|
+
| Space | Files | Purpose |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| Soul memory | `soul/knowledge/` | Long-term OKF bundle: lessons, decisions, playbooks, references, role-grown sections. |
|
|
45
|
+
| Instance memory | `STATE.md`, `log.md`, `notes/` | Current task state, dated history, and captured insights. |
|
|
46
|
+
|
|
47
|
+
The instance does not promote its own notes. It captures them, and after
|
|
48
|
+
committing with pending notes it runs `oats okf harvest` (its okf injection
|
|
49
|
+
carries this instruction), which spawns a **memory-harvest** agent. That
|
|
50
|
+
harvester judges the notes and updates the soul; the delivery matches the
|
|
51
|
+
soul's custody — a commit on the instance's branch for repo-resident souls,
|
|
52
|
+
a PR to the soul's home repo for workspace-mode souls, and **direct edits
|
|
53
|
+
with no commit** for local souls (their `local-agents/` home is
|
|
54
|
+
uncommitted by contract). Then it retires.
|
|
55
|
+
|
|
56
|
+
## Capture and judgment
|
|
57
|
+
|
|
58
|
+
OATS splits memory work into two roles.
|
|
59
|
+
|
|
60
|
+
**The working instance captures.** It keeps `STATE.md` current, appends
|
|
61
|
+
milestones to `log.md`, and writes every non-obvious insight to `notes/`.
|
|
62
|
+
It does not decide whether an insight is "important enough" for the soul.
|
|
63
|
+
Capture should be cheap and in-flow.
|
|
64
|
+
|
|
65
|
+
**The memory-harvest agent judges.** It reads pending notes and applies the
|
|
66
|
+
promotion bar:
|
|
67
|
+
|
|
68
|
+
> Promote only what is durable and would change what a future instance of
|
|
69
|
+
> this soul does.
|
|
70
|
+
|
|
71
|
+
For each note it chooses one outcome:
|
|
72
|
+
|
|
73
|
+
| Outcome | Meaning |
|
|
74
|
+
|---|---|
|
|
75
|
+
| Promote | Move it into the right soul knowledge section, or into a soul skill if it is procedural. |
|
|
76
|
+
| Merge | Fold it into an existing concept or skill. |
|
|
77
|
+
| Drop | Delete it and log why it failed the bar. |
|
|
78
|
+
|
|
79
|
+
This separation keeps working agents from overthinking memory, and gives
|
|
80
|
+
promotion the deliberate attention it deserves.
|
|
81
|
+
|
|
82
|
+
## Why instance memory and soul memory differ
|
|
83
|
+
|
|
84
|
+
Instance memory is indexical. It talks about this task, this branch, this
|
|
85
|
+
moment, this blocker. That is why it lives in `STATE.md`, `log.md`, and
|
|
86
|
+
`notes/`.
|
|
87
|
+
|
|
88
|
+
Soul memory must be incarnation-invariant. It should remain true for future
|
|
89
|
+
instances, future models, and future sessions. A future instance should be
|
|
90
|
+
able to read a concept and act differently because of it.
|
|
91
|
+
|
|
92
|
+
Harvest is the conversion between the two. Notes are where an instance tries
|
|
93
|
+
to phrase what it learned without "I, here, now". The harvester checks
|
|
94
|
+
whether that conversion succeeded.
|
|
95
|
+
|
|
96
|
+
## OKF concept types
|
|
97
|
+
|
|
98
|
+
OKF itself does not prescribe one vocabulary. OATS conventions use these
|
|
99
|
+
common types:
|
|
100
|
+
|
|
101
|
+
| Type | Usual home | Meaning |
|
|
102
|
+
|---|---|---|
|
|
103
|
+
| `Instance State` | `STATE.md` | Current working state. Rewritten, not superseded. |
|
|
104
|
+
| `Finding` | `notes/` | A captured observation whose durability is unproven. |
|
|
105
|
+
| `Lesson` | Soul knowledge | A durable behavior-changing conclusion. |
|
|
106
|
+
| `Decision` | `notes/` or soul knowledge | A decision and its rationale. Task-local decisions stay in `STATE.md` or `log.md`. |
|
|
107
|
+
| `Playbook` | Soul knowledge or soul skills | Repeatable steps. Procedure-shaped notes usually become skills. |
|
|
108
|
+
| `Reference` | Soul knowledge | External truth or stable internal reference. |
|
|
109
|
+
|
|
110
|
+
Souls start with core knowledge sections:
|
|
111
|
+
|
|
112
|
+
- `lessons/`
|
|
113
|
+
- `decisions/`
|
|
114
|
+
- `playbooks/`
|
|
115
|
+
- `references/`
|
|
116
|
+
|
|
117
|
+
Souls can grow role-specific sections such as `architecture/`, `codebase/`, or
|
|
118
|
+
`roadmap/`. Add a section when future instances of that soul need to navigate
|
|
119
|
+
that kind of knowledge.
|
|
120
|
+
|
|
121
|
+
## What a working instance should do
|
|
122
|
+
|
|
123
|
+
As you work:
|
|
124
|
+
|
|
125
|
+
1. Keep `STATE.md` accurate. A fresh session should be able to resume from
|
|
126
|
+
its `# Next` section.
|
|
127
|
+
2. Append dated milestones and decisions to `log.md`.
|
|
128
|
+
3. Write non-obvious insights to `notes/` as one concept per file.
|
|
129
|
+
4. Before every commit, bring memory up to date.
|
|
130
|
+
5. Commit, then run `oats okf harvest` to send your notes to the soul.
|
|
131
|
+
|
|
132
|
+
Do not hold back a note because you are unsure it is soul-grade. Capture
|
|
133
|
+
first. The harvester judges.
|
|
134
|
+
|
|
135
|
+
## Without a knowledge integration
|
|
136
|
+
|
|
137
|
+
`knowledge: none` is valid. The agent gets no OATS memory files, no memory
|
|
138
|
+
briefing, no harvest agent, and no OKF skills. It may still use whatever
|
|
139
|
+
memory conventions the repo or harness already provides.
|
package/docs/layers.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# The five layers of agent specialization
|
|
2
|
+
|
|
3
|
+
A capable model in a fresh session is not a specialist. A specialist has
|
|
4
|
+
identity, habits, memory, teammates, and work to track. OATS names those needs
|
|
5
|
+
as five layers.
|
|
6
|
+
|
|
7
|
+
Two layers are the OATS pattern itself: **soul** and **instances**. The kernel
|
|
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
|
+
|
|
13
|
+
## The layers at a glance
|
|
14
|
+
|
|
15
|
+
| Layer | Question it answers | Owner |
|
|
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 |
|
|
22
|
+
|
|
23
|
+
## 1. Soul — durable expert identity
|
|
24
|
+
|
|
25
|
+
A soul is what an agent *is* when no session is running. It contains the
|
|
26
|
+
agent's operating doc (`AGENTS.md`), its own skills, and any long-term
|
|
27
|
+
knowledge its knowledge layer provides.
|
|
28
|
+
|
|
29
|
+
A soul is committed and reviewed like code. It has no terminal, no network
|
|
30
|
+
identity, and no current task. It is the expert template that compounds over
|
|
31
|
+
many incarnations.
|
|
32
|
+
|
|
33
|
+
The kernel owns this layer. The shape of a soul is the pattern itself:
|
|
34
|
+
`soul.yaml`, canonical files, symlinks, and directory layout. Deployment
|
|
35
|
+
capabilities compose into instances and never redefine or mutate the soul.
|
|
36
|
+
|
|
37
|
+
## 2. Knowledge — learning that survives sessions
|
|
38
|
+
|
|
39
|
+
Specialization requires memory. The knowledge layer decides where memory
|
|
40
|
+
lives, what kinds exist, and how learning moves from an instance into the
|
|
41
|
+
soul.
|
|
42
|
+
|
|
43
|
+
The kernel is memory-agnostic. It only provides lifecycle events such as
|
|
44
|
+
`soul-scaffold`, `spawn`, and `retire`. A knowledge integration
|
|
45
|
+
uses those events to create memory files, teach the protocol, and run
|
|
46
|
+
promotion.
|
|
47
|
+
|
|
48
|
+
The default `oats-okf` integration creates an OKF bundle in the soul and
|
|
49
|
+
`STATE.md`, `log.md`, and `notes/` in instances. Instances capture what they
|
|
50
|
+
learn, and after committing with pending notes run `oats okf harvest`, which
|
|
51
|
+
spawns a memory-harvest agent that judges notes and promotes
|
|
52
|
+
what belongs in the soul.
|
|
53
|
+
|
|
54
|
+
If config resolves `knowledge: none`, none of this exists. The agent works
|
|
55
|
+
with whatever memory its harness or repo already provides.
|
|
56
|
+
|
|
57
|
+
See [Knowledge](knowledge.md).
|
|
58
|
+
|
|
59
|
+
## 3. Instances — the soul doing work
|
|
60
|
+
|
|
61
|
+
An instance is one running incarnation of a soul. It has a home directory, a
|
|
62
|
+
work tree, a task briefing, metadata, and possibly episodic memory.
|
|
63
|
+
|
|
64
|
+
Instances are disposable by design. Sessions crash, context windows fill, and
|
|
65
|
+
models change. The soul survives. With a knowledge integration, what matters
|
|
66
|
+
feeds back into the soul as the instance works.
|
|
67
|
+
|
|
68
|
+
The kernel owns this layer: spawn, exact skill/instruction composition,
|
|
69
|
+
retire, work modes, tmux windows, metadata, and lifecycle hook points.
|
|
70
|
+
(There is no resume command; a retired instance is gone — its session
|
|
71
|
+
transcript survives in the turn record if capture is running.)
|
|
72
|
+
|
|
73
|
+
See [Souls and instances](souls-and-instances.md).
|
|
74
|
+
|
|
75
|
+
## 4. Messaging — reachable team identities
|
|
76
|
+
|
|
77
|
+
Team agents need to reach humans and each other. The messaging layer maps an
|
|
78
|
+
instance name to a communication identity, then cleans that identity up when
|
|
79
|
+
the instance retires.
|
|
80
|
+
|
|
81
|
+
The default integration is `oats-aweb`. It gives each instance an aweb identity
|
|
82
|
+
and teaches agents to use `aw mail` and `aw chat`.
|
|
83
|
+
|
|
84
|
+
Messaging is deliberately narrow. It is about communication only. Task
|
|
85
|
+
coordination belongs to layer 5.
|
|
86
|
+
|
|
87
|
+
## 5. Tasks — shared work state
|
|
88
|
+
|
|
89
|
+
Work needs a queue and status that outlive any one instance: planned, in
|
|
90
|
+
flight, blocked, done. OATS does not choose the tracker. It only requires that
|
|
91
|
+
agents know where the shared work state lives and how to use it.
|
|
92
|
+
|
|
93
|
+
There is no shipped default task integration. One deployment can bind Jira,
|
|
94
|
+
another Linear, another GitHub Issues. The LFX-style Jira integration is just
|
|
95
|
+
skills plus an injection that points agents at those skills.
|
|
96
|
+
|
|
97
|
+
## Why the split matters
|
|
98
|
+
|
|
99
|
+
Souls and instances are the stable core. Moving them out would leave nothing
|
|
100
|
+
to specialize.
|
|
101
|
+
|
|
102
|
+
Knowledge, messaging, and tasks vary by team. They should be easy to swap.
|
|
103
|
+
One workspace can run OKF + aweb + Jira. Another can run a team wiki + Slack
|
|
104
|
+
+ Linear. A repo can disable messaging with `messaging: none`. The soul stays
|
|
105
|
+
the same kind of object. Only its layer bindings change.
|
|
106
|
+
|
|
107
|
+
Layer exclusivity prevents two task systems or knowledge protocols from
|
|
108
|
+
competing inside one soul context. Capability targeting still allows another
|
|
109
|
+
soul to select a different provider. See [Integrations](integrations.md) and
|
|
110
|
+
[Capability packages](capabilities.md).
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Migrating from OAS to OATS
|
|
2
|
+
|
|
3
|
+
Status: **the migration path exists in the kernel** — `oats migrate
|
|
4
|
+
--from-oas`, one transactional conversion per scope (plan steps 1–3 below,
|
|
5
|
+
all landed 2026-08-21). What remains is distribution: end users get the
|
|
6
|
+
command with the v0.22.0 release (steps 4–6). This document keeps the facts
|
|
7
|
+
in one place; the work is tracked as epic `aweb-abfy` in this team's aw
|
|
8
|
+
tasks. Audited 2026-08-21 against a live OAS deployment
|
|
9
|
+
(`@oas-framework/oas@0.20.0-aweb.1`).
|
|
10
|
+
|
|
11
|
+
OATS was published as **OAS** (`@oas-framework/oas`, `@oas-framework/pi`)
|
|
12
|
+
until the 2026-08-13 rename (commit `fa1e646`), which was a deliberate
|
|
13
|
+
clean break: no compatibility shims, and no code in this repo recognizes
|
|
14
|
+
`oas-*` names.
|
|
15
|
+
|
|
16
|
+
## Do not migrate by hand yet
|
|
17
|
+
|
|
18
|
+
The dangerous property of the original state was that it failed **quietly**:
|
|
19
|
+
|
|
20
|
+
- On a scope with `oas-config.yaml`/`oas-lock.json`, `oats status` works
|
|
21
|
+
(the `agents/` layout is unchanged) — everything looks healthy.
|
|
22
|
+
- But `oats doctor` finds no config, all layers are unresolved, and a spawn
|
|
23
|
+
produces instances **without the knowledge (`oas.okf`) and messaging
|
|
24
|
+
(`oas.aweb`) injections**. The compounding-memory and team-comms value
|
|
25
|
+
disappears with no error.
|
|
26
|
+
- `oats migrate --official --dry-run` on such a scope reported "nothing to
|
|
27
|
+
migrate" and exited 0 — false success.
|
|
28
|
+
|
|
29
|
+
Since plan step 1 landed (below), the silence is closed: `oats doctor` names
|
|
30
|
+
an un-migrated OAS scope with the remedy, and every `oats migrate` form —
|
|
31
|
+
plain or guided, dry run or apply — exits nonzero when `oas-config.yaml` /
|
|
32
|
+
`oas-lock.json` are visible from the scope (detection is by name only; the
|
|
33
|
+
kernel never parses OAS files).
|
|
34
|
+
|
|
35
|
+
## Migrating: `oats migrate --from-oas`
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
oats migrate --from-oas --dry-run --dir <scope> # full per-scope plan, touches nothing
|
|
39
|
+
oats migrate --from-oas --dir <scope> # convert this scope
|
|
40
|
+
oats migrate --from-oas --recursive --dir <root> # every visible OAS scope
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
One transaction per scope, two phases under one journal:
|
|
44
|
+
|
|
45
|
+
1. **Rename phase** — `oas-config.yaml` → `oats-config.yaml` (line
|
|
46
|
+
transform: the `oas:` defaults key becomes `oats:` and capability ids
|
|
47
|
+
with catalog renames become their successors; comments and every other
|
|
48
|
+
byte survive), `oas-lock.json` → `oats-lock.json` verbatim, `oas.json` →
|
|
49
|
+
`oats.json` inside each installed capability dir, and
|
|
50
|
+
`.oas-scaffold-owners.json` → `.oats-scaffold-owners.json` in `agents/`
|
|
51
|
+
and `local-agents/` souls with owner ids mapped to their successors.
|
|
52
|
+
2. **Chained guided conversion** — the existing v1→v2 official migration
|
|
53
|
+
runs on the renamed lock; the catalog's renaming aliases map each
|
|
54
|
+
`oas.*` entry onto the `oats.*` package that replaces it, re-acquiring
|
|
55
|
+
the artifacts (stale v1 integrity is resolved by re-acquisition, never
|
|
56
|
+
recomputed) and cleaning the superseded `oas`-named artifact dirs.
|
|
57
|
+
|
|
58
|
+
Any failure in either phase restores the scope's original OAS-named bytes.
|
|
59
|
+
A second run finds nothing and exits 0. Executable trust is re-earned after
|
|
60
|
+
conversion (`oats trust` commands are printed), and comments inside your
|
|
61
|
+
config that mention `oas` paths are left untouched — comments are yours.
|
|
62
|
+
|
|
63
|
+
## The four breaks
|
|
64
|
+
|
|
65
|
+
1. **File names.** The kernel reads only `oats-config.yaml`
|
|
66
|
+
(`lib/core.mjs:326`) and `oats-lock.json` (`lib/core.mjs:643`). OAS
|
|
67
|
+
scopes have `oas-config.yaml`, `oas-lock.json`, `oas.json` inside each
|
|
68
|
+
installed capability dir, and `.oas-scaffold-owners.json` in souls.
|
|
69
|
+
2. **The config key.** The schema (`docs/oats-config.schema.json`,
|
|
70
|
+
`additionalProperties: false`) accepts an `oats:` defaults block and
|
|
71
|
+
rejects the `oas:` block an OAS config carries — renaming the file is
|
|
72
|
+
not enough.
|
|
73
|
+
3. **Capability ids.** `oas.okf` / `oas.aweb` appear in the config, the
|
|
74
|
+
lock, and the `.agents/capabilities/installed/<id>/` directory names.
|
|
75
|
+
4. **No catalog aliases.** `package-catalog.json` maps only `oats.*` ids;
|
|
76
|
+
a hand-renamed lock naming `marketplace:oas.okf` resolves to
|
|
77
|
+
`available: false` and the guided migration **holds the whole scope**
|
|
78
|
+
(`lib/core.mjs:3251-3262`, `:1416`).
|
|
79
|
+
|
|
80
|
+
## Why an OAS user cannot even find OATS
|
|
81
|
+
|
|
82
|
+
- `@awebai/oats` and `@awebai/oats-pi` are **not yet published**. The
|
|
83
|
+
v0.22.0 release notes exist and the three manifests are aligned; what
|
|
84
|
+
remains is the tag and the publish (`.github/workflows/release.yml`, or
|
|
85
|
+
the runnerless lane in `scripts/release-lane.mjs`).
|
|
86
|
+
- `@oas-framework/oas` is still live on npm (0.21.2 as of 2026-09-03) and
|
|
87
|
+
**not deprecated**, so the old CLI's `oas update` (which checks that
|
|
88
|
+
package) never learns OATS exists.
|
|
89
|
+
- The old OAS desktop probes for `@oas-framework/oas`; the new desktop
|
|
90
|
+
requires `@awebai/oats >=0.22.0 <0.23.0` — old app and new CLI are
|
|
91
|
+
mutually invisible, so desktop must ship in the same release.
|
|
92
|
+
|
|
93
|
+
## The plan (epic `aweb-abfy`)
|
|
94
|
+
|
|
95
|
+
1. **Done.** `oats migrate` / `oats doctor` detect an OAS scope and fail
|
|
96
|
+
**loud** with the exact remedy (never exit 0 on "nothing to migrate" when
|
|
97
|
+
`oas-*` siblings exist). `detectOasScopes` in `lib/core.mjs`,
|
|
98
|
+
`discoverOasScopes` in `lib/packages.mjs`, wired in `bin/oats.mjs`;
|
|
99
|
+
tests in `test/oas-scope-detection.test.mjs`.
|
|
100
|
+
2. **Done.** Catalog aliases `oas.*` → `oats.*` so legacy locks map instead
|
|
101
|
+
of holding — as *renaming* aliases (`{ "package": "oats.okf",
|
|
102
|
+
"capability": "oats.okf" }`), because the replacement packages export the
|
|
103
|
+
successor ids, never the legacy ones. All seven 0.20 ids are mapped in
|
|
104
|
+
`package-catalog.json`.
|
|
105
|
+
3. **Done.** `oats migrate --from-oas`: one transactional command covering
|
|
106
|
+
all four breaks (section above), fixture built from the real deployment
|
|
107
|
+
shape, idempotent, byte-identical rollback on failure, with a migrated
|
|
108
|
+
scope reaching green `oats doctor` and spawns composing the knowledge and
|
|
109
|
+
messaging injections again (`test/from-oas-migration.test.mjs`).
|
|
110
|
+
4. v0.22.0 release: notes and version alignment are **done**; remaining are
|
|
111
|
+
the tag, npm publish of `@awebai/oats` + `@awebai/oats-pi`, and the
|
|
112
|
+
desktop GitHub Release.
|
|
113
|
+
5. `npm deprecate` the `@oas-framework/*` packages with a pointer here.
|
|
114
|
+
6. Close the `oats-okf` / `oats-aweb` publication gates so migrated scopes
|
|
115
|
+
can restore their capabilities under the new ids.
|
|
116
|
+
|
|
117
|
+
Until 4–6 are done, OAS users (this includes real daily users) should stay
|
|
118
|
+
on `@oas-framework/oas` — it keeps working and loses nothing by
|
|
119
|
+
waiting. The conversion command exists, but until the v0.22.0 release it is
|
|
120
|
+
only reachable from a repo checkout, and until the satellite publication
|
|
121
|
+
gates close the catalog's package refs are not a supported acquisition
|
|
122
|
+
source for migrated scopes.
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://oats.dev/schemas/oats-config.schema.json",
|
|
4
|
+
"title": "OATS scoped configuration",
|
|
5
|
+
"$defs": {
|
|
6
|
+
"settings": { "type": "object", "additionalProperties": true },
|
|
7
|
+
"binding": {
|
|
8
|
+
"oneOf": [
|
|
9
|
+
{ "type": "boolean" },
|
|
10
|
+
{
|
|
11
|
+
"type": "object",
|
|
12
|
+
"properties": {
|
|
13
|
+
"enabled": { "type": "boolean" },
|
|
14
|
+
"settings": { "$ref": "#/$defs/settings" }
|
|
15
|
+
},
|
|
16
|
+
"additionalProperties": false
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
"injection-override": { "type": "string", "description": "Override an instruction injection: a config-relative path, none, or default. Convention: .agents/injections/…" },
|
|
21
|
+
"capabilityTargets": {
|
|
22
|
+
"type": "object",
|
|
23
|
+
"properties": {
|
|
24
|
+
"from": { "type": "string", "description": "Enforced provenance: installed | owned | path:<dir>." },
|
|
25
|
+
"global": { "$ref": "#/$defs/binding" },
|
|
26
|
+
"agent-types": {
|
|
27
|
+
"oneOf": [
|
|
28
|
+
{ "type": "array", "items": { "type": "string" }, "uniqueItems": true },
|
|
29
|
+
{ "type": "object", "additionalProperties": { "$ref": "#/$defs/binding" } }
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
"souls": { "type": "object", "additionalProperties": { "$ref": "#/$defs/binding" } },
|
|
33
|
+
"settings": { "$ref": "#/$defs/settings" },
|
|
34
|
+
"injection-override": { "$ref": "#/$defs/injection-override" }
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"layerEntry": {
|
|
38
|
+
"oneOf": [
|
|
39
|
+
{ "const": "none" },
|
|
40
|
+
{
|
|
41
|
+
"allOf": [{ "$ref": "#/$defs/capabilityTargets" }],
|
|
42
|
+
"type": "object",
|
|
43
|
+
"required": ["capability"],
|
|
44
|
+
"properties": {
|
|
45
|
+
"capability": { "type": "string" },
|
|
46
|
+
"from": true, "global": true, "agent-types": true, "souls": true, "settings": true, "injection-override": true
|
|
47
|
+
},
|
|
48
|
+
"additionalProperties": false
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
},
|
|
52
|
+
"additiveEntry": {
|
|
53
|
+
"allOf": [{ "$ref": "#/$defs/capabilityTargets" }],
|
|
54
|
+
"type": "object",
|
|
55
|
+
"properties": {
|
|
56
|
+
"from": true, "global": true, "agent-types": true, "souls": true, "settings": true, "injection-override": true
|
|
57
|
+
},
|
|
58
|
+
"additionalProperties": false
|
|
59
|
+
},
|
|
60
|
+
"workMode": {
|
|
61
|
+
"oneOf": [
|
|
62
|
+
{ "type": "null" },
|
|
63
|
+
{
|
|
64
|
+
"type": "object",
|
|
65
|
+
"properties": {
|
|
66
|
+
"setup": { "type": "string", "description": "Env-bootstrap command run inside each new worktree after creation (path relative to this config's directory)." }
|
|
67
|
+
},
|
|
68
|
+
"additionalProperties": false
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"type": "object",
|
|
74
|
+
"properties": {
|
|
75
|
+
"name": { "type": "string" },
|
|
76
|
+
"team": {
|
|
77
|
+
"type": "object",
|
|
78
|
+
"description": "The deployment/team boundary. Closest scope declaring team: wins; used for identity, cross-repo agent discovery (oats status --team), and messaging providers.",
|
|
79
|
+
"properties": {
|
|
80
|
+
"name": { "type": "string" },
|
|
81
|
+
"id": { "type": "string", "description": "Explicit provider team id (e.g. aweb <name>:<namespace>)." }
|
|
82
|
+
},
|
|
83
|
+
"required": ["name"],
|
|
84
|
+
"additionalProperties": false
|
|
85
|
+
},
|
|
86
|
+
"agent-types": {
|
|
87
|
+
"type": "object",
|
|
88
|
+
"description": "Agent families declared by name; membership is `type: <name>` in each soul.yaml.",
|
|
89
|
+
"additionalProperties": {
|
|
90
|
+
"oneOf": [
|
|
91
|
+
{ "type": "null" },
|
|
92
|
+
{
|
|
93
|
+
"type": "object",
|
|
94
|
+
"properties": { "description": { "type": "string" } },
|
|
95
|
+
"additionalProperties": false
|
|
96
|
+
}
|
|
97
|
+
]
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
"capabilities": {
|
|
101
|
+
"type": "object",
|
|
102
|
+
"properties": {
|
|
103
|
+
"layers": {
|
|
104
|
+
"type": "object",
|
|
105
|
+
"description": "The three exclusive fundamental slots: a capability entry or an explicit none.",
|
|
106
|
+
"properties": {
|
|
107
|
+
"knowledge": { "$ref": "#/$defs/layerEntry" },
|
|
108
|
+
"messaging": { "$ref": "#/$defs/layerEntry" },
|
|
109
|
+
"tasks": { "$ref": "#/$defs/layerEntry" }
|
|
110
|
+
},
|
|
111
|
+
"additionalProperties": false
|
|
112
|
+
},
|
|
113
|
+
"additive": {
|
|
114
|
+
"type": "object",
|
|
115
|
+
"propertyNames": { "pattern": "^(?:@?[a-z0-9][a-z0-9._-]*[./])[a-z0-9][a-z0-9._/-]*$" },
|
|
116
|
+
"additionalProperties": { "$ref": "#/$defs/additiveEntry" }
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
"additionalProperties": false
|
|
120
|
+
},
|
|
121
|
+
"skill-overrides": { "type": "object", "additionalProperties": { "type": "string" } },
|
|
122
|
+
"templates": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Named oats init templates: local config paths or git URLs whose main branch carries an oats-config.yaml." },
|
|
123
|
+
"agents-md-injection": { "oneOf": [{ "type": "string" }, { "type": "object", "additionalProperties": { "type": "string" } }], "description": "Extra unconditional instruction blocks (adds content; does not override packaged defaults)." },
|
|
124
|
+
"oats": {
|
|
125
|
+
"type": "object",
|
|
126
|
+
"properties": { "injection-override": { "$ref": "#/$defs/injection-override" } },
|
|
127
|
+
"additionalProperties": false
|
|
128
|
+
},
|
|
129
|
+
"work-modes": {
|
|
130
|
+
"type": "object",
|
|
131
|
+
"properties": {
|
|
132
|
+
"worktree": { "$ref": "#/$defs/workMode" },
|
|
133
|
+
"checkout": { "$ref": "#/$defs/workMode" },
|
|
134
|
+
"attached": { "$ref": "#/$defs/workMode" }
|
|
135
|
+
},
|
|
136
|
+
"additionalProperties": false
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
"additionalProperties": false
|
|
140
|
+
}
|