@awebai/oats 0.27.2 → 0.29.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/bin/oats.mjs +445 -96
- package/capabilities/oats-okf/bin/oats-okf.mjs +55 -30
- package/capabilities/oats-okf/injects/okf.md +36 -28
- package/capabilities/oats-okf/lib/binding-wire.mjs +4 -1
- package/capabilities/oats-okf/lib/config.mjs +6 -1
- package/capabilities/oats-okf/lib/consult.mjs +496 -0
- package/capabilities/oats-okf/lib/harvest-status.mjs +88 -0
- package/capabilities/oats-okf/lib/harvest-switch.mjs +81 -0
- package/capabilities/oats-okf/lib/inspection.mjs +11 -3
- package/capabilities/oats-okf/lib/io.mjs +9 -2
- package/capabilities/oats-okf/lib/okf-validate.mjs +123 -0
- package/capabilities/oats-okf/lib/sources.mjs +42 -55
- package/capabilities/oats-okf/lib/stores.mjs +19 -11
- package/capabilities/oats-okf/lib/worker.mjs +90 -8
- package/capabilities/oats-okf/oats.json +24 -9
- package/capabilities/oats-okf/skills/okf-consultation/SKILL.md +144 -0
- package/capabilities/oats-okf/skills/okf-consultation/references/consult.md +86 -0
- package/capabilities/oats-okf/skills/okf-instance-knowledge/SKILL.md +104 -0
- package/capabilities/oats-okf-harvest/bin/okf-harvest.mjs +140 -0
- package/capabilities/oats-okf-harvest/injects/harvester.md +12 -0
- package/capabilities/oats-okf-harvest/oats.json +26 -0
- package/capabilities/oats-okf-harvest/skills/knowledge-harvest/SKILL.md +168 -0
- package/capabilities/oats-okf-harvest/skills/knowledge-theory/SKILL.md +192 -0
- package/capabilities/{oats-okf/skills/okf → oats-okf-harvest/skills/okf-authoring}/SKILL.md +15 -22
- package/capabilities/oats-okf-maintenance/bin/okf-maintenance.mjs +149 -0
- package/capabilities/oats-okf-maintenance/injects/maintainer.md +12 -0
- package/capabilities/oats-okf-maintenance/lib/provenance.mjs +45 -0
- package/capabilities/oats-okf-maintenance/oats.json +21 -0
- package/capabilities/oats-okf-maintenance/skills/knowledge-review/SKILL.md +144 -0
- package/capabilities/oats-okf-maintenance/skills/knowledge-theory/SKILL.md +192 -0
- package/capabilities/oats-okf-maintenance/skills/okf-authoring/SKILL.md +151 -0
- package/capabilities/oats-okf-maintenance/skills/okf-authoring/scripts/okf-validate.mjs +123 -0
- package/capabilities/oats-okf-maintenance/skills/okf-trigger-setup/SKILL.md +146 -0
- package/capabilities/oats-review/injects/review.md +3 -2
- package/capabilities/oats-review/oats.json +3 -4
- package/docs/capabilities.md +41 -9
- package/docs/capability-manifest.schema.json +0 -7
- package/docs/design/2026-09-24-phase-d-plan.md +11 -0
- package/docs/design/2026-09-26-desktop-design-brief-architecture.md +241 -0
- package/docs/design/2026-09-26-okf-knowledge-operations.md +389 -0
- package/docs/desktop-cli-api.md +342 -10
- package/docs/implementation.md +1 -1
- package/docs/knowledge-capability-authoring.md +8 -2
- package/docs/knowledge-reference/package-craft.md +8 -5
- package/docs/knowledge.md +101 -0
- package/docs/oats-local.schema.json +33 -2
- package/docs/oats-package.schema.json +39 -0
- package/docs/official-catalog.md +7 -4
- package/docs/packages.md +76 -6
- package/docs/release-lane.md +1 -1
- package/docs/release-notes/v0.28.0.md +144 -0
- package/docs/release-notes/v0.29.0.md +240 -0
- package/docs/schedules.md +230 -4
- package/docs/souls-and-instances.md +11 -9
- package/docs/workspaces.md +18 -3
- package/lib/automations.mjs +369 -0
- package/lib/core.mjs +87 -158
- package/lib/instance-inspect.mjs +16 -8
- package/lib/instance-resolution.mjs +90 -197
- package/lib/materialize.mjs +18 -7
- package/lib/operator-dispatch.mjs +1 -2
- package/lib/packages.mjs +107 -6
- package/lib/remote.mjs +21 -1
- package/lib/resolve.mjs +71 -9
- package/lib/schedule.mjs +228 -45
- package/lib/triggers.mjs +678 -0
- package/lib/workspace.mjs +81 -4
- package/package-catalog.json +6 -4
- package/package.json +1 -1
- package/capabilities/oats-okf/agents/memory-harvest/AGENTS.md +0 -21
- package/capabilities/oats-okf/agents/memory-harvest/soul.yaml +0 -5
- package/capabilities/oats-okf/skills/memory-harvest/SKILL.md +0 -285
- package/capabilities/oats-review/agents/reviewer/AGENTS.md +0 -53
- package/capabilities/oats-review/agents/reviewer/soul.yaml +0 -6
- /package/capabilities/{oats-okf/skills/okf → oats-okf-harvest/skills/okf-authoring}/scripts/okf-validate.mjs +0 -0
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# OATS for designers: the architecture, and the why, behind the Desktop
|
|
2
|
+
|
|
3
|
+
**Audience:** a product designer redesigning the OATS Desktop. You don't need to read code. After this you should be able to answer the questions a user will ask the Desktop: *what is OATS, what is my setup, where does each thing come from, and why is it that way?*
|
|
4
|
+
|
|
5
|
+
**Status:** the model described here is what ships in OATS 0.27.x. Things that are planned but not shipped are marked **(planned)**.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. What OATS is, in one paragraph
|
|
10
|
+
|
|
11
|
+
OATS lets a person or a company run a **team of AI agents** (Claude, Codex or Pi sessions) that each have a durable role, their own tools and knowledge, and a place to work. The unit you design and keep is a **soul** (a role, like "release manager"). The unit that actually runs is an **instance** (a working session of that soul, with its own folder and task). Everything a soul needs (tools, instructions, knowledge, messaging) comes from **Git repositories** the organisation already has, gathered into one **workspace**. OATS never "installs" anything globally: when an instance starts, OATS copies exactly what that soul needs into the instance's own folder, and records where each piece came from.
|
|
12
|
+
|
|
13
|
+
**The design promise to users:** *you can always see what an agent is made of, where every part came from, and why it's there.*
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 2. The five things a user must be able to picture
|
|
18
|
+
|
|
19
|
+
Think of these as the nouns of the product. The Desktop's job is to make each one visible and to show how they connect.
|
|
20
|
+
|
|
21
|
+
| Concept | Plain meaning | Analogy |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| **Workspace** | The organisation's agent setup: which repositories take part, which shared tools and versions everyone uses, and the teams. One per organisation. | The company's org chart + approved-tools list. |
|
|
24
|
+
| **Repository (member)** | A Git repo that has **joined** the workspace. It can contribute **souls** and **capabilities**. | A department that brings its people and its tools. |
|
|
25
|
+
| **Soul** | A durable agent role: instructions, skills, and which capabilities it uses. Lives as a folder in a member repo. | A job description. |
|
|
26
|
+
| **Instance** | A running (or stopped) incarnation of a soul: its own folder, task, work branch, and session. You spawn, attach to and retire instances. | A person currently doing that job. |
|
|
27
|
+
| **Capability** | A reusable bundle of skills, instructions, commands and hooks (e.g. "house style", "deploy tooling", "knowledge", "messaging"). | A tool or training the person gets. |
|
|
28
|
+
|
|
29
|
+
Plus two supporting nouns:
|
|
30
|
+
|
|
31
|
+
- **Package**: a *versioned* bundle of capabilities published by a repo (e.g. `oats.okf v2.1.5`). The workspace pins its version.
|
|
32
|
+
- **Deployment**: one machine's realisation of the workspace. It's a folder on the user's computer that holds the per-machine settings, the lock, the instance folders and any repo clones they work in.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 3. How a workspace is set up
|
|
37
|
+
|
|
38
|
+
### 3.1 Files, and who owns them
|
|
39
|
+
|
|
40
|
+
A workspace is **declared in Git**, not configured in an app. The Desktop *reads* these and helps edit them; it doesn't hold hidden state.
|
|
41
|
+
|
|
42
|
+
| File | Lives in | Shared? | Says |
|
|
43
|
+
|---|---|---|---|
|
|
44
|
+
| `oats-workspace.yaml` | the **host** repo (any member; often a dedicated `agents` repo) | yes, via Git | the members, the pinned packages, the teams, the defaults, the knowledge stores |
|
|
45
|
+
| `oats-membership.yaml` | **every** member repo | yes, via Git | "I belong to workspace X" (+ an optional default team) |
|
|
46
|
+
| `souls/<name>/soul.yaml` | a member repo | yes, via Git | this role's work mode, team(s), capabilities, and where each comes from |
|
|
47
|
+
| `capabilities/<name>/oats.json` | a member repo | yes, via Git | the capability's manifest (what it provides, optional core-capability "layer", optional repo-owned flag) |
|
|
48
|
+
| `oats-local.yaml` | the user's **deployment folder** | **no, per machine** | which workspace this machine runs, where clones live, host-only settings (paths, keys), souls disabled here |
|
|
49
|
+
| `oats-lock.json` | the deployment folder | per machine (but identical wherever the same workspace commit was synced) | the exact commit + content fingerprint of every pinned package |
|
|
50
|
+
|
|
51
|
+
**Design implication:** show clearly **what is shared** (Git, the same for everyone in the org) versus **what is this machine** (local settings, clones, running instances). Users get confused when the two blur.
|
|
52
|
+
|
|
53
|
+
### 3.2 Membership is a two-way handshake (and it IS the trust)
|
|
54
|
+
|
|
55
|
+
A repo is a member only when **both**:
|
|
56
|
+
|
|
57
|
+
1. the workspace lists it, **and**
|
|
58
|
+
2. the repo's `oats-membership.yaml` points back to that workspace.
|
|
59
|
+
|
|
60
|
+
One side alone isn't enough (a copied file in a fork doesn't count). OATS checks both sides over Git, with the user's own access.
|
|
61
|
+
|
|
62
|
+
**Why:** whoever can push to a member repo decides what its souls and capabilities are, the same trust model as the code itself. There's no separate "approve this tool" step for members.
|
|
63
|
+
|
|
64
|
+
Each member shows one of these states, and the Desktop must surface them plainly:
|
|
65
|
+
|
|
66
|
+
| State | What the user should understand |
|
|
67
|
+
|---|---|
|
|
68
|
+
| **confirmed** | It's in. Its souls and capabilities are available. |
|
|
69
|
+
| **not listed** | The repo points at the workspace, but the workspace doesn't list it. |
|
|
70
|
+
| **no backlink** | The workspace lists it, but the repo hasn't joined (no membership file). |
|
|
71
|
+
| **points elsewhere** | The repo says it belongs to a different workspace. |
|
|
72
|
+
| **can't read** | This user can't read the repo (access, network). Nothing from it is available *for this user*. |
|
|
73
|
+
|
|
74
|
+
An unconfirmed member contributes **nothing**: its souls and capabilities are invisible. This is often the answer to "why can't I see soul X?"
|
|
75
|
+
|
|
76
|
+
### 3.3 Packages: the only versioned things
|
|
77
|
+
|
|
78
|
+
- **Member** capabilities and souls are always the repo's **latest** default-branch state. They're not versioned.
|
|
79
|
+
- **Packages** are **pinned**: the workspace lists `package: version`; the lock records the exact commit + fingerprint.
|
|
80
|
+
- **Declaring a package is the trust decision.** There's no second approval.
|
|
81
|
+
- Official packages (`oats.framework`, `oats.okf`, `oats.aweb`, `oats.jira`, `oats.linear`, `oats.authoring`, `oats.dev`) come from a reviewed **official catalog**. Others are referenced by Git URL + tag.
|
|
82
|
+
|
|
83
|
+
**Why two tiers:** your own repos move fast and you trust them (latest state), while third-party or shared tooling must not change under you (pinned + fingerprinted). A repo can be **both** a member *and* publish a package. They never merge: "from this repo" means its latest `capabilities/`; "from the package" means the pinned version.
|
|
84
|
+
|
|
85
|
+
**Design implication:** every capability shown should say **where it comes from**: a member repo (latest), a package (with its pinned version), or "this soul's own repo". This is the single most important fact for a user to understand their setup.
|
|
86
|
+
|
|
87
|
+
### 3.4 Teams: labels that organise, never walls
|
|
88
|
+
|
|
89
|
+
- The workspace declares team labels once (e.g. `global`, `engineering`, `marketing`).
|
|
90
|
+
- A soul has one team or several (the first is its **primary**). A repo can set a default team for its souls.
|
|
91
|
+
- A team label can **add default capabilities** for its souls (e.g. every `engineering` soul gets the release tooling).
|
|
92
|
+
- A team label **never** restricts, gates or changes trust. It's organisation, plus optional defaults.
|
|
93
|
+
- For **messaging**, each label a soul carries is a team it's *eligible* to join. By default an instance is only in its person's **personal team**, and joining others is an explicit choice, at spawn or later.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## 4. How a soul gets its capabilities (composition)
|
|
98
|
+
|
|
99
|
+
When you spawn an instance, OATS assembles the soul's capability list from layers, later layers winning:
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
workspace defaults → team defaults (per label) → the soul's own list
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
- A soul can **add** capabilities, **turn off** a default (`off`), or empty a core-capability slot (`none`).
|
|
106
|
+
- If two of a soul's teams disagree about a capability, that's a **team conflict**, and the soul can't be spawned until the workspace fixes it. The Desktop shows the two labels.
|
|
107
|
+
- The result is an exact, fingerprinted **resolution**. Preview shows it before anything is created; if something changed between preview and spawn, OATS refuses and asks you to preview again.
|
|
108
|
+
|
|
109
|
+
**Design implication:** for any soul, the Desktop can show a **composition view**: each capability, and **why it's there** (a workspace default, a team default via label X, or the soul's own choice). The kernel reports this per core capability as `from: soul | workspace | team:<label>`.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## 5. The core capabilities: knowledge, messaging, tasks
|
|
114
|
+
|
|
115
|
+
Most capabilities are unlimited and additive (a soul can have any number). Three are special, the **core capabilities**, and each has exactly **one slot** per soul:
|
|
116
|
+
|
|
117
|
+
| Core capability | What it gives an agent | Official provider | Can be `none` |
|
|
118
|
+
|---|---|---|---|
|
|
119
|
+
| **Knowledge** | durable, shared memory: what the organisation has learned, decisions, lessons; the agent reads it and proposes additions | `oats.okf` | yes |
|
|
120
|
+
| **Messaging** | an identity, a team, mail/chat with other agents and humans, being woken by messages | `oats.aweb` | yes |
|
|
121
|
+
| **Tasks** | a tracker for assignment, status, blockers (Jira, Linear) | `oats.jira`, `oats.linear` | yes |
|
|
122
|
+
|
|
123
|
+
**Why slots:** an agent should have exactly one memory, one address book and one task list, not two competing ones. Everything else is additive.
|
|
124
|
+
|
|
125
|
+
Plus one **default capability** almost every soul has: **`oats.core`**, which teaches the agent how to operate inside OATS (see its teammates, spawn helpers, retire). It's a workspace default and can be turned off per soul.
|
|
126
|
+
|
|
127
|
+
**Vocabulary:** say **"core capabilities"** in the UI (not "layers" or "slots"; those are internal words).
|
|
128
|
+
|
|
129
|
+
### 5.1 Knowledge, specifically
|
|
130
|
+
|
|
131
|
+
- Knowledge lives in **knowledge bases**: Markdown "concepts" organised in **nodes**, usually in a Git repo like `org/knowledge`.
|
|
132
|
+
- A soul **owns** some nodes (its responsibility) and **reads** others (its starting context).
|
|
133
|
+
- Agents propose knowledge through **pull requests**. Nothing is accepted until merged. Agents never write accepted knowledge directly.
|
|
134
|
+
- **(planned, oats.okf 3.0.0, in progress)** Agents consult knowledge **remotely** through commands (`index`, `cat`, `search`, `links`), with **no copy inside each agent's folder**. They're told to consult it at the start of every task and regularly while working. For the Desktop this means a soul's knowledge can be browsed live, at its accepted state, from one shared place.
|
|
135
|
+
|
|
136
|
+
### 5.2 Messaging, specifically
|
|
137
|
+
|
|
138
|
+
- Each instance gets a messaging **identity** (its address).
|
|
139
|
+
- By default it's in the person's **personal team**. It can **join** other eligible teams (from its labels) at spawn or later, and **leave** them. The personal team can't be left.
|
|
140
|
+
- Joined teams currently **check mail between tasks**; live delivery for joined teams is **(planned)**.
|
|
141
|
+
- A stopped agent can be **woken** by a message.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## 6. Instances: lifecycle and work
|
|
146
|
+
|
|
147
|
+
### 6.1 Lifecycle
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
preview → spawn → (start / restart / attach) → … → retire
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
- **Spawn** creates the instance folder, copies the capabilities in, records provenance, and optionally starts a session.
|
|
154
|
+
- **Start / restart** runs the session (in tmux or Herdr), with a **harness** (Claude, Codex or Pi) and a model.
|
|
155
|
+
- **Attach** opens the live terminal.
|
|
156
|
+
- **Retire** preserves any unfinished work, runs each capability's cleanup (e.g. revokes the messaging identity), and removes the folder.
|
|
157
|
+
|
|
158
|
+
### 6.2 Work modes (where the agent works)
|
|
159
|
+
|
|
160
|
+
| Mode | Meaning |
|
|
161
|
+
|---|---|
|
|
162
|
+
| **worktree** | its own branch in a clone of the soul's repo (isolated) |
|
|
163
|
+
| **checkout** | the shared current branch (for coordinators) |
|
|
164
|
+
| **attached** | another instance's work tree (a helper inside a parent's work) |
|
|
165
|
+
| **directory** | an independent folder, no Git |
|
|
166
|
+
| **workspace** | a read view across all member repos (cross-repo coordination) |
|
|
167
|
+
|
|
168
|
+
### 6.3 Relationships between instances
|
|
169
|
+
|
|
170
|
+
Instances form a **hierarchy**: a **child** works for its parent, a **sibling** is a peer, a **parent** oversees. The Desktop's roster is this tree.
|
|
171
|
+
|
|
172
|
+
### 6.4 Provenance and drift: the "what is this agent made of?" answer
|
|
173
|
+
|
|
174
|
+
Each instance records **exactly** what it was built from: every capability's source (repo or package), commit and fingerprint, plus the soul's own commit. A running instance **never changes under itself**.
|
|
175
|
+
|
|
176
|
+
When the workspace moves on (a member pushes, a package version is bumped), existing instances show **drift**: `current`, `moved` (a newer version exists) or `missing` (no longer available). New spawns get the new state.
|
|
177
|
+
|
|
178
|
+
**Design implication:** drift is **information, not an error.** Show it gently ("built from an older version of X; new spawns use the new one") with a clear path to re-spawn.
|
|
179
|
+
|
|
180
|
+
### 6.5 Terminology the UI should use
|
|
181
|
+
|
|
182
|
+
- **Harness**, not "runtime" (Claude, Codex, Pi).
|
|
183
|
+
- **Core capabilities**, not "layers".
|
|
184
|
+
- **Soul / instance**, not "agent type / agent" (though "agent" is fine in casual copy).
|
|
185
|
+
- **Repo-owned** capability: usable only by souls of its own repo.
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## 7. What the Desktop is for (the principle)
|
|
190
|
+
|
|
191
|
+
**The kernel is the model; the Desktop renders it and drives it.** Everything the Desktop shows comes from the `oats` CLI's JSON (status, workspace status, inspect, capabilities, spawn preview). The Desktop never keeps its own copy of the setup, never guesses, and gates features on what the installed CLI *declares*, not on version numbers.
|
|
192
|
+
|
|
193
|
+
**So the design should answer, at a glance:**
|
|
194
|
+
|
|
195
|
+
1. **What is my workspace?** Its members (and their handshake state), its packages (and versions), its teams.
|
|
196
|
+
2. **Who are my agents?** Souls (what roles exist, grouped by team/repo) and instances (what's running, their hierarchy, their state).
|
|
197
|
+
3. **What is this agent made of, and why?** Its composition, with each capability's source and reason (workspace/team/soul), its core capabilities, harness and work mode.
|
|
198
|
+
4. **Where does it work?** Its work mode, branch, and repo; its Git state and pull requests.
|
|
199
|
+
5. **Who can it talk to?** Its messaging identity, its personal team, eligible teams, joined teams.
|
|
200
|
+
6. **What does it know?** Its knowledge nodes (owned/read). **(planned)** A live browser of them.
|
|
201
|
+
7. **Is anything wrong?** Unconfirmed members, missing clones, team conflicts, drift, readiness problems, each with the plain cause and the fix.
|
|
202
|
+
|
|
203
|
+
**The Desktop today already has** (0.27.x): a Workspace area (souls, capabilities with *workspace-owned / packages / repo-owned* sections, a **Setup** graph of *this computer → workspace → repos/packages*), soul pages and capability pages, a spawn dialog (with a Teams row), instance side panels (*Instance · Soul · Git & GitHub*), a live Teams panel, and terminals. The redesign is about making this **legible and professional**, not inventing new concepts.
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## 8. Why the architecture is like this (the reasoning to carry into the design)
|
|
208
|
+
|
|
209
|
+
- **Git is the source of truth.** Organisations already review, permission and history their repos. OATS reuses that instead of inventing an admin console. → *The Desktop shows and edits declarations; it doesn't hide settings in the app.*
|
|
210
|
+
- **No installs, only copies with receipts.** Every agent's folder is self-contained and records its sources. → *"Where did this come from?" always has an exact answer. Surface it.*
|
|
211
|
+
- **Members are live; packages are pinned.** Your own work moves fast; shared tooling doesn't shift under you. → *Always show a capability's source tier and version.*
|
|
212
|
+
- **Membership is trust.** Joining a workspace is a two-sided, reviewable act in Git. → *Membership state is a first-class, visible status, not a hidden error.*
|
|
213
|
+
- **Exactly one memory, one address book, one task list per agent.** → *The core capabilities are a distinct, fixed-shape section of every soul.*
|
|
214
|
+
- **Teams organise; they don't restrict.** → *Don't design teams as permissions or walls.*
|
|
215
|
+
- **Nothing changes under a running agent.** → *Drift is calm information with a re-spawn path.*
|
|
216
|
+
- **Per-machine vs shared is explicit.** → *Clearly separate "this computer" from "the organisation's setup".*
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## 9. Glossary
|
|
221
|
+
|
|
222
|
+
- **Workspace**: the organisation's shared agent setup (one `oats-workspace.yaml`).
|
|
223
|
+
- **Host repo**: the member repo that holds `oats-workspace.yaml`.
|
|
224
|
+
- **Member**: a repo that completed the two-way handshake.
|
|
225
|
+
- **Deployment**: one machine's folder that runs the workspace (`oats-local.yaml` + lock + instances).
|
|
226
|
+
- **Soul**: a durable agent role (a folder with `soul.yaml`, `AGENTS.md`, skills).
|
|
227
|
+
- **Instance**: a working incarnation of a soul (folder + task + session).
|
|
228
|
+
- **Capability**: a reusable bundle (skills, instructions, commands, hooks).
|
|
229
|
+
- **Core capability**: knowledge, messaging or tasks: one slot each per soul.
|
|
230
|
+
- **Package**: a versioned, pinned bundle of capabilities.
|
|
231
|
+
- **Official catalog**: the reviewed list of official packages and versions.
|
|
232
|
+
- **Lock**: the exact commit + fingerprint of each package, per deployment.
|
|
233
|
+
- **Team (label)**: an organising label; supplies defaults and eligible messaging teams.
|
|
234
|
+
- **Personal team**: the messaging team every instance is in by default.
|
|
235
|
+
- **Harness**: what runs the agent session (Claude, Codex, Pi).
|
|
236
|
+
- **Work mode**: where an instance works (worktree, checkout, attached, directory, workspace).
|
|
237
|
+
- **Drift**: an instance built from an older state than the workspace's current one.
|
|
238
|
+
- **Repo-owned capability**: usable only by souls of its own repo.
|
|
239
|
+
- **Accepted knowledge**: knowledge merged into its base's accepted branch.
|
|
240
|
+
|
|
241
|
+
**Further reading (technical):** `docs/workspaces.md`, `docs/souls-and-instances.md`, `docs/capabilities.md`, `docs/desktop-cli-api.md`, and the Desktop Phase F boundary `docs/design/2026-09-24-desktop-phase-f-boundary.md`.
|
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
# OKF knowledge operations: harvest, maintenance, triggers, and the working-soul surface
|
|
2
|
+
|
|
3
|
+
**Status:** APPROVED by the human, 2026-09-26 ("perfect, I like it … get it moving and implemented and deployed as fast as possible"). Planned by the lead; the co-lead's amendments are folded in as they arrive.
|
|
4
|
+
**Targets:** kernel **0.28.0**, oats.okf **4.0.0**, oats.framework **1.2.0**. okf **3.0.0** (the remote consult, in flight) ships first and unchanged in scope.
|
|
5
|
+
|
|
6
|
+
## 0. The human's direction, restated
|
|
7
|
+
|
|
8
|
+
1. **Knowledge operations are split across three capabilities.**
|
|
9
|
+
- **oats.okf**: the working-soul surface.
|
|
10
|
+
- **oats.okf-harvest**: the harvester.
|
|
11
|
+
- **oats.okf-maintenance**: the maintainer.
|
|
12
|
+
- The harvester and the maintainer share a renamed **knowledge-theory** skill (today `memory-harvest`), and each has its own skills too.
|
|
13
|
+
- **oats.okf ships no harvest doctrine at all.**
|
|
14
|
+
2. **Working souls using OKF get exactly two okf skills and one inject.**
|
|
15
|
+
- A skill for *instance knowledge maintenance* (STATE/log/notes), **teaching the judgment and theory of what useful instance knowledge to capture** (amended by the human, 2026-09-26).
|
|
16
|
+
- A skill for *soul knowledge consultation* (`okf-consultation`).
|
|
17
|
+
- The inject teaches the work mode: query both before starting a task, before compaction, and every so often while working, to decide, situate and work coherently with the soul's knowledge.
|
|
18
|
+
3. **The harvester**:
|
|
19
|
+
- reads the harvested instance's **session transcript** (not only its notes), so its judgment has full context;
|
|
20
|
+
- opens a PR to the knowledge-base repo;
|
|
21
|
+
- **stays alive until that PR is merged (or closed), then self-retires.**
|
|
22
|
+
4. **The maintainer**: a **knowledge-maintainer soul** reviews each harvest PR.
|
|
23
|
+
- It situates the addition in the base.
|
|
24
|
+
- It reads the harvested instance's tasks, if that instance had a tasks capability.
|
|
25
|
+
- It reads the existing soul knowledge.
|
|
26
|
+
- It judges soundness, amends whatever needs amending, and merges.
|
|
27
|
+
5. **Triggers** (new concept).
|
|
28
|
+
- A deployment (laptop or server) can declare "on an event, spawn a NEW instance of soul X with this instruction, in these teams".
|
|
29
|
+
- The first use: *on a harvest PR opened → spawn the knowledge maintainer to review it.*
|
|
30
|
+
6. **Fully defined in the okf repo.**
|
|
31
|
+
- The maintainer (and harvester) souls live in oats-okf.
|
|
32
|
+
- Users who onboard with the defaults get the trigger that launches the maintainer, **sourced from the okf package**.
|
|
33
|
+
- The skills insist the trigger runs on a deployment whose GitHub credentials can approve/merge PRs on the KB repo.
|
|
34
|
+
7. **An `okf` team.**
|
|
35
|
+
- Workspaces using OKF get an `okf` team, so harvesters and maintainers talk without polluting the working teams.
|
|
36
|
+
- The okf onboarding teaches it.
|
|
37
|
+
|
|
38
|
+
## 1. What already exists (verified 2026-09-26)
|
|
39
|
+
|
|
40
|
+
- **Scheduler** (`docs/schedules.md`).
|
|
41
|
+
- Committable definitions per deployment scope.
|
|
42
|
+
- One host timer runs `oats schedule tick --host` every minute; there's no daemon.
|
|
43
|
+
- Kinds: `spawn`, `command`, `wake`.
|
|
44
|
+
- Scheduled spawns materialize exactly like `oats spawn`.
|
|
45
|
+
- okf already registers one `command` job per source (`oats okf run-source`).
|
|
46
|
+
- **Transcript capture.** okf's custody already copies **notes AND the record** (bounded `recall` windows of the session transcript, full text) into `<stateDir>/sources/<uuid>/inputs/<hash>.json`. It excludes privacy-excluded sessions. The harvester therefore needs no live source home. The gap is **doctrine and procedure**: the current skill does not make reading the transcript windows mandatory and systematic.
|
|
47
|
+
- **PR delivery.** okf's `complete` pushes a branch and runs `gh pr create` on the base's repository (title `memory-harvest: <run>`). It already tracks PR state by `gh pr view/list`.
|
|
48
|
+
- **The harvester today is a *capability agent*** (`agents/memory-harvest` in the okf manifest).
|
|
49
|
+
- It gets the whole oats.okf module (so every okf skill), no okf inject, and no hooks, so no messaging identity.
|
|
50
|
+
- It retires as soon as the completion receipt is written.
|
|
51
|
+
- **Souls from a non-member repo** exist only as `external:` (commit-pinned, not versioned with a package). **Packages cannot ship souls today.** This is the one real kernel gap for (6).
|
|
52
|
+
- **Teams:**
|
|
53
|
+
- labels are declared in `teams:`;
|
|
54
|
+
- `join=` at spawn exists (0.27.x);
|
|
55
|
+
- a soul's label must be declared, or it's `E_TEAM_UNKNOWN`.
|
|
56
|
+
|
|
57
|
+
## 2. Target design
|
|
58
|
+
|
|
59
|
+
### 2.1 Capabilities in the oats.okf package (4.0.0)
|
|
60
|
+
|
|
61
|
+
| Capability | Who gets it | Skills | Inject | Commands, hooks and the rest |
|
|
62
|
+
|---|---|---|---|---|
|
|
63
|
+
| **oats.okf** (knowledge slot) | every working soul with OKF knowledge | `okf-consultation` (soul knowledge: bases/index/cat/ls/links/search, receipts, citing); **`okf-instance-knowledge`** (instance memory: **the theory and judgment of what is worth capturing**, plus STATE.md/log.md/notes form and compaction discipline; §2.5a) | **the work-mode inject** (§2.5) | the consult commands; `setup`/`init`/`migrate`/binding; the spawn hook (source registration) and retire hook (custody) |
|
|
64
|
+
| **oats.okf-harvest** (additive) | the harvester soul only | **`knowledge-theory`** (the doctrine, renamed from `memory-harvest` §3.x); **`knowledge-harvest`** (the procedure: read input fully, transcript windows first-class, situate, stage, PR, lifecycle until merged); **`okf-authoring`** (OKF Markdown craft, today's `okf` skill) | a harvester inject: you are a judge, not a worker; the staged roots are your only write surface; stay alive until the PR is merged/closed | `complete`, `harvest-status`; no source registration |
|
|
65
|
+
| **oats.okf-maintenance** (additive) | the maintainer soul only | **`knowledge-theory`** (identical copy); **`knowledge-review`** (situate a PR, read provenance, the source soul's knowledge, its tasks, verdicts, amend, merge, notify); **`okf-authoring`** (identical copy); **`okf-trigger-setup`** (install/verify the review trigger on a host with merge-capable GitHub credentials) | a maintainer inject: one PR per instance; never merge what fails the doctrine; supersede, never silently overwrite | `review-context` (the PR's provenance → the reading list), `notify-harvester` |
|
|
66
|
+
|
|
67
|
+
**Shared skills are shipped as identical copies** in each capability (a package is a Git tree; there's no build step). A package test fails if the copies differ. There's no `E_SKILL_DUPLICATE` risk, because no soul composes both harvest and maintenance.
|
|
68
|
+
|
|
69
|
+
**Removed from oats.okf:** `memory-harvest` (it becomes `knowledge-theory` + `knowledge-harvest` in oats.okf-harvest), the `okf` authoring skill (→ `okf-authoring`, maintenance/harvest only), and the `agents/memory-harvest` capability agent (→ a package soul).
|
|
70
|
+
|
|
71
|
+
**Name note:** oats.framework already ships a *capability* `oats.knowledge-theory` (the skill `knowledge-capability-authoring`, for capability authors). The new *skill* `knowledge-theory` is unrelated and lives in okf's namespace. Its description must say "OKF promotion doctrine" so triggering doesn't confuse the two.
|
|
72
|
+
|
|
73
|
+
### 2.2 Package souls (kernel 0.28.0), the enabler for "sourced from the okf package"
|
|
74
|
+
|
|
75
|
+
- A package manifest may declare `souls: ["souls/knowledge-maintainer", "souls/knowledge-harvester"]`.
|
|
76
|
+
- Each is an ordinary soul directory (`soul.yaml`, `AGENTS.md`, `skills/`).
|
|
77
|
+
- **Versioned and locked with the package:** one pin (`packages: { oats.okf: 4.0.0 }`) versions the capabilities *and* the souls. Nothing drifts, unlike `external:` commit pins.
|
|
78
|
+
- **Discovery:** they're listed with `origin: package` (`oats status --workspace`, and the Desktop Souls page shows "from package oats.okf 4.0.0").
|
|
79
|
+
- **Spawn:** by name. A package soul's instances live in a qualified directory (not shared with a same-named member soul).
|
|
80
|
+
- Package souls are namespaced `oats.okf/knowledge-maintainer` to avoid collisions with member souls.
|
|
81
|
+
- A bare name works when unambiguous.
|
|
82
|
+
- **Resolution:**
|
|
83
|
+
- `from: here` inside a package soul means *this package*.
|
|
84
|
+
- Workspace/team defaults apply as for any soul (the soul can opt out with `off`/`none`).
|
|
85
|
+
- **Workspace control:** `disabled:` in `oats-local.yaml` works as for member souls.
|
|
86
|
+
- **Trust:** the same as the package's capabilities. Declaring the package is the trust decision.
|
|
87
|
+
- **This replaces capability agents** (`agents:` in a capability manifest) once okf 4.0.0 is pinned. Removing the capability-agent path is a separate kernel PR, per "v2 becomes the classic" (no dual path), after the okf 4.0.0 mirror.
|
|
88
|
+
|
|
89
|
+
### 2.3 Triggers (kernel 0.28.0)
|
|
90
|
+
|
|
91
|
+
**The concept:**
|
|
92
|
+
- A trigger is **an event-driven schedule**: "when EVENT matches, spawn a NEW instance of SOUL with TASK, in TEAMS".
|
|
93
|
+
- It lives beside schedules: the same deployment scope, file and host tick (`oats schedule tick --host`), and the same spawn path. There's no new daemon, and it runs only on the host that holds the scope.
|
|
94
|
+
- Triggers are **per-deployment by design**: they need that machine's credentials.
|
|
95
|
+
|
|
96
|
+
**Definition** (stored in the schedules file as `kind: "trigger"`, managed by `oats trigger …`):
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{ "id": "okf-harvest-review", "enabled": true, "kind": "trigger",
|
|
100
|
+
"on": { "source": "github.pull_request", "repo": "github.com/acme/knowledge",
|
|
101
|
+
"events": ["opened", "reopened", "ready_for_review"],
|
|
102
|
+
"labels": ["okf-harvest"], "base": "main", "poll": "2m" },
|
|
103
|
+
"spawn": { "soul": "oats.okf/knowledge-maintainer", "purpose": "review-pr-{number}",
|
|
104
|
+
"task": "Review knowledge-base PR {repo}#{number}. Load knowledge-review first.",
|
|
105
|
+
"teams": ["okf"], "harness": "claude", "model": "opus" },
|
|
106
|
+
"concurrency": { "max": 2, "perKey": 1 } }
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- **Sources, v1:** `github.pull_request` only (polled with the host's `gh` auth; a laptop has no webhook). The shape is open to `github.issue`, `aweb.mail` and `okf.harvest` later.
|
|
110
|
+
- **Dedup and delivery:**
|
|
111
|
+
- An event key (`<trigger>:<repo>#<number>:<event>:<updated_at>`) is recorded in the trigger state; each key spawns at most once.
|
|
112
|
+
- The key is recorded *after* a successful spawn, so a failed spawn is retried on the next poll.
|
|
113
|
+
- `perKey: 1` means one live instance per PR.
|
|
114
|
+
- **The event reaches the instance** as `OATS_TRIGGER_EVENT_FILE` (a JSON file in the home: `{trigger, source, repo, number, url, event, headSha, labels}`), plus the templated task.
|
|
115
|
+
- **Templates substitute ONLY whitelisted structured fields** (`{repo} {number} {url} {event} {headSha}`). PR titles and bodies are **never** interpolated into the task. They're untrusted data, which the soul reads from the event file and GitHub.
|
|
116
|
+
- **Teams:** `spawn.teams` → the spawn's `join=` (0.27.x) for the messaging provider.
|
|
117
|
+
- **CLI:**
|
|
118
|
+
- `oats trigger add --from <package>:<template> | --file <json>`;
|
|
119
|
+
- `list`, `show`, `enable`/`disable`, `remove`;
|
|
120
|
+
- `test <id>` (a dry run: check gh auth, repo access and the soul's resolvability, and list what WOULD fire now);
|
|
121
|
+
- `status` (the last polls, fired keys, live instances).
|
|
122
|
+
- Also in `--json` and `oats capabilities` (`features: ["triggers"]`) for the Desktop.
|
|
123
|
+
- **Package trigger templates:** a package may declare `triggers: [{ id, file }]`; `oats trigger add --from oats.okf:harvest-review` instantiates one after asking for the repo. This is how okf ships the default.
|
|
124
|
+
- **Safety:** a trigger spawns only a soul that resolves in this workspace. A disabled soul refuses. The trigger runs with the host's own credentials, and there's no credential in the definition.
|
|
125
|
+
|
|
126
|
+
### 2.3a Workspace automations: triggers and schedules declared in Git (the human, 2026-09-26)
|
|
127
|
+
|
|
128
|
+
Triggers and schedules are defined at **one of two levels** (the canonical folders are `oats-triggers/` and `oats-schedules/`; any file following the contract is picked up):
|
|
129
|
+
- **the workspace level**, committed in any member repo and shared through Git: the default for anything a team relies on;
|
|
130
|
+
- **locally**, in the deployment (§2.3 as built: `oats trigger add`, `oats schedule add`): machine-private, for personal or experimental jobs.
|
|
131
|
+
|
|
132
|
+
**A human is a GitHub account** (a person or a machine user). Every workspace automation says **which machine runs it** and **which account it acts as**.
|
|
133
|
+
|
|
134
|
+
**The canonical contract:**
|
|
135
|
+
- **Where it lives (the human, amended):**
|
|
136
|
+
- **Canonical folder:** `oats-triggers/` (and `oats-schedules/`) at a member's root. Every `*.yaml`/`*.yml` there is a candidate.
|
|
137
|
+
- **Also picked up anywhere in the repo:** any file that follows the contract by name, `*.oats-trigger.yaml` / `*.oats-schedule.yaml` (`.yml` too), e.g. `services/billing/nightly.oats-schedule.yaml` beside the code it concerns.
|
|
138
|
+
- **The contract is self-describing:** the file carries `kind: oats-trigger` (or `oats-schedule`) + `schemaVersion: 1`. A candidate without the right `kind` is an `E_AUTOMATION_SCHEMA` discovery problem, not silently ignored.
|
|
139
|
+
- **The id** is the file's `id:`, else the filename stem (without `.oats-trigger`). Two files in one member with the same id → `E_AUTOMATION_DUPLICATE`, naming both paths.
|
|
140
|
+
- **Discovery cost:** one recursive tree listing per member commit (names only, no blobs; cached per commit), then blob reads of the candidates only.
|
|
141
|
+
- **Never scanned:** `oats-package/` (package templates are not workspace automations), `.git/`, `node_modules/`.
|
|
142
|
+
- **Discovery:** they're discovered like souls (over the remote, from CONFIRMED members only), named `<member>/<id>`, and listed by `oats workspace status` / `oats trigger list` / `oats schedule list` with `origin: { kind: "workspace", repoKey, commit }`.
|
|
143
|
+
|
|
144
|
+
```yaml
|
|
145
|
+
# <member>/oats-triggers/okf-harvest-review.yaml
|
|
146
|
+
kind: oats-trigger
|
|
147
|
+
schemaVersion: 1
|
|
148
|
+
description: Review every harvest PR on the knowledge base
|
|
149
|
+
from: oats.okf:harvest-review # optional: a package template (§2.3), then overrides
|
|
150
|
+
set: { repo: github.com/acme/knowledge }
|
|
151
|
+
runsOn: kb-bot-server # the host name (oats-local.yaml host.name) that runs it
|
|
152
|
+
owner: github.com/acme-kb-bot # the GitHub account it acts as (a person or a machine user)
|
|
153
|
+
# …or a full definition (on/spawn/concurrency) as in §2.3, instead of from/set
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
```yaml
|
|
157
|
+
# <member>/oats-schedules/nightly-digest.yaml (or anywhere: …/nightly-digest.oats-schedule.yaml)
|
|
158
|
+
kind: oats-schedule
|
|
159
|
+
schemaVersion: 1
|
|
160
|
+
run: spawn # spawn | command | wake, as today
|
|
161
|
+
cron: "0 7 * * *"
|
|
162
|
+
tz: Europe/Madrid
|
|
163
|
+
agent: digest-writer
|
|
164
|
+
task: Write the nightly digest.
|
|
165
|
+
runsOn: ana-laptop
|
|
166
|
+
owner: github.com/ana
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**Host identity:** `oats-local.yaml` gains `host: { name: <slug> }`. It's a machine fact, never in Git.
|
|
170
|
+
|
|
171
|
+
**Who runs it:** a host runs a workspace automation ONLY when BOTH are true:
|
|
172
|
+
- `runsOn` equals its `host.name`;
|
|
173
|
+
- the host's authenticated `gh` account equals `owner` (`gh api user`, cached per tick).
|
|
174
|
+
|
|
175
|
+
**Otherwise** it's listed with the reason:
|
|
176
|
+
- `assigned-elsewhere` (another host);
|
|
177
|
+
- `owner-mismatch` (this host is named but logged in as someone else; nothing runs, and `oats trigger test` says so);
|
|
178
|
+
- `host-unnamed` (the host has no `host.name`).
|
|
179
|
+
|
|
180
|
+
That makes "exactly one machine" a declared fact, and **consent** explicit: a machine acts for an account only when its operator named it AND is logged in as that account. Declaring the automation in a member is the trust decision for its *definition*, like souls.
|
|
181
|
+
|
|
182
|
+
**Opting out:** per kind, mirroring `souls.disabled`: `oats-local.yaml` `triggers: { disabled: [<member>/<id>, …] }` / `schedules: { disabled: [...] }` stops a named host from running one, without a commit. Triggers and schedules are separate modules (the human), sharing only the kind-neutral pieces.
|
|
183
|
+
|
|
184
|
+
**Refresh:**
|
|
185
|
+
- The host tick reads a snapshot of the workspace automations taken by `oats sync`, and refreshed by the tick at most every 10 minutes.
|
|
186
|
+
- A definition change reaches the host within ~10 minutes; no fetch happens every minute.
|
|
187
|
+
- The run state (dedup keys, the last poll) stays per host and local.
|
|
188
|
+
|
|
189
|
+
**Local automations are unchanged:** machine-private, implicitly this host and its own `gh`, so no `runsOn`/`owner`. Workspace ids are `<member>/<id>`. A local schedule row keeps its bare `id` (compatible with existing consumers) plus a `qualifiedId: local/<id>`.
|
|
190
|
+
|
|
191
|
+
**Safety:** everything in §2.3 still holds (the soul must resolve here; only whitelisted fields are templated; PR text is never interpolated; there's no credential in any definition).
|
|
192
|
+
|
|
193
|
+
**Schedules are the same contract as triggers** (the human, 2026-09-26):
|
|
194
|
+
- A workspace schedule (`oats-schedules/<id>.yaml`, or `*.oats-schedule.yaml` anywhere) carries `runsOn` + `owner` and runs ONLY on the named host logged in as that account.
|
|
195
|
+
- The same `assigned-elsewhere` / `owner-mismatch` / `host-unnamed` reasons, the same per-kind opt-out (`schedules.disabled`), the same snapshot refresh, and local schedules as `local/<id>`.
|
|
196
|
+
- One rule set for both kinds; the kernel implements them together.
|
|
197
|
+
|
|
198
|
+
**Desktop: the Schedules tab (existing, redesigned) + a NEW Triggers tab** (the human, 2026-09-26; no unified "Automations" view):
|
|
199
|
+
- The existing **Schedules** tab is redesigned in place, and a new **Triggers** tab sits beside it.
|
|
200
|
+
- **Both show workspace AND local items together**, each row marked with its origin.
|
|
201
|
+
- **Sequencing:** the Desktop engineer's finished redesign ships FIRST (in 0.28.0). These tabs come after, on the kernel's `automations` JSON (0.29.0).
|
|
202
|
+
- In each tab the user sees **every workspace item defined in the member repos they can read**, plus their own machine's local ones.
|
|
203
|
+
- **Each row:**
|
|
204
|
+
- the id (`<member>/<id>` or `local/<id>`) and its origin (workspace/local);
|
|
205
|
+
- **the owner** (the GitHub account);
|
|
206
|
+
- **where it runs** (`runsOn`, and whether that's THIS machine, with the reason when not);
|
|
207
|
+
- **the soul** it spawns (with its origin: member/package);
|
|
208
|
+
- **the prompt** (the task template, shown verbatim, with the whitelisted fields highlighted);
|
|
209
|
+
- the event (a trigger's `on`) or the cron+tz (a schedule);
|
|
210
|
+
- teams, harness/model, concurrency;
|
|
211
|
+
- enabled/disabled here;
|
|
212
|
+
- the last run/fire and the next due (for automations this machine runs).
|
|
213
|
+
- **Where it comes from:** the repo + path + commit of the file, linking to the file.
|
|
214
|
+
- **Actions:**
|
|
215
|
+
- `test` (a dry run on this host);
|
|
216
|
+
- disable/enable here (`triggers.disabled` / `schedules.disabled`);
|
|
217
|
+
- open the defining file;
|
|
218
|
+
- for local ones: add/edit/remove.
|
|
219
|
+
- **Visibility follows repo access:** a member the user can't read contributes nothing (the standalone rule), so the Desktop never shows automations the user couldn't read in Git.
|
|
220
|
+
- **Data:** `oats trigger list --json` / `oats schedule list --json` (workspace + local, with origin, owner, runsOn, runsHere + reason, soul, task, and the last/next run). This JSON is part of PR 2b's contract, so the Desktop renders it and never re-derives it.
|
|
221
|
+
|
|
222
|
+
**Onboarding / okf:**
|
|
223
|
+
- The review trigger becomes a **workspace file** (`oats-triggers/okf-harvest-review.yaml` in the host repo, `from: oats.okf:harvest-review`, with `runsOn` + `owner` naming the merge-capable host and account).
|
|
224
|
+
- `oats trigger add --from … --workspace <member>` writes it (or prints it when that repo isn't the current checkout).
|
|
225
|
+
- `oats trigger test <member>/<id>` runs on the named host. This supersedes "install on ONE host" by hand.
|
|
226
|
+
|
|
227
|
+
**Delivery:**
|
|
228
|
+
- **PR 2b (kernel):** after #205. Discovery + the host identity + the owner/host matching + the snapshot + the CLI/JSON + docs.
|
|
229
|
+
- The target is **0.29.0**, released with okf 4.0.0, whose `okf-trigger-setup` teaches the workspace form first. The floor becomes `oats >= 0.29.0`.
|
|
230
|
+
- 0.28.0 ships the local triggers (#205) as the mechanism.
|
|
231
|
+
|
|
232
|
+
### 2.4 The harvester and the maintainer (oats.okf 4.0.0)
|
|
233
|
+
|
|
234
|
+
**`knowledge-harvester` soul** (a package soul; `work: directory`; `team: okf`; `knowledge: none`, so there's no recursive harvest; capability `oats.okf-harvest`).
|
|
235
|
+
1. okf's `run-source` job captures custody (unchanged) and **spawns the harvester soul** (not a capability agent) with the frozen input, joining `okf`.
|
|
236
|
+
2. **Reads the input fully:** notes AND the **transcript windows**. This is mandatory, and the judgment receipt must cite the turn ids it relied on.
|
|
237
|
+
- It also extracts **task references** (ticket ids/URLs seen in the transcript, notes and the source's `instance.json` tasks provider).
|
|
238
|
+
3. Judges with `knowledge-theory`; stages edits on the owned nodes; `complete` opens the PR:
|
|
239
|
+
- label `okf-harvest`;
|
|
240
|
+
- a **provenance block** in the body: a fenced `okf-harvest` JSON block, `{ run, input, source: { soul, soulId, instance, ownedNodes, readNodes, bases }, tasks: { provider, refs[] }, harvester: { instance, alias } }`.
|
|
241
|
+
4. **Stays alive** (idle; woken by messages in `okf`):
|
|
242
|
+
- It answers the maintainer's questions and pushes amendments on request.
|
|
243
|
+
- It retires on **merged/closed** (the maintainer's message, or its own PR check on each wake).
|
|
244
|
+
- A **max-age** (the setting `harvester-max-age`, default 7d) retires it after telling the team. It never closes the PR itself.
|
|
245
|
+
|
|
246
|
+
**The harvest switch (lead decision, 2026-09-26; L2 implements it):**
|
|
247
|
+
- **A setting, not a job toggle:** `harvest: on|off` for oats.okf, **default `off`**.
|
|
248
|
+
- **Where it's set:**
|
|
249
|
+
- Deployment-wide, in `oats-local.yaml` `settings.oats.okf.harvest` (a machine fact: the operator decides whether this host harvests).
|
|
250
|
+
- Per soul, as the opt-out: `soul.yaml` `knowledge: { harvest: off }`.
|
|
251
|
+
- **Effective = on only if the deployment says `on` AND the soul does not say `off`.** A soul's `off` cannot be overridden by the host. This deliberately departs from the usual later-wins merge, and L2 must implement it explicitly.
|
|
252
|
+
- **When it's off:** the spawn hook registers no source, and no capture or custody happens. Private transcripts are never accumulated "for later", and nothing drains when the switch flips; harvest starts from the next session. The per-source `run-source` job exists only when harvest is effectively on.
|
|
253
|
+
- **The verbs:**
|
|
254
|
+
- `oats okf setup --harvest on|off` writes the local setting (else it prints the line to add);
|
|
255
|
+
- `oats okf harvest-status [--soul X]` reports the effective value and why (the deployment/soul row), plus the registered sources.
|
|
256
|
+
- `oats schedule enable|disable <job>` remains the per-source emergency brake, not the switch.
|
|
257
|
+
- **The review trigger is independent of the switch:** a trigger host can review PRs from other hosts' harvesters without harvesting itself.
|
|
258
|
+
|
|
259
|
+
**`knowledge-maintainer` soul** (a package soul; `work: directory`; `team: okf`; `knowledge: none` in v1; capabilities `oats.okf-maintenance` + the workspace's tasks slot, **read-only use**).
|
|
260
|
+
1. Spawned by the trigger, one per PR. It reads `OATS_TRIGGER_EVENT_FILE`, clones/fetches the KB repo and `gh pr checkout`s the PR in its `./work`.
|
|
261
|
+
2. **Situates** the addition:
|
|
262
|
+
- the provenance → the source soul's owned/read nodes at the accepted base;
|
|
263
|
+
- the whole node index and neighbouring concepts (duplicates, supersession candidates, the canonical home);
|
|
264
|
+
- the source soul's other knowledge.
|
|
265
|
+
3. **Tasks:** if the provenance names a tasks provider and refs, it reads those tickets through its own tasks capability (when the workspace's tasks slot matches). Otherwise it notes "tasks unavailable" in the verdict. This is never a blocker.
|
|
266
|
+
4. **Verdict** (recorded as a PR review comment, as structured JSON + prose):
|
|
267
|
+
- `merge`;
|
|
268
|
+
- `amend+merge` (it pushes commits to the PR branch: fixes, supersession edits in other concepts of the same base, index/log);
|
|
269
|
+
- `request-changes` (it messages the harvester in `okf`; waits bounded);
|
|
270
|
+
- `close` (with the reason).
|
|
271
|
+
- The doctrine's two-part test, one canonical home, explicit supersession, and provenance are all checked.
|
|
272
|
+
5. **Human-accepted decisions are never superseded silently.** If a PR would supersede a concept with human acceptance evidence, the maintainer does not merge. It labels `okf-needs-human` and messages the workspace's human channel.
|
|
273
|
+
6. Merges with the host's `gh` (squash); notifies the harvester (`merged`/`closed`); self-retires.
|
|
274
|
+
|
|
275
|
+
**GitHub credentials:** the maintainer's host must be able to **merge** on the KB repo. `okf-trigger-setup` and `oats trigger test` verify it (`gh api repos/{repo} --jq .permissions`). **If the harvester and maintainer use the same GitHub account, GitHub forbids self-approval.** The skill says so: either use a separate reviewer account/bot on the maintainer's host, or rely on merge permissions without required approvals on the KB repo's `main`.
|
|
276
|
+
|
|
277
|
+
### 2.5 The working-soul inject (oats.okf 4.0.0)
|
|
278
|
+
|
|
279
|
+
It extends the 3.0.0 inject into a *work mode*:
|
|
280
|
+
- **At task start and after compaction:** read instance memory (`STATE.md`, recent `log.md`, relevant `notes/`), then consult soul knowledge (`oats okf index`, then `cat` what's relevant).
|
|
281
|
+
- **Before compaction:** update `STATE.md`/`log.md`/`notes/` first.
|
|
282
|
+
- **Every so often while working, and always before a design decision or re-deriving something:** `oats okf search`/`cat`, and re-read your own notes.
|
|
283
|
+
- Use both to situate the task and stay coherent with the soul's accepted decisions. Cite what you relied on.
|
|
284
|
+
- **Capture with judgment** (§2.5a). The harvester still decides what is *promoted*. Never write accepted knowledge.
|
|
285
|
+
|
|
286
|
+
### 2.5a Instance-knowledge judgment (the human, 2026-09-26)
|
|
287
|
+
|
|
288
|
+
`okf-instance-knowledge` teaches **what useful instance knowledge is**, not only where to put it. This replaces "capture without judging importance" in today's inject. The **capture bar** is lower than the **promotion bar** (`knowledge-theory`), and they don't compete.
|
|
289
|
+
|
|
290
|
+
- **The capture test:** *would my future self after compaction, or the harvester judging this session, decide or act better for having it, and is it absent from the code, the tracker and the repo docs?*
|
|
291
|
+
- **Capture:**
|
|
292
|
+
- decisions taken, and **why**;
|
|
293
|
+
- alternatives rejected, and why;
|
|
294
|
+
- discoveries that cost effort;
|
|
295
|
+
- limitations and the workaround that worked;
|
|
296
|
+
- conclusions of an investigation (not its transcript);
|
|
297
|
+
- blockers, with what unblocks them;
|
|
298
|
+
- human direction and corrections, as the instance understood them;
|
|
299
|
+
- surprises (the world behaved differently from what the soul's knowledge says: a *candidate supersession*, flagged as such);
|
|
300
|
+
- process and environment lessons.
|
|
301
|
+
- **Don't capture:**
|
|
302
|
+
- descriptions of the code, and maps of the repo;
|
|
303
|
+
- command logs and tool output;
|
|
304
|
+
- retries that taught nothing;
|
|
305
|
+
- secrets;
|
|
306
|
+
- third-party messages verbatim;
|
|
307
|
+
- things already in the tracker or the docs (link instead).
|
|
308
|
+
- **Form:**
|
|
309
|
+
- `STATE.md` = the current task picture (rewritten);
|
|
310
|
+
- `log.md` = dated events (append-only);
|
|
311
|
+
- `notes/` = **one concept per insight**, with type (Decision / Rejected / Discovery / Limitation / Conclusion / Lesson / Blocker), a one-line claim, the *why*, the evidence and provenance (what was observed, when, from what), and its **generality** (instance-only vs likely true for the soul, a hint to the harvester, not a verdict).
|
|
312
|
+
- **Timing:** capture as it happens, at the decision, not reconstructed at the end; update before compaction and before task boundaries.
|
|
313
|
+
- **Relation to soul knowledge:** consult first; a note that confirms, refines or contradicts an existing concept cites it (`alias/node/concept.md@oid`). That is what lets the harvester situate it.
|
|
314
|
+
- **The theory it teaches in brief:** decision vs description (descriptions drift and lie; decisions are superseded explicitly), code is truth about code, and indexical residue dies with the instance. This is a short version of `knowledge-theory`, taught from the capture side. **Working souls do NOT get the full promotion doctrine**, so there's no duplicate judge.
|
|
315
|
+
|
|
316
|
+
### 2.6 The `okf` team
|
|
317
|
+
|
|
318
|
+
- Onboarding (the oats.framework `oats-onboarding` skill + okf's `okf-trigger-setup`) adds `teams: { okf: { description: Knowledge operations } }` and the `messaging.byTeam.okf` mapping.
|
|
319
|
+
- The package souls carry `team: okf`. A workspace that does not declare `okf` gets the `E_TEAM_UNKNOWN` discovery problem on them (listed with the remedy; as for member souls it's not a spawn refusal, but their instances then land in no messaging team, so harvester↔maintainer talk fails). So onboarding must add it, and `oats trigger test` checks it.
|
|
320
|
+
- The label organises and gates nothing (the teams contract).
|
|
321
|
+
|
|
322
|
+
## 3. Delivery plan
|
|
323
|
+
|
|
324
|
+
**Order:** 3.0.0 (in flight) → kernel 0.28.0 contracts (C1, C2) frozen → the three lanes in parallel → okf 4.0.0 → the 0.28.0 release with the mirror + pin + onboarding.
|
|
325
|
+
|
|
326
|
+
**Contracts frozen first** (in this doc, by the lead; the co-lead ACKs):
|
|
327
|
+
- **C1, package souls:** §2.2.
|
|
328
|
+
- **C2, triggers:** §2.3 (the definition, the event file, the dedup, the CLI).
|
|
329
|
+
- **C3, the harvest provenance block:** §2.4.3.
|
|
330
|
+
- **C4, the okf-team messages:** `question`/`amend-request`/`amended`/`merged`/`closed` (a subject prefix `okf:` + a PR URL). This is prose-level and is owned by the skills.
|
|
331
|
+
|
|
332
|
+
**L1, kernel.** A **Claude kernel developer** (`cli-dev`, a new instance, Opus), in a worktree. Three PRs, each Class B, reviewed by the lead:
|
|
333
|
+
1. **Package souls** (C1): discovery, resolution, spawn by name, status/Desktop JSON `origin: package`, `oats capabilities` feature `package-souls`.
|
|
334
|
+
2. **Triggers** (C2): `kind: "trigger"`, `github.pull_request` polling in the host tick, dedup state, `OATS_TRIGGER_EVENT_FILE`, `oats trigger …`, package trigger templates, feature `triggers`.
|
|
335
|
+
3. **Remove capability agents** (after okf 4.0.0 is mirrored): `agents:` in manifests is refused with a remedy naming package souls.
|
|
336
|
+
|
|
337
|
+
Gates:
|
|
338
|
+
- test-first;
|
|
339
|
+
- scaffold-only probes;
|
|
340
|
+
- a real `gh` poll against a scratch repo in the PR's evidence;
|
|
341
|
+
- the full glob + `smoke:tarball` (kernel dev).
|
|
342
|
+
|
|
343
|
+
**L2, okf** (oats-okf; **the okf expert**, a new `integrations-expert` instance, or the 3.0.0 child continuing once 3.0.0 is tagged, lead's pick; the co-lead reviews and tags):
|
|
344
|
+
- the three capabilities (§2.1);
|
|
345
|
+
- the skill rework:
|
|
346
|
+
- rename memory-harvest → knowledge-theory;
|
|
347
|
+
- new knowledge-harvest, knowledge-review, okf-instance-knowledge, okf-trigger-setup;
|
|
348
|
+
- okf → okf-authoring;
|
|
349
|
+
- the two package souls;
|
|
350
|
+
- the trigger template `harvest-review`;
|
|
351
|
+
- the harvester lifecycle (spawn as a soul, stay alive, retire on merge);
|
|
352
|
+
- the provenance block (C3);
|
|
353
|
+
- the inject (§2.5);
|
|
354
|
+
- the identical-copy test;
|
|
355
|
+
- no symlinks.
|
|
356
|
+
|
|
357
|
+
Gate: **a real end-to-end run** against a scratch KB repo: a source is harvested → the PR opens with provenance → the trigger spawns the maintainer → it amends + merges → the harvester retires. Every step is read back. It requires kernel ≥ 0.28.0.
|
|
358
|
+
|
|
359
|
+
**L3, onboarding** (oats.framework `oats-setup`; **the Phase D driver** `oats-expert-phase-d`):
|
|
360
|
+
- `oats-onboarding` gains "Knowledge operations with OKF":
|
|
361
|
+
- the package pin;
|
|
362
|
+
- the `okf` team + mapping;
|
|
363
|
+
- where to install the trigger (a host with merge-capable credentials; `oats trigger add --from oats.okf:harvest-review`; `oats trigger test`);
|
|
364
|
+
- harvest stays opt-in.
|
|
365
|
+
- `docs/knowledge.md`, `docs/schedules.md` (triggers) and `docs/packages.md` (package souls) get updated.
|
|
366
|
+
- A framework 1.2.0 PR.
|
|
367
|
+
|
|
368
|
+
**L4, Desktop (later):** a Triggers section under the deployment (list, status, test, enable/disable), and package souls on the Souls page with their package origin.
|
|
369
|
+
|
|
370
|
+
**Review:**
|
|
371
|
+
- The lead reviews L1 and L3 and cross-reviews L2.
|
|
372
|
+
- The co-lead reviews and tags L2 and cross-reviews L1.
|
|
373
|
+
- The release: 0.28.0 = L1 + the L2 mirror/pin + L3 pin.
|
|
374
|
+
|
|
375
|
+
## 4. Decisions taken (lead, delegated authority), revisit on request
|
|
376
|
+
|
|
377
|
+
1. **Package souls, not `external:`**, for "sourced from the okf package". One pin versions everything.
|
|
378
|
+
2. **Triggers are schedules of `kind: trigger`**: the same store, tick and spawn path. There's no daemon and no webhook in v1.
|
|
379
|
+
3. **The harvester becomes a package soul** (it needs messaging + a lifetime past its PR). Capability agents are removed after okf 4.0.0.
|
|
380
|
+
4. **The maintainer merges autonomously** when the doctrine passes, **except** where it would supersede a human-accepted decision (`okf-needs-human`).
|
|
381
|
+
5. **The harvester and the maintainer hold no knowledge slot in v1** (no recursive harvest). Revisit when a maintainer's own lessons are wanted.
|
|
382
|
+
6. **okf 3.0.0 is not widened.** The working-soul skill split lands in 4.0.0 with the new capabilities. Removing `memory-harvest` from oats.okf before the harvester has another home would break harvest.
|
|
383
|
+
7. **Harvest stays OFF on the development deployment** until 0.28.0 + okf 4.0.0 pass the end-to-end gate.
|
|
384
|
+
|
|
385
|
+
## 5. Open questions
|
|
386
|
+
|
|
387
|
+
- The maintainer's `work` mode: `directory` + `gh pr checkout` (planned) vs a registered KB clone in worktree mode. The L2 implementer confirms in the first PR.
|
|
388
|
+
- Multi-base PRs: v1 keeps one base per PR (today's delivery). The maintainer's cross-base supersession is out of scope.
|
|
389
|
+
- `aweb.mail` as a trigger source (e.g. "on a mail to `okf-review`") is left for after v1.
|