@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
package/docs/desktop-cli-api.md
CHANGED
|
@@ -54,6 +54,18 @@ something to say. The one warning so far is `deprecated-runtime-name` (see
|
|
|
54
54
|
--json`, whose document is not an envelope, carries the same `warnings` beside
|
|
55
55
|
its `problems`. In text mode the warning is one `oats: warning: …` line on stderr.
|
|
56
56
|
|
|
57
|
+
## Flags
|
|
58
|
+
|
|
59
|
+
A kernel command reads `--flag=value` exactly as `--flag value`, with the
|
|
60
|
+
same validation (0.27.3+; before, the inline form was silently ignored, so
|
|
61
|
+
`--harness=claude` spawned the default harness). The value is everything after
|
|
62
|
+
the first `=`. An empty `--flag=` is `E_BAD_ARGS` ("`--flag=` needs a value"),
|
|
63
|
+
and so is a value on a switch: `--yolo=false` is refused and never turns
|
|
64
|
+
yolo on. A capability command's own flags belong to its provider. They are
|
|
65
|
+
forwarded exactly as typed; the kernel reads only its dispatch flag (`--soul`)
|
|
66
|
+
in either form. There is no feature string: a caller that must work with
|
|
67
|
+
older kernels uses the spaced form.
|
|
68
|
+
|
|
57
69
|
## The harness rename (feature `harness`, OATS 0.27.0)
|
|
58
70
|
|
|
59
71
|
What starts an instance (pi, claude or codex) is its **harness**. 0.27.0 renames
|
|
@@ -84,7 +96,7 @@ routed commands (`--server`) already translate for such a host, sending
|
|
|
84
96
|
| `oats inspect --json` `souls[]` rows, remote roster rows | `runtime` | `harness` | Output only; a pre-0.27 host's `runtime` rows are read as `harness` |
|
|
85
97
|
| `oats inspect --home --json` `instance` | `runtime` | `harness` | Output only |
|
|
86
98
|
| The launch plan's package check (`launch-config preview` `problems[]`) | `runtime-packages` | `harness-packages` | Output only |
|
|
87
|
-
| Soul `soul.yaml` (member
|
|
99
|
+
| Soul `soul.yaml` (member and package souls) | `runtime:` | `harness:` | Yes, **without** a warning: released capabilities (oats.aweb 1.13.1) ship `runtime:`, and the operator cannot fix a provider's file. Both, disagreeing → `E_BAD_MANIFEST` |
|
|
88
100
|
| `oats-local.yaml` `launch-configs.<name>` | `runtime:` | `harness:` | Yes, with the warning. Both, disagreeing → `E_WORKSPACE_SCHEMA`. `launch-config set` writes `harness` (a `runtime` in its `--file` definition too) |
|
|
89
101
|
| `launch-config list/preview --json` rows and `selection` | `runtime` | `harness` | Output only |
|
|
90
102
|
| Home `instance.json` | `runtime`; launch recipe `launch` version 1 `{runtime}` | `harness`; recipe version **2** `{harness}` | Yes, with the warning naming the home: a 0.26.0 home inspects, starts, restarts and retires; its next start or restart records the new names |
|
|
@@ -241,6 +253,8 @@ payload the spawn recorded for a home, or the resolution computes for a soul.
|
|
|
241
253
|
- `operations[].available` is `false` with a `reason` when it cannot run
|
|
242
254
|
here: a `context: "home"` operation for a soul subject says `needs a
|
|
243
255
|
running home (--home)`.
|
|
256
|
+
- `capabilities[].composedFrom` and `capabilitiesOff[]` (feature
|
|
257
|
+
`desktop-facts`): see [Desktop facts](#desktop-facts-feature-desktop-facts-oats-0290).
|
|
244
258
|
- `instance` is `null` for a soul. For a home, `instructions.sources` names
|
|
245
259
|
each composed inject in order.
|
|
246
260
|
- A soul whose resolution is refused (for example, a package the lock does
|
|
@@ -388,7 +402,8 @@ on stdout:
|
|
|
388
402
|
```
|
|
389
403
|
|
|
390
404
|
The environment is the provider's module environment:
|
|
391
|
-
- `OATS_CAPABILITY`, `OATS_SETTINGS`, `
|
|
405
|
+
- `OATS_CAPABILITY`, `OATS_SETTINGS`, `OATS_SETTINGS_ORIGINS` (0.29.0: JSON
|
|
406
|
+
pointer → `{ kind, at }`), `OATS_CLI_BIN` and `OATS_WORKSPACE`;
|
|
392
407
|
- the team variables (`OATS_TEAM_*`, `OATS_WORKSPACE_NAME`/`_KEY`);
|
|
393
408
|
- `OATS_AGENT` (the soul), and `OATS_SOUL` when the soul directory is known;
|
|
394
409
|
- for a home, `OATS_INSTANCE` and `OATS_INSTANCE_HOME`.
|
|
@@ -667,7 +682,7 @@ unchecked, echoed a stored `definition.id` without checking it, and named a
|
|
|
667
682
|
```
|
|
668
683
|
|
|
669
684
|
**Exact shapes (API 3):**
|
|
670
|
-
- `schedule list --json` → `result = {scope, scheduleApi: 2, scheduleHistoryApi: 3, integrity, schedules: Entry[], scheduler}
|
|
685
|
+
- `schedule list --json` → `result = {scope, scheduleApi: 2, scheduleHistoryApi: 3, integrity, schedules: Entry[], triggers: {count, command: "oats trigger list"}, scheduler}` (`triggers`, 0.28.0: the trigger definitions this listing leaves out).
|
|
671
686
|
- `schedule show <id> --json` → `result = {schedule: Entry}` (one level of nesting; `integrity` is NOT on `show` — it is a scope fact reported by `list`).
|
|
672
687
|
- `Entry` (readable) = definition fields (`id, kind, home, message|operation, cron, enabled, …`) + `{scope, scheduleApi: 2, scheduleHistoryApi: 3, executionStatus, nextRun: ISO|null, lastRun: Run|null, history, recentRuns: Run[], running: boolean, attempt?, pendingWake?}`.
|
|
673
688
|
- `Entry` (unreadable, `list` only) = `{id, scope, scheduleApi: 2, scheduleHistoryApi: 3, unreadable: {code, message}, history: {status: "corrupt", stored: null, truncated: false}, recentRuns: []}` — no definition fields.
|
|
@@ -743,7 +758,7 @@ the pre-fix marker and is never accepted for dispatch.
|
|
|
743
758
|
`agents/<soul>/soul` pointer. (0.25.x previews populated the cache: that stated
|
|
744
759
|
exception is gone.)
|
|
745
760
|
- **Exact root**: `spawn <soul> --agents-root <abs>` binds the soul to that root
|
|
746
|
-
(as inspect/readiness take it) — no team-soul /
|
|
761
|
+
(as inspect/readiness take it) — no team-soul / importable-
|
|
747
762
|
def fallback; mismatch → `E_SOUL_UNKNOWN`. The preview echoes
|
|
748
763
|
`subject {soul, agentsRoot|null, dir|null}` **as given, byte-exact**.
|
|
749
764
|
- **Decision binding**: `decision {instance, home, branch, base{ref,oid},
|
|
@@ -1115,8 +1130,8 @@ gate that on the absence of `packages-no-approval`.
|
|
|
1115
1130
|
"souls":["tools-expert"],"capabilities":["acme-tools-dev"],"publishes":{"package":"acme.tools","version":"0.4.0"}},
|
|
1116
1131
|
{"key":"github.com/acme/billing","name":"billing","commit":"<oid>","confirmed":false,"status":"no-backlink","detail":"github.com/acme/billing@… has no oats-membership.yaml","team":null,
|
|
1117
1132
|
"souls":[],"capabilities":[],"publishes":null}],
|
|
1118
|
-
"packages":[{"id":"oats.okf","version":"2.1.3","source":"catalog:oats.okf","commit":"<oid>","integrity":"sha256-…","capabilities":["oats.okf"]},
|
|
1119
|
-
{"id":"acme.tools","version":"0.4.0","source":"git:github.com/acme/tools@v0.4.0","commit":"<oid>","integrity":"sha256-…","capabilities":["acme-deploy","acme-lint"]}],
|
|
1133
|
+
"packages":[{"id":"oats.okf","version":"2.1.3","source":"catalog:oats.okf","commit":"<oid>","integrity":"sha256-…","capabilities":["oats.okf"],"souls":[]},
|
|
1134
|
+
{"id":"acme.tools","version":"0.4.0","source":"git:github.com/acme/tools@v0.4.0","commit":"<oid>","integrity":"sha256-…","capabilities":["acme-deploy","acme-lint"],"souls":["release-reviewer"]}],
|
|
1120
1135
|
"changes":[{"id":"acme.tools","from":null,"to":"0.4.0","commit":"<oid>"}],
|
|
1121
1136
|
"problems":[]}
|
|
1122
1137
|
```
|
|
@@ -1125,6 +1140,8 @@ gate that on the absence of `packages-no-approval`.
|
|
|
1125
1140
|
`backlink-elsewhere` | `cannot-read`; `detail` explains an unconfirmed row.
|
|
1126
1141
|
`publishes` reports a member's `oats-package/` (informational — its
|
|
1127
1142
|
capabilities are **not** in `capabilities[]`; the non-collapse rule).
|
|
1143
|
+
- `packages[].souls` (feature `package-souls`, 0.28.0): the names of the
|
|
1144
|
+
package souls the lock records for that package (`[]` when none).
|
|
1128
1145
|
- `changes[]`: `from` = previously locked version or `null`; `to` = `null` when
|
|
1129
1146
|
the package was dropped from `packages:` and from the lock.
|
|
1130
1147
|
- `problems[]`: `{ code, path, message, repoKey? }` — per-item discovery
|
|
@@ -1176,6 +1193,9 @@ souls, paths, message }` — one `unmapped-team-label` per label that is in
|
|
|
1176
1193
|
`teams:` but not in `messaging.byTeam`, naming its souls (sorted) and each
|
|
1177
1194
|
soul's `<repoKey>:<path>#/team`; sorted by label. Never a problem.
|
|
1178
1195
|
|
|
1196
|
+
`defaults`, `clones`, `disabledSouls`, `lock`, file locations and
|
|
1197
|
+
`packages[].latest` (feature `desktop-facts`): see [Desktop facts](#desktop-facts-feature-desktop-facts-oats-0290).
|
|
1198
|
+
|
|
1179
1199
|
`unsynced` = declared in `packages:` but not in the lock (run `sync`);
|
|
1180
1200
|
`stale` = locked but no longer declared. Read-only: does not write the lock.
|
|
1181
1201
|
(0.26.0: the `approval` object is gone with package approval.)
|
|
@@ -1207,10 +1227,27 @@ or `"unassigned"`.
|
|
|
1207
1227
|
"souls":[
|
|
1208
1228
|
{"name":"release-manager","origin":"member github.com/acme/agents @ 3f2a9c1e","kind":"member","repoKey":"github.com/acme/agents","commit":"<oid>",
|
|
1209
1229
|
"team":"engineering","private":false,"path":"souls/release-manager","work":"worktree","description":"Cuts, verifies and announces releases."},
|
|
1210
|
-
{"name":"security-reviewer","origin":"external github.com/oss-collective/experts @ 9c4e1f2a","kind":"external",…}
|
|
1230
|
+
{"name":"security-reviewer","origin":"external github.com/oss-collective/experts @ 9c4e1f2a","kind":"external",…},
|
|
1231
|
+
{"name":"release-reviewer","qualifiedName":"acme.tools/release-reviewer","origin":"package acme.tools v0.4.0","kind":"package","package":"acme.tools","version":"0.4.0",
|
|
1232
|
+
"repoKey":"github.com/acme/tools","commit":"<oid>","team":"engineering","labels":["engineering"],"private":false,"path":"oats-package/souls/release-reviewer","work":"directory","description":"…"}],
|
|
1211
1233
|
"problems":[]}
|
|
1212
1234
|
```
|
|
1213
1235
|
|
|
1236
|
+
**Package souls** (feature `package-souls`, 0.28.0): a row with `kind:
|
|
1237
|
+
"package"` is a soul a locked package ships (listed only while the workspace
|
|
1238
|
+
declares the package). It carries `package`, `version` and `qualifiedName`
|
|
1239
|
+
(`<package>/<soul>`); spawn it by `qualifiedName` (the bare `name` works when
|
|
1240
|
+
it is unique). The Souls page shows it as "from package <id> <version>".
|
|
1241
|
+
Its instances home under `agents/<package>--<soul>/` (`.` in the package id
|
|
1242
|
+
becomes `-`), and that directory is the agent `name` in `oats status --json`
|
|
1243
|
+
(`agents[].name`, e.g. `oats-okf--knowledge-maintainer`). A
|
|
1244
|
+
problem about a package soul carries `package` (and `repoKey: null`); its
|
|
1245
|
+
`path` is `package:<id>:<path in the repo>`.
|
|
1246
|
+
|
|
1247
|
+
Souls rows' defaults, spawnability and `file`, and capability rows' `layer`,
|
|
1248
|
+
`description`, provides, `file` and `tree` (feature `desktop-facts`): see
|
|
1249
|
+
[Desktop facts](#desktop-facts-feature-desktop-facts-oats-0290).
|
|
1250
|
+
|
|
1214
1251
|
Package capabilities of declared-but-unsynced packages are absent until `sync`.
|
|
1215
1252
|
(`oats souls --json` keeps `soulsApi: 1` in 0.26.0: its shape is unchanged.
|
|
1216
1253
|
The probe's `soulsApi` is **2** because it tracks the `oats inspect --json`
|
|
@@ -1261,9 +1298,13 @@ between preview and apply is `E_DECISION_STALE`):
|
|
|
1261
1298
|
key**: legal only at the top level of the workspace file's `messaging:`;
|
|
1262
1299
|
anywhere else in any payload layer (soul, `oats-local.yaml` `settings`,
|
|
1263
1300
|
`--provider`, at any depth) it is `E_WORKSPACE_SCHEMA { reason: "reserved-key", path, key }`.
|
|
1264
|
-
- Soul lookup: `E_SOUL_UNKNOWN { name, members[] }` (not among
|
|
1265
|
-
members or
|
|
1266
|
-
|
|
1301
|
+
- Soul lookup: `E_SOUL_UNKNOWN { name, members[], packages[] }` (not among
|
|
1302
|
+
confirmed members, externals or package souls), `E_SOUL_AMBIGUOUS { name,
|
|
1303
|
+
repos[], qualified[] }` (name one of `qualified`: `<member>/<soul>` or
|
|
1304
|
+
`<package>/<soul>`), `E_SOUL_DISABLED { name, qualifiedName, entry }` (the
|
|
1305
|
+
soul is in `oats-local.yaml` `souls.disabled`). A package soul whose fetched
|
|
1306
|
+
content does not match the lock is `E_PACKAGE_INTEGRITY { why:
|
|
1307
|
+
"soul-digest", package, soul, locked, observed }`. Resolution errors keep their codes (`E_NOT_A_MEMBER`,
|
|
1267
1308
|
`E_MEMBERSHIP_UNCONFIRMED { repoKey, reason }`, `E_CAPABILITY_MISSING { hint? }`,
|
|
1268
1309
|
`E_CAPABILITY_PRIVATE`, `E_PACKAGE_MISSING`, `E_PACKAGE_INTEGRITY { why: "capabilities", listed, locked }`,
|
|
1269
1310
|
`E_SLOT_CONFLICT { slot, modules[], reason? }`, `E_SKILL_DUPLICATE { name, modules[] }`,
|
|
@@ -1286,6 +1327,7 @@ Written by materialization inside the spawn transaction; read back by
|
|
|
1286
1327
|
"providers":{"acme-release-tooling":{},"oats.okf":{"owns":"release-manager","reads":["platform-engineer"],"state-dir":"/Users/ana/.oats/okf"}},
|
|
1287
1328
|
"workspace":{"key":"github.com/acme/agents","name":"acme","deployment":"/Users/ana/acme-workspace","commit":"<oid>","resolution":"<24 hex>","standalone":false,
|
|
1288
1329
|
"soul":{"repoKey":"github.com/acme/agents","commit":"<oid>","team":"engineering"}},
|
|
1330
|
+
"…":"a package soul's workspace.soul also records package: {id, version, commit, digest, path}, and its id is package:<id>#<soul>",
|
|
1289
1331
|
"capabilities":[{"id":"oats.okf","capability":"oats.okf","origin":"package:oats.okf@2.1.3","…":"one row per module"}]}
|
|
1290
1332
|
```
|
|
1291
1333
|
|
|
@@ -1341,6 +1383,296 @@ top-level `workspace` reachability field:
|
|
|
1341
1383
|
`oats-local.yaml` has no `workspace` field and `modules` as recorded.
|
|
1342
1384
|
- Text mode prints `modules: <cap> from <member|package …> @ <7-char>` lines
|
|
1343
1385
|
for non-current modules (`--verbose` for all).
|
|
1386
|
+
- `instances[].soul` is the soul source's drift: `{ repoKey, commit, current,
|
|
1387
|
+
status, reason? }`. For a **package soul** (feature `package-souls`) it also
|
|
1388
|
+
carries `package`, `version` and `currentVersion`; `moved` means the package
|
|
1389
|
+
pin moved (another version/commit is locked now), `missing` has `reason`
|
|
1390
|
+
`package-absent` (no longer locked or declared) or `soul-absent` (the locked
|
|
1391
|
+
package no longer ships it). Text: `soul: <name> from package <id> v<version>
|
|
1392
|
+
@ <7-char> [package moved since (now v<version> @ <7-char>)]`.
|
|
1393
|
+
|
|
1394
|
+
### Triggers (feature `triggers`, OATS 0.28.0) — `oats trigger … --json` → `triggerApi: 1`
|
|
1395
|
+
|
|
1396
|
+
Event-driven spawns of a deployment ([schedules.md#triggers](schedules.md#triggers)).
|
|
1397
|
+
Definitions live in `oats-schedules.json` (`kind: "trigger"`); `oats schedule list`
|
|
1398
|
+
does not show them. From 0.29.0 a row's `id` is qualified (`local/<id>` here; a
|
|
1399
|
+
workspace trigger's is `<member>/<id>`) and the row carries the shared fields of
|
|
1400
|
+
[workspace triggers and schedules](#workspace-triggers-and-schedules-feature-automations-oats-0290-automationsapi-1).
|
|
1401
|
+
|
|
1402
|
+
```json
|
|
1403
|
+
{"triggerApi":1,"scope":"/abs/deployment","triggers":[
|
|
1404
|
+
{"id":"okf-harvest-review","enabled":true,"kind":"trigger",
|
|
1405
|
+
"on":{"source":"github.pull_request","repo":"github.com/acme/knowledge","events":["opened","reopened","ready_for_review"],"labels":["okf-harvest"],"base":"main","poll":"2m"},
|
|
1406
|
+
"spawn":{"soul":"oats.okf/knowledge-maintainer","purpose":"review-pr-{number}","task":"…","teams":["okf"],"launchConfig":"reviewers","harness":"claude","model":"opus"},
|
|
1407
|
+
"concurrency":{"max":2,"perKey":1},"template":{"package":"oats.okf","version":"4.0.0","commit":"<oid>","template":"harvest-review"},
|
|
1408
|
+
"triggerApi":1,"scope":"/abs/deployment","createdAt":"<iso>","updatedAt":"<iso>"}]}
|
|
1409
|
+
```
|
|
1410
|
+
|
|
1411
|
+
- `list` → the document above; `show <id>`, `add`, `enable`, `disable` →
|
|
1412
|
+
`{ trigger }` (one row); a stored definition that no longer validates carries
|
|
1413
|
+
`invalid: { code, message }`. `remove <id>` → `{ removed, live: [instance] }`.
|
|
1414
|
+
- `status [<id>]` → `{ triggerApi, scope, triggers: [Status] }`. It writes
|
|
1415
|
+
nothing. Each `Status`:
|
|
1416
|
+
- `id`, `name`, `enabled`, `runsHere`, `reason`, `enabledHere`, `repo`, `soul` (the soul name);
|
|
1417
|
+
- `concurrency: { max, perKey }` and `liveCount`: live instances against `max`;
|
|
1418
|
+
`live: [{ instance, home, repo, number, event }]`;
|
|
1419
|
+
- `lastPoll: { at, ok: true, prs, matching } | { at, ok: false, error } | null`;
|
|
1420
|
+
`nextPollAt`; `nextDue` (the next poll when it runs here, else `null`);
|
|
1421
|
+
- `pending: [{ key, event, number, url, observedAt }]`: observed, not yet spawned
|
|
1422
|
+
(held, or its spawn failed);
|
|
1423
|
+
- `fired: [{ key, at, instance, home, event, number }]` (newest 50) and `firedTotal`;
|
|
1424
|
+
- `lastError: { at, code, message, key? } | null`.
|
|
1425
|
+
- `test <id>` → `{ triggerApi, id, ok, gh: { ok, account, credentialSource:
|
|
1426
|
+
"keyring" | "config" | "env:<VAR>" | "unknown" | null, reachesHostTimer:
|
|
1427
|
+
boolean | null, note, detail }, repo: { key,
|
|
1428
|
+
readable, fullName, permissions: { push, maintain, admin }, canMerge } |
|
|
1429
|
+
{ key, readable: false, error }, soul: { resolves, name, agent, messaging } |
|
|
1430
|
+
{ resolves: false, name, error }, teams: { requested, undeclared | null,
|
|
1431
|
+
messaging }, wouldFire: [{ key, repo, number, event, url, held? }], pollError?, problems:
|
|
1432
|
+
[string], warnings: [string], spawned: false }`. It writes nothing. `ok`
|
|
1433
|
+
counts `problems` only; a credential the host timer cannot reach
|
|
1434
|
+
(`reachesHostTimer: false`) is a warning.
|
|
1435
|
+
- `oats schedule list --json` gains `triggers: { count, command: "oats trigger
|
|
1436
|
+
list" }`: the triggers it does not list.
|
|
1437
|
+
- The tick's `considered[]` gains trigger rows `{ workspace, trigger, action,
|
|
1438
|
+
… }` with `action` `not-due`, `poll-failed`, `polled` (`prs`, `matching`;
|
|
1439
|
+
nothing to fire), `held`, `fired` (`key`,
|
|
1440
|
+
`instance`, `home`), `spawn-failed` (`key`, `code`, `error`), `would-fire`
|
|
1441
|
+
(`--dry-run`) or `invalid`.
|
|
1442
|
+
- A triggered instance's `instance.json.trigger` is `{ id, key, source, repo,
|
|
1443
|
+
number, url, event, headSha, observedAt, eventFile }`; the event file is
|
|
1444
|
+
`OATS_TRIGGER_EVENT_FILE`.
|
|
1445
|
+
- Errors: `E_TRIGGER_INVALID { field }`, `E_TRIGGER_EXISTS`,
|
|
1446
|
+
`E_TRIGGER_UNKNOWN`, `E_BAD_ARGS` (`missing` / `parameters` for a template),
|
|
1447
|
+
`E_PACKAGE_MISSING`, `E_PACKAGE_MANIFEST`, `E_LOCAL_MISSING`.
|
|
1448
|
+
|
|
1449
|
+
### Workspace triggers and schedules (feature `automations`, OATS 0.29.0; `automationsApi: 1`)
|
|
1450
|
+
|
|
1451
|
+
See [schedules.md#workspace-triggers-and-schedules](schedules.md#workspace-triggers-and-schedules).
|
|
1452
|
+
`oats trigger list --json` and `oats schedule list --json` answer this machine's
|
|
1453
|
+
local items and every workspace item defined in a member the user can read. The
|
|
1454
|
+
Desktop renders these rows and never re-derives them. The two lists stay separate:
|
|
1455
|
+
a trigger never appears in `schedule list`, and a schedule never appears in
|
|
1456
|
+
`trigger list`.
|
|
1457
|
+
|
|
1458
|
+
- Both lists add:
|
|
1459
|
+
- `host: { name | null, ghUser: { <gh host>: <login> | null } }`: this machine's
|
|
1460
|
+
`oats-local.yaml` `host.name`, and who its `gh` is logged in as on every GitHub
|
|
1461
|
+
host the rows name (the owners'; a trigger's repository's) — `null` when `gh`
|
|
1462
|
+
is not authenticated there. The Desktop compares it with a row's `owner`.
|
|
1463
|
+
- `snapshot: { takenAt, problems } | null` (`null` until `oats sync` has found some).
|
|
1464
|
+
- `scheduler: { installed, active, registered, lastTick, maxConcurrent, … }`: the
|
|
1465
|
+
host tick (the same object as `oats schedule host status`). Nothing runs unless
|
|
1466
|
+
it is installed, active and this deployment is registered.
|
|
1467
|
+
- **Identity:**
|
|
1468
|
+
- `id`:
|
|
1469
|
+
- a trigger row's is always qualified (`local/<id>`, `<member>/<id>`);
|
|
1470
|
+
- a local schedule row keeps its bare id (the 0.28 contract);
|
|
1471
|
+
- a workspace schedule row's is `<member>/<id>`.
|
|
1472
|
+
- `qualifiedId` is always the qualified form, and `name` is the bare id.
|
|
1473
|
+
- Every verb accepts `local/<id>` or a bare local id.
|
|
1474
|
+
- **Shared fields in every row:**
|
|
1475
|
+
- `origin`: where the item is defined, and where to open it:
|
|
1476
|
+
- `{ kind: "local", path: "oats-schedules.json", url: null, localPath }`;
|
|
1477
|
+
- `{ kind: "workspace", repoKey, path, commit, url, localPath }`: `url` is the
|
|
1478
|
+
file's web URL at `commit` (`https://github.com/<owner>/<repo>/blob/<commit>/<path>`
|
|
1479
|
+
for a `github.com` member, else `null`); `localPath` is the file in this
|
|
1480
|
+
machine's clone of the member (`null` when the member is not cloned here).
|
|
1481
|
+
- `description`, `owner`, `runsOn`;
|
|
1482
|
+
- `runsHere`; `reason` (`null` | `host-unnamed` | `assigned-elsewhere` | `owner-mismatch`) with `reasonDetail`;
|
|
1483
|
+
- `enabledHere`;
|
|
1484
|
+
- `soul`: `{ name, origin } | null` (`null` for a command, wake or operation schedule). `origin` is where the name resolves, per the snapshot:
|
|
1485
|
+
- `{ kind: "member", repoKey, member }`: a soul in a workspace member;
|
|
1486
|
+
- `{ kind: "package", package, version }`: a soul of a locked package;
|
|
1487
|
+
- `{ kind: "external", repoKey, source }`: an external soul (`source` is the workspace's `external[].source` ref);
|
|
1488
|
+
- `{ kind: "ambiguous", candidates }`: a bare name several souls answer to (`candidates` is how many); a spawn needs the qualified name;
|
|
1489
|
+
- `null`: not found (or no snapshot yet).
|
|
1490
|
+
- `task`: the template, verbatim;
|
|
1491
|
+
- `teams`, `launchConfig`, `harness`, `model`, `concurrency`;
|
|
1492
|
+
- `lastRun`, `nextDue`;
|
|
1493
|
+
- `invalid?: { code, message, field? }`.
|
|
1494
|
+
- **A trigger row** also carries `kind: "trigger"`, `on`, `spawn`, and `template?`:
|
|
1495
|
+
- `on: { source: "github.pull_request", repo: "<host>/<owner>/<repo>", events: [opened | reopened | ready_for_review | labeled | synchronize], labels: [string], base?: string, poll: "<n>s|m|h" }` (`base` absent: any base branch);
|
|
1496
|
+
- `spawn: { soul, purpose, task, teams: [label], launchConfig?, harness?, model?, yolo?, backend? }`
|
|
1497
|
+
(`purpose` and `task` are templates over `{repo}`, `{number}`, `{url}`, `{event}`, `{trigger}`, `{headSha}`;
|
|
1498
|
+
`launchConfig` names a launch configuration in the running host's `oats-local.yaml`);
|
|
1499
|
+
- `template?: { package, version, commit, template }`: the package template it was added from.
|
|
1500
|
+
- `lastRun` is the last fired event: `{ at, instance, home, event, number, key }`.
|
|
1501
|
+
- `nextDue` is the next poll, only when it runs here; `null` before its first poll (it polls at the next tick).
|
|
1502
|
+
- **A schedule row** keeps every 0.28 field (`scheduleApi: 2`). Its `kind` is the run (`spawn` | `command` | `wake` | `operation`); it also carries `cron` and `tz`.
|
|
1503
|
+
- `nextDue` is the next minute, only when it runs here.
|
|
1504
|
+
- `teams` is `[]` and `concurrency` is `null`.
|
|
1505
|
+
- A workspace schedule another host runs carries its definition and placement only: `lastRun` and `nextDue` are `null`.
|
|
1506
|
+
- A spawn schedule's `launchConfig` names a launch configuration in the running host's `oats-local.yaml`.
|
|
1507
|
+
- **Naming:** `nextDue` is the one name for "when it next runs" in every trigger and
|
|
1508
|
+
schedule row. A schedule row still carries the 0.24 `nextRun` for older readers;
|
|
1509
|
+
they agree whenever it runs here.
|
|
1510
|
+
- **Actions:**
|
|
1511
|
+
- `enable` and `disable` on a workspace id edit `oats-local.yaml` `triggers.disabled` or `schedules.disabled`.
|
|
1512
|
+
- `update` and `remove` refuse it with `E_AUTOMATION_WORKSPACE { id, origin }`.
|
|
1513
|
+
- `schedule run` and `schedule reconcile` work when it runs here, else `E_AUTOMATION_NOT_HERE { id, reason, runsOn, owner }`.
|
|
1514
|
+
- **`oats trigger test <id>`** adds `placement: { runsOn, owner, host, runsHere, reason, detail?, enabledHere }`. Any reason, or disabled here, is a problem (`ok: false`).
|
|
1515
|
+
- **`oats schedule test <id> --json`** (local or workspace) → `{ test: { id, qualifiedId, kind,
|
|
1516
|
+
placement: { runsHere, reason, reasonDetail?, enabledHere, runsOn, owner, host },
|
|
1517
|
+
soul: { name, origin, resolves, error: { code, message } | null } | null, nextDue,
|
|
1518
|
+
spawned: false, problems: [string], ok } }`. `soul` is checked the way the run
|
|
1519
|
+
would start it (`oats spawn <soul> --preview`, which writes nothing); it is `null`
|
|
1520
|
+
for a command, wake or operation. `nextDue` is the next cron match whether or not
|
|
1521
|
+
this host runs it (`placement` says that). Not running here, disabled, invalid or a
|
|
1522
|
+
soul that does not resolve is a problem (`ok: false`). It spawns nothing and records
|
|
1523
|
+
nothing. Errors: `E_SCHEDULE_UNKNOWN`, `E_BAD_ARGS`.
|
|
1524
|
+
- **`oats trigger|schedule add … --workspace <member> --runs-on <host> --owner <host>/<login> --json`** answers `{ id, written, file: { member, repoKey, path, content, written? } }`.
|
|
1525
|
+
- Errors: `E_AUTOMATION_MEMBER` (not a confirmed member), `E_TRIGGER_EXISTS` or `E_SCHEDULE_EXISTS` (the file exists), and the kind's validation codes.
|
|
1526
|
+
- **`oats automations refresh --json`** answers `{ automationsApi, snapshot, triggers, schedules, problems: [...], takenAt }`.
|
|
1527
|
+
- **`oats sync --json`** gains `automations: { triggers, schedules, problems, takenAt }`. Discovery problems join `problems` (`E_AUTOMATION_SCHEMA`, `E_AUTOMATION_DUPLICATE`, each with `kind`, `repoKey` and `path`).
|
|
1528
|
+
- **`oats workspace status --json`** gains `automations: { host, snapshot, rows: [{ kind, id, runsOn, owner, runsHere, reason, enabledHere, origin, invalid? }] }`.
|
|
1529
|
+
- **The tick's `considered[]`** gains the trigger action `not-here` (`reason: owner-mismatch`, `detail`): a trigger naming this host that this host cannot run. A workspace schedule's row `id` is its state key, `<member>~<id>`. A failed snapshot refresh is `{ action: "error", error: "automations refresh: …" }`.
|
|
1530
|
+
|
|
1531
|
+
### Desktop facts (feature `desktop-facts`, OATS 0.29.0)
|
|
1532
|
+
|
|
1533
|
+
These are facts the Workspace view shows. The kernel reports them so the
|
|
1534
|
+
Desktop never works them out itself. Gate reading every field below on
|
|
1535
|
+
`desktop-facts` in `features[]`. No API integer changes, and every field is an
|
|
1536
|
+
addition to an existing row.
|
|
1537
|
+
|
|
1538
|
+
**`oats inspect --soul <name> --json`: why each capability is there**
|
|
1539
|
+
|
|
1540
|
+
- `capabilities[].composedFrom` says which layer put the module in the soul:
|
|
1541
|
+
`"workspace"` (`defaults.<slot>` or `defaults.capabilities`),
|
|
1542
|
+
`"team:<label>"` (`defaults.byTeam.<label>.capabilities`) or `"soul"` (the
|
|
1543
|
+
soul's own `capabilities:`). This is the same vocabulary as
|
|
1544
|
+
`layers.<slot>.from`. It is `null` on `inspect --home`, because a spawn does
|
|
1545
|
+
not record it. `from` stays the module's origin object (`{kind, repoKey,
|
|
1546
|
+
commit}` or the package object), so it is a separate key.
|
|
1547
|
+
- `capabilitiesOff[]` lists the capabilities the soul turned off, which a
|
|
1548
|
+
lower layer would otherwise have given it. They are not rows of
|
|
1549
|
+
`capabilities[]`, because those are resolved modules with operations. Each
|
|
1550
|
+
entry is `{ id, off: true, from: "soul", reason, slot?, overrides }`:
|
|
1551
|
+
- `reason: "off"`: the soul wrote `<id>: off` over a workspace or team
|
|
1552
|
+
default.
|
|
1553
|
+
- `reason: "slot-none"`: the soul wrote `<slot>: none` (`slot` names it),
|
|
1554
|
+
which emptied the slot the workspace filled with `<id>`.
|
|
1555
|
+
- `overrides`: the layer whose default was turned off (`"workspace"` or
|
|
1556
|
+
`"team:<label>"`).
|
|
1557
|
+
- Sorted by id. `[]` on `inspect --home`.
|
|
1558
|
+
|
|
1559
|
+
**`oats souls --json` rows**
|
|
1560
|
+
|
|
1561
|
+
- `harness`, `model`, `harnessFrom`: what a spawn of the soul starts with
|
|
1562
|
+
when no `--harness`/`--model` is given. A v2 `soul.yaml` cannot declare a
|
|
1563
|
+
harness or a model, so today this is always `harness: "pi"`, `model: null`
|
|
1564
|
+
(the harness's native model) and `harnessFrom: "kernel-default"`.
|
|
1565
|
+
`harnessFrom: "soul"` is reserved for a schema that lets a soul declare
|
|
1566
|
+
one.
|
|
1567
|
+
- `spawnable`, `problem`: whether a spawn here would refuse.
|
|
1568
|
+
- `problem` is `{ code, message }` when a spawn would refuse, else `null`.
|
|
1569
|
+
- The kernel resolves the soul exactly as a spawn does, but spawns nothing,
|
|
1570
|
+
writes nothing and reads only the sync cache.
|
|
1571
|
+
- Codes: `E_SOUL_DISABLED` (this machine's `souls.disabled`),
|
|
1572
|
+
`E_TEAM_CONFLICT`, `E_CAPABILITY_MISSING`, `E_CAPABILITY_PRIVATE`,
|
|
1573
|
+
`E_CAPABILITY_INCOMPATIBLE`, `E_PACKAGE_MISSING`, `E_PACKAGE_INTEGRITY`,
|
|
1574
|
+
`E_LOCK_SCHEMA`, `E_REMOTE_*`, and any other resolution refusal.
|
|
1575
|
+
- An `E_TEAM_UNKNOWN` problem in `problems[]` is informational. It does not
|
|
1576
|
+
make a soul unspawnable.
|
|
1577
|
+
- `file`: `{ path, url }`, the soul's `soul.yaml` in its repository (see
|
|
1578
|
+
**URLs** at the end of this section).
|
|
1579
|
+
|
|
1580
|
+
**`oats capabilities --json` rows**
|
|
1581
|
+
|
|
1582
|
+
- `layer` on every row. Package rows now carry it too, from the package
|
|
1583
|
+
manifest; `null` for a capability outside the slots.
|
|
1584
|
+
- `description`: the manifest's `description`, or `null`.
|
|
1585
|
+
- `skills`, `commands`, `hooks`: what the capability provides, by name,
|
|
1586
|
+
sorted.
|
|
1587
|
+
- `skills` is enumerated as a spawn would. It is `null` when the declared
|
|
1588
|
+
skills cannot be listed, which a spawn of it would refuse.
|
|
1589
|
+
- `commands` and `hooks` are the keys of the manifest's `commands` and
|
|
1590
|
+
`hooks`.
|
|
1591
|
+
- `file`: `{ path, url }`, the capability's `oats.json`, or `null` when the
|
|
1592
|
+
manifest cannot be read.
|
|
1593
|
+
- `tree`: a member capability's fingerprint, the Git tree id of its
|
|
1594
|
+
directory at the member commit. The same bytes give the same id. It is
|
|
1595
|
+
`null` on package rows, whose fingerprint is `integrity` in the lock (see
|
|
1596
|
+
`oats workspace status`).
|
|
1597
|
+
- A package whose manifests cannot be read at its locked commit leaves these
|
|
1598
|
+
facts `null` on its rows.
|
|
1599
|
+
- Package manifests are read at the locked commit from the sync cache. There
|
|
1600
|
+
is no network beyond what `sync` already fetched.
|
|
1601
|
+
|
|
1602
|
+
**`oats workspace status --json`**
|
|
1603
|
+
|
|
1604
|
+
```json
|
|
1605
|
+
{"workspace":{"…":"…","file":{"path":"oats-workspace.yaml","url":"https://github.com/acme/agents/blob/<oid>/oats-workspace.yaml"}},
|
|
1606
|
+
"members":[{"…":"…","url":"https://github.com/acme/tools/tree/<oid>","membershipFile":{"path":"oats-membership.yaml","url":"https://github.com/acme/tools/blob/<oid>/oats-membership.yaml"}}],
|
|
1607
|
+
"packages":[{"id":"oats.okf","version":"3.0.0","source":"catalog:oats.okf","commit":"<oid>","…":"…","latest":{"version":"4.0.0","ref":"v4.0.0"}}],
|
|
1608
|
+
"defaults":{"slots":{"knowledge":{"name":"oats.okf","from":"package"},"messaging":"none","tasks":null},
|
|
1609
|
+
"capabilities":[{"name":"acme-house-style","from":"github.com/acme/agents","off":false}],
|
|
1610
|
+
"byTeam":{"engineering":{"capabilities":[{"name":"acme-house-style","from":null,"off":true},{"name":"acme-deploy","from":"package","off":false}]}}},
|
|
1611
|
+
"clones":[{"key":"github.com/acme/agents","name":"agents","path":"/abs/acme-workspace/agents","rule":"convention"},
|
|
1612
|
+
{"key":"github.com/acme/tools","name":"tools","path":null,"rule":null}],
|
|
1613
|
+
"disabledSouls":["release-reviewer"],
|
|
1614
|
+
"lock":{"path":"/abs/acme-workspace/oats-lock.json","lockfileVersion":3}}
|
|
1615
|
+
```
|
|
1616
|
+
|
|
1617
|
+
- `defaults`: the workspace file's defaults, as declared rather than
|
|
1618
|
+
resolved for a soul.
|
|
1619
|
+
- `slots.<slot>` is `{ name, from }` when the workspace fills it, `"none"`
|
|
1620
|
+
when it empties it, and `null` when it says nothing.
|
|
1621
|
+
- `capabilities` and `byTeam.<label>.capabilities` are rows `{ name, from,
|
|
1622
|
+
off }`, sorted by name. `from` is the declared location (`"package"`,
|
|
1623
|
+
`"here"` or a member repo key); an `off` row has `from: null`.
|
|
1624
|
+
- Standalone: slots `null`, `capabilities: []` and `byTeam: {}`.
|
|
1625
|
+
- `clones`: this computer's clone of each member.
|
|
1626
|
+
- `path` is the absolute clone, or `null` when this machine has none.
|
|
1627
|
+
- `rule` names what found it: `"clones"` (the `oats-local.yaml` `clones:`
|
|
1628
|
+
entry) or `"convention"` (`<deployment>/<member name>`). It is `null`
|
|
1629
|
+
with no clone.
|
|
1630
|
+
- A path that is not the member's clone gives `path: null, rule: null,
|
|
1631
|
+
problem: { code: "E_CLONE_MISMATCH", message }`, the refusal a spawn
|
|
1632
|
+
would meet.
|
|
1633
|
+
- (`--repo` is a spawn option, so it plays no part here.)
|
|
1634
|
+
- `disabledSouls`: `oats-local.yaml` `souls.disabled`, as written.
|
|
1635
|
+
- `lock`: `{ path, lockfileVersion }`. The per-package commit is each
|
|
1636
|
+
`packages[]` row's `commit`, and its fingerprint is `integrity`.
|
|
1637
|
+
- `packages[].latest`: `{ version, ref }` when the official catalog shipped
|
|
1638
|
+
with this kernel has a newer version of a catalog-sourced package than the
|
|
1639
|
+
lock holds. It is `null` when the pin is current and for `git:` packages.
|
|
1640
|
+
It never reaches the network: the catalog is the kernel's own
|
|
1641
|
+
(`OATS_PACKAGE_CATALOG` overrides it, as for `sync`).
|
|
1642
|
+
- `workspace.file` is `{ path, url }` for the workspace file in the
|
|
1643
|
+
workspace repository (at `workspace.key` @ `workspace.commit`). It is
|
|
1644
|
+
`null` for a standalone deployment.
|
|
1645
|
+
- `members[].url` is the member repository at its commit.
|
|
1646
|
+
`members[].membershipFile` is `{ path, url }`.
|
|
1647
|
+
|
|
1648
|
+
**`oats status --json` instance rows**
|
|
1649
|
+
|
|
1650
|
+
- A member module's `modules[].current` gains `version` (the capability's
|
|
1651
|
+
manifest version at the current commit, `null` when it has none) beside
|
|
1652
|
+
`commit`, on `current` and `moved` rows. Package rows already carried it. On a `moved` row, the recorded `commit`/`from` and `current`
|
|
1653
|
+
together say what moved and to what.
|
|
1654
|
+
- `startedAt`: the last session start or restart (the session receipt). A
|
|
1655
|
+
home spawned with a launch and never restarted uses `createdAt`. A home
|
|
1656
|
+
never launched is `null`. `createdAt` stays the spawn time.
|
|
1657
|
+
- `modelFrom`: where the model the home runs came from.
|
|
1658
|
+
- `"soul"`: the soul's model preference.
|
|
1659
|
+
- `"spawn"` or `"start"`: an explicit `--model` on that command.
|
|
1660
|
+
- `"launch-config"`: a launch configuration's model.
|
|
1661
|
+
- `"harness-default"`: the harness's own model.
|
|
1662
|
+
- A start that reuses the recorded model keeps the recorded answer.
|
|
1663
|
+
- `null` for a home spawned before 0.29.0. `instance.json` records it as
|
|
1664
|
+
`modelFrom`.
|
|
1665
|
+
- `identityAddress`: the messaging identity's `address` (else `alias`) that
|
|
1666
|
+
the messaging capability recorded (`capabilityMeta.<messaging>.identity`),
|
|
1667
|
+
passed through unchanged. `null` otherwise.
|
|
1668
|
+
|
|
1669
|
+
**URLs.** Every `url` is a browsable page of
|
|
1670
|
+
the file (or of the repository, for a member) at the commit the row names.
|
|
1671
|
+
Only repositories on `github.com` have one (`https://github.com/<org>/<repo>/blob/<commit>/<path>`,
|
|
1672
|
+
or `/tree/<commit>`). Every other host and local repository gives `url:
|
|
1673
|
+
null`, with `path` still set. `path` is relative to that repository's root.
|
|
1674
|
+
|
|
1675
|
+
**Help.** `oats help` lists `spawn … [--provider <capability> <key>=<value>]`.
|
|
1344
1676
|
|
|
1345
1677
|
### Eligible teams (feature `teams`, OATS 0.26.0)
|
|
1346
1678
|
|
package/docs/implementation.md
CHANGED
|
@@ -113,7 +113,7 @@ what they contribute stays with them.
|
|
|
113
113
|
|
|
114
114
|
After the canonical soul and kernel text, every generated `AGENTS.md` states the
|
|
115
115
|
runtime-neutral **home/work boundary** (`injects/instance-boundary.md`) — for
|
|
116
|
-
every work mode and for
|
|
116
|
+
every work mode and for service souls (the post-commit reviewer) alike — immediately before the
|
|
117
117
|
work-mode block it frames: `<instance-home>` (`$OATS_INSTANCE_HOME`) holds the
|
|
118
118
|
brain, task, provenance and working state, and is where OATS operational/lifecycle
|
|
119
119
|
commands are run from — together with the commands of whatever capabilities are
|
|
@@ -57,8 +57,14 @@ source. The current authoring-reference patch is package 1.0.1: once framework
|
|
|
57
57
|
v0.23.1 is published, an explicit initial Git acquisition at that tag selects
|
|
58
58
|
the patch instead. It does not silently change the catalog's 1.0.0 selection
|
|
59
59
|
or an existing lock. For local development, use an explicit complete source
|
|
60
|
-
package path instead. Activation
|
|
61
|
-
|
|
60
|
+
package path instead. Activation targets the authoring skill, without
|
|
61
|
+
selecting or replacing a knowledge capability.
|
|
62
|
+
|
|
63
|
+
The expert is an oats.framework **package soul** from framework 1.3.0
|
|
64
|
+
(`oats-package/souls/knowledge-theory-expert/`, reading `oats.knowledge-theory`
|
|
65
|
+
1.1.0 from its own package): spawn it by its qualified name in the author's
|
|
66
|
+
repository, `oats spawn oats.framework/knowledge-theory-expert --repo <repo>`.
|
|
67
|
+
Before 1.3.0 it was a capability-defined agent, which OATS 0.29.0 removed.
|
|
62
68
|
There are no executable surfaces to trust in this package. Installed experts
|
|
63
69
|
use their materialized local curriculum, not this repository at runtime.
|
|
64
70
|
|
|
@@ -35,8 +35,7 @@ A knowledge implementation's capability manifest might begin:
|
|
|
35
35
|
"compatibility": { "oats": ">=0.22.19" },
|
|
36
36
|
"layer": "knowledge",
|
|
37
37
|
"skills": ["skills/native-reader", "skills/native-harvest"],
|
|
38
|
-
"inject": "injects/knowledge.md"
|
|
39
|
-
"agents": ["agents/native-harvester"]
|
|
38
|
+
"inject": "injects/knowledge.md"
|
|
40
39
|
}
|
|
41
40
|
```
|
|
42
41
|
|
|
@@ -49,14 +48,18 @@ kernel's real manifest validation, not this example as a complete schema.
|
|
|
49
48
|
|
|
50
49
|
The optional `oats.knowledge-theory` capability is deliberately **different**:
|
|
51
50
|
it is additive, declares no layer, injection, command or hook, and supplies
|
|
52
|
-
only
|
|
51
|
+
only its authoring skill; the expert that uses it is the oats.framework package
|
|
52
|
+
soul `knowledge-theory-expert`. It neither selects knowledge policy nor
|
|
53
53
|
depends on OKF. A runtime integration should not depend on it just to inherit
|
|
54
54
|
mandatory doctrine. Explicit versioned reuse is a choice, not a requirement.
|
|
55
55
|
|
|
56
56
|
## Soul craft
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
An agent a package ships is a **package soul**: `souls/<name>/` beside the
|
|
59
|
+
package's capabilities (listed in `oats-package.json` `souls:`), holding
|
|
60
|
+
`soul.yaml`, canonical `AGENTS.md` and relative `CLAUDE.md -> AGENTS.md`; it
|
|
61
|
+
reads the package's own capabilities with `from: here`. (A capability manifest
|
|
62
|
+
declares no agents: `agents:` was removed in OATS 0.29.0.) Keep role instructions to a screen or two:
|
|
60
63
|
role and boundaries, operating loop, verification, local skill pointer,
|
|
61
64
|
escalation. Do not bury an entire curriculum in always-loaded instructions.
|
|
62
65
|
|
package/docs/knowledge.md
CHANGED
|
@@ -311,6 +311,107 @@ receipts. Inputs are processed only when required destinations resolve. All-drop
|
|
|
311
311
|
or no-change judgment can be successful without inventing a PR. Enqueue, worker
|
|
312
312
|
spawn and command exit alone are not successful learning.
|
|
313
313
|
|
|
314
|
+
## Knowledge operations
|
|
315
|
+
|
|
316
|
+
> **Version scope:** oats.okf **4.0.0** on kernel **0.29.0** (package souls,
|
|
317
|
+
> triggers and workspace automations). Everything above describes the 2.x runtime, which 4.0.0 keeps for
|
|
318
|
+
> capture, custody and delivery. The design and its decisions are in
|
|
319
|
+
> [the knowledge-operations plan](design/2026-09-26-okf-knowledge-operations.md).
|
|
320
|
+
> The setup procedure is the `oats-onboarding` skill ("Knowledge operations with
|
|
321
|
+
> OKF") and okf's `okf-trigger-setup`.
|
|
322
|
+
|
|
323
|
+
From 4.0.0, harvested knowledge is judged by a harvester, reviewed by a
|
|
324
|
+
maintainer and merged without an operator in the loop, except where a merge
|
|
325
|
+
would supersede a human-accepted decision.
|
|
326
|
+
|
|
327
|
+
### The flow
|
|
328
|
+
|
|
329
|
+
1. **Capture.** A working soul whose knowledge slot is `oats.okf`, on a host
|
|
330
|
+
where harvest is on (below), registers a source at spawn. Capture and
|
|
331
|
+
custody are as above: notes and bounded transcript windows, copied outside
|
|
332
|
+
the home.
|
|
333
|
+
2. **Harvest.** The source's `run-source` job spawns the package soul
|
|
334
|
+
`oats.okf/knowledge-harvester` (team `okf`). It reads the input in full,
|
|
335
|
+
transcript windows included, and judges it with the OKF promotion
|
|
336
|
+
doctrine. It stages edits on the owned nodes and opens a PR on the
|
|
337
|
+
knowledge-base repo, labelled `okf-harvest`, whose body carries a fenced
|
|
338
|
+
`okf-harvest` provenance block (the run, the source soul and instance, the
|
|
339
|
+
owned and read nodes, the task references, the harvester's alias). It
|
|
340
|
+
stays alive, answering questions in `okf`, until the PR is merged or
|
|
341
|
+
closed, then retires. `harvester-max-age` (default 7d) bounds it; it never
|
|
342
|
+
closes its own PR.
|
|
343
|
+
3. **Trigger.** The workspace declares the trigger in a member repo,
|
|
344
|
+
`oats-triggers/okf-harvest-review.yaml` (`kind: oats-trigger`), from the package template
|
|
345
|
+
`oats.okf:harvest-review`. It names the host that runs it (`runsOn`, that
|
|
346
|
+
machine's `host.name`) and the GitHub account it acts as (`owner`, which
|
|
347
|
+
must be able to merge on the knowledge-base repo). Only that host, logged
|
|
348
|
+
in to `gh` as that account, polls for such PRs. For each one it spawns a
|
|
349
|
+
NEW `oats.okf/knowledge-maintainer`, joining `okf`. The event reaches it as
|
|
350
|
+
`OATS_TRIGGER_EVENT_FILE`. A local trigger (`oats trigger add`, this host
|
|
351
|
+
only) is the machine-private alternative. Triggers are described in
|
|
352
|
+
[schedules.md, "Triggers"](schedules.md#triggers), and the workspace
|
|
353
|
+
file in ["Workspace triggers and schedules"](schedules.md#workspace-triggers-and-schedules).
|
|
354
|
+
4. **Review.** The maintainer checks out the PR and situates it: the
|
|
355
|
+
provenance, the source soul's owned and read nodes, the neighbouring
|
|
356
|
+
concepts, and the source's tickets when a tasks capability can read them.
|
|
357
|
+
It records a verdict on the PR (`merge`, `amend+merge`, `request-changes`
|
|
358
|
+
or `close`), amends what needs amending, and merges with the host's `gh`. A
|
|
359
|
+
PR that would supersede a concept with human acceptance evidence is not
|
|
360
|
+
merged: it is labelled `okf-needs-human` for the workspace's human. The
|
|
361
|
+
maintainer tells the harvester the outcome and retires.
|
|
362
|
+
|
|
363
|
+
### Who gets which okf skills
|
|
364
|
+
|
|
365
|
+
| Capability | Composed into | Skills | Inject |
|
|
366
|
+
|---|---|---|---|
|
|
367
|
+
| `oats.okf` | every working soul whose knowledge slot it fills | `okf-consultation` (reading soul knowledge and citing it); `okf-instance-knowledge` (what instance knowledge is worth capturing, and the form of `STATE.md`, `log.md` and `notes/`) | the work mode: consult instance memory and soul knowledge at task start, after compaction and before decisions; capture before compaction |
|
|
368
|
+
| `oats.okf-harvest` | `oats.okf/knowledge-harvester` only | `knowledge-theory` (the OKF promotion doctrine); `knowledge-harvest` (the procedure, through the PR's lifetime); `okf-authoring` | the harvester's: a judge, not a worker; the staged roots are its only write surface |
|
|
369
|
+
| `oats.okf-maintenance` | `oats.okf/knowledge-maintainer` only | `knowledge-theory`; `knowledge-review`; `okf-authoring`; `okf-trigger-setup` | the maintainer's: one PR per instance; supersede explicitly, never silently |
|
|
370
|
+
|
|
371
|
+
Working souls get no promotion doctrine: the harvester is the only judge of
|
|
372
|
+
what is promoted, and the maintainer the only one who merges. The shared
|
|
373
|
+
skills ship as identical copies in each capability. The harvester and the
|
|
374
|
+
maintainer hold no knowledge slot, so nothing harvests them.
|
|
375
|
+
|
|
376
|
+
### The harvest switch
|
|
377
|
+
|
|
378
|
+
Harvest is off unless both the host and the soul allow it:
|
|
379
|
+
|
|
380
|
+
| Where | Setting | Effect |
|
|
381
|
+
|---|---|---|
|
|
382
|
+
| The host, `oats-local.yaml` | `settings.oats.okf.harvest: on` (default `off`) | This host harvests its working souls. |
|
|
383
|
+
| A soul, `soul.yaml` | `knowledge: { harvest: off }` | This soul is never harvested, whatever the host says. |
|
|
384
|
+
|
|
385
|
+
Off means **no capture at all**: no source is registered and no transcript or
|
|
386
|
+
notes enter custody, so nothing accumulates for later. Turning it on starts
|
|
387
|
+
with the next session. `oats okf setup --harvest on|off` writes the host
|
|
388
|
+
setting, and `oats okf harvest-status [--soul <soul>]` reports the effective
|
|
389
|
+
value, the row that decided it and the registered sources.
|
|
390
|
+
`oats schedule disable <job>` on a source's `run-source` job is an emergency
|
|
391
|
+
brake for one source, not the switch. The review trigger does not depend on the
|
|
392
|
+
switch: a host can review harvest PRs from other hosts without harvesting.
|
|
393
|
+
Keep harvest off until the end-to-end check in `okf-trigger-setup` passes.
|
|
394
|
+
|
|
395
|
+
### The `okf` team
|
|
396
|
+
|
|
397
|
+
The package souls carry `team: okf`. The workspace declares the label and maps
|
|
398
|
+
it to a messaging team:
|
|
399
|
+
|
|
400
|
+
```yaml
|
|
401
|
+
teams:
|
|
402
|
+
okf: { description: Knowledge operations }
|
|
403
|
+
messaging:
|
|
404
|
+
byTeam:
|
|
405
|
+
okf: { team: <messaging team id> }
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
Harvesters and maintainers talk there (subjects prefixed `okf:` with the PR's
|
|
409
|
+
URL) without writing into the working teams. Like every label it organises and
|
|
410
|
+
gates nothing. A workspace without it reports `E_TEAM_UNKNOWN` on both package
|
|
411
|
+
souls in discovery. They still spawn, but into no messaging team, so the
|
|
412
|
+
harvester and the maintainer cannot talk, and `oats trigger test` fails its
|
|
413
|
+
team check.
|
|
414
|
+
|
|
314
415
|
## Inspection and operator commands
|
|
315
416
|
|
|
316
417
|
Run home-local commands from that source home: inside an instance the
|