@awebai/oats 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +380 -0
  3. package/bin/oats.mjs +3294 -0
  4. package/capabilities/oats-authoring/oats.json +12 -0
  5. package/capabilities/oats-aweb/bin/oats-aweb.mjs +297 -0
  6. package/capabilities/oats-aweb/injects/aweb.md +55 -0
  7. package/capabilities/oats-aweb/oats.json +47 -0
  8. package/capabilities/oats-aweb/package.json +20 -0
  9. package/capabilities/oats-jira/bin/oats-jira.mjs +40 -0
  10. package/capabilities/oats-jira/injects/jira.md +10 -0
  11. package/capabilities/oats-jira/oats.json +22 -0
  12. package/capabilities/oats-jira/package.json +25 -0
  13. package/capabilities/oats-jira/skills/jira-tasks/SKILL.md +176 -0
  14. package/capabilities/oats-linear/README.md +234 -0
  15. package/capabilities/oats-linear/bin/oats-linear-hook.mjs +32 -0
  16. package/capabilities/oats-linear/bin/oats-linear.mjs +344 -0
  17. package/capabilities/oats-linear/injects/linear.md +8 -0
  18. package/capabilities/oats-linear/oats.json +24 -0
  19. package/capabilities/oats-linear/package.json +29 -0
  20. package/capabilities/oats-linear/skills/linear-tasks/SKILL.md +217 -0
  21. package/capabilities/oats-linear/test/oats-linear.test.mjs +168 -0
  22. package/capabilities/oats-okf/agents/memory-harvest.md +25 -0
  23. package/capabilities/oats-okf/bin/oats-okf.mjs +283 -0
  24. package/capabilities/oats-okf/injects/okf.md +62 -0
  25. package/capabilities/oats-okf/oats.json +20 -0
  26. package/capabilities/oats-okf/package.json +22 -0
  27. package/capabilities/oats-okf/skills/memory-harvest/SKILL.md +100 -0
  28. package/capabilities/oats-okf/skills/okf/SKILL.md +107 -0
  29. package/capabilities/oats-okf/skills/okf/scripts/okf-validate.mjs +123 -0
  30. package/capabilities/oats-review/agents/reviewer/AGENTS.md +53 -0
  31. package/capabilities/oats-review/agents/reviewer/soul.yaml +6 -0
  32. package/capabilities/oats-review/injects/review.md +68 -0
  33. package/capabilities/oats-review/oats.json +10 -0
  34. package/capabilities/oats-review/skills/code-review/SKILL.md +44 -0
  35. package/capabilities/oats-review/skills/security-review/SKILL.md +59 -0
  36. package/docs/capabilities.md +505 -0
  37. package/docs/capability-manifest.schema.json +223 -0
  38. package/docs/configuration.md +482 -0
  39. package/docs/conventions.md +73 -0
  40. package/docs/design/desktop-ux-plan.md +362 -0
  41. package/docs/design/package-engine-contract.md +813 -0
  42. package/docs/design/package-runtime-api.md +414 -0
  43. package/docs/desktop-cli-api.md +89 -0
  44. package/docs/desktop-succession.md +51 -0
  45. package/docs/desktop.md +187 -0
  46. package/docs/implementation.md +282 -0
  47. package/docs/integrations.md +123 -0
  48. package/docs/knowledge-theory.md +97 -0
  49. package/docs/knowledge.md +139 -0
  50. package/docs/layers.md +110 -0
  51. package/docs/migration-from-oas.md +122 -0
  52. package/docs/oats-config.schema.json +140 -0
  53. package/docs/oats-lock.schema.json +175 -0
  54. package/docs/oats-package.schema.json +129 -0
  55. package/docs/packages.md +442 -0
  56. package/docs/release-lane.md +132 -0
  57. package/docs/release-notes/v0.18.2.md +79 -0
  58. package/docs/release-notes/v0.18.3.md +63 -0
  59. package/docs/release-notes/v0.18.4.md +65 -0
  60. package/docs/release-notes/v0.18.5.md +66 -0
  61. package/docs/release-notes/v0.18.6.md +87 -0
  62. package/docs/release-notes/v0.19.0.md +186 -0
  63. package/docs/release-notes/v0.19.1.md +24 -0
  64. package/docs/release-notes/v0.19.2.md +32 -0
  65. package/docs/release-notes/v0.19.3.md +16 -0
  66. package/docs/release-notes/v0.19.4.md +12 -0
  67. package/docs/release-notes/v0.20.0.md +89 -0
  68. package/docs/release-notes/v0.22.0.md +180 -0
  69. package/docs/souls-and-instances.md +344 -0
  70. package/injects/framework-workspace.md +7 -0
  71. package/injects/instance-boundary.md +43 -0
  72. package/injects/local-soul.md +19 -0
  73. package/injects/oats.md +11 -0
  74. package/injects/work-attached.md +16 -0
  75. package/injects/work-checkout.md +12 -0
  76. package/injects/work-workspace.md +22 -0
  77. package/injects/work-worktree.md +13 -0
  78. package/lib/core.mjs +6792 -0
  79. package/lib/packages.mjs +1375 -0
  80. package/lib/tmux-config.mjs +35 -0
  81. package/package-catalog.json +44 -0
  82. package/package.json +55 -0
  83. package/packages/record/README.md +151 -0
  84. package/packages/record/bin/capture.mjs +256 -0
  85. package/packages/record/bin/recall.mjs +102 -0
  86. package/packages/record/bin/setup.mjs +281 -0
  87. package/packages/record/bin/turn-record.mjs +47 -0
  88. package/packages/record/docs/turn-record-sot.md +350 -0
  89. package/packages/record/lib/canonical.mjs +151 -0
  90. package/packages/record/lib/capture-aw.mjs +179 -0
  91. package/packages/record/lib/capture-cc.mjs +322 -0
  92. package/packages/record/lib/formats.mjs +296 -0
  93. package/packages/record/lib/ignore.mjs +155 -0
  94. package/packages/record/lib/index-db.mjs +524 -0
  95. package/packages/record/lib/project-aweb.mjs +251 -0
  96. package/packages/record/lib/segments.mjs +186 -0
  97. package/packages/record/lib/store.mjs +447 -0
  98. package/packages/record/lib/tags.mjs +114 -0
  99. package/packages/record/package.json +45 -0
  100. package/packages/record/test/vectors/README.md +34 -0
  101. package/packages/record/test/vectors/aweb-projection-v1.json +231 -0
  102. package/packages/record/test/vectors/journal-merge-v1.json +261 -0
  103. package/packages/record/test/vectors/turn-id-v1.json +152 -0
  104. package/packages/record/test/vectors/validate.mjs +391 -0
  105. package/skills/integration-authoring/SKILL.md +76 -0
  106. package/skills/oats/SKILL.md +151 -0
  107. package/skills/oats-config/SKILL.md +162 -0
  108. package/skills/oats-getting-started/SKILL.md +159 -0
  109. package/skills/oats-packages/SKILL.md +180 -0
  110. package/skills/oats-support/SKILL.md +79 -0
  111. package/skills/skill-craft/SKILL.md +109 -0
  112. package/skills/soul-craft/SKILL.md +109 -0
@@ -0,0 +1,505 @@
1
+ # Capability packages
2
+
3
+ A **capability package** is OATS's reusable distribution unit. It can contribute
4
+ skills, instance instructions, requirements, namespaced commands, and approved
5
+ lifecycle hooks. Configuration—not the package—decides which souls receive it.
6
+
7
+ An **integration** is a capability package that implements one exclusive
8
+ fundamental layer: `knowledge`, `messaging`, or `tasks`. General capabilities
9
+ claim no layer and compose additively.
10
+
11
+ ## Mental model
12
+
13
+ This is OATS's first public capability-package contract. The unpublished,
14
+ pre-release integration prototype has no compatibility promise: its manifest,
15
+ config, discovery, and command aliases are intentionally not accepted.
16
+
17
+ The contract is:
18
+
19
+ 1. **Acquire** a package. External artifacts are pinned in `oats-lock.json`.
20
+ 2. **Activate** it for global scope, a config-owned soul group, or one soul.
21
+ 3. **Spawn** a soul. OATS resolves the target, creates the exact
22
+ `.agents/skills/`, and generates that instance's `AGENTS.md` without
23
+ changing the canonical soul.
24
+
25
+ Acquired does not mean active. `oats init` activates only the explicit defaults
26
+ it writes; it never enables every package merely because it is available.
27
+
28
+ ## Manifest
29
+
30
+ A self-contained package has an `oats.json`:
31
+
32
+ ```json
33
+ {
34
+ "capability": "example.team-chat",
35
+ "command": "team-chat",
36
+ "version": "1.2.3",
37
+ "compatibility": { "oats": ">=0.6.2" },
38
+ "description": "Messaging through Team Chat.",
39
+ "layer": "messaging",
40
+ "requires": [
41
+ { "command": "team-chat", "why": "send and receive messages" },
42
+ {
43
+ "runtime": "pi",
44
+ "package": "npm:team-chat-pi",
45
+ "why": "real-time push events in pi sessions"
46
+ }
47
+ ],
48
+ "skills": ["skills"],
49
+ "inject": "injects/team-chat.md",
50
+ "commands": { "auth": "bin/team-chat.mjs auth" },
51
+ "environment": ["EXAMPLE_IDENTITY_HOME"],
52
+ "hooks": {
53
+ "spawn": "bin/team-chat-hook.mjs spawn",
54
+ "retire": "bin/team-chat-hook.mjs retire"
55
+ }
56
+ }
57
+ ```
58
+
59
+ - `capability` is a namespaced ID. Duplicate IDs are errors. A capability that
60
+ declares launch environment must use a lowercase dotted vendor prefix such
61
+ as `aweb.identity`, because that prefix owns the corresponding `AWEB_*`
62
+ namespace.
63
+ - `command` is an optional, unique CLI namespace. The example exposes
64
+ `oats team-chat auth`.
65
+ - `layer` is optional and may name exactly one fundamental layer. Two active
66
+ packages cannot implement the same layer for one soul.
67
+ - `skills` entries can be skill directories or roots containing skills.
68
+ - `inject` is optional instance instruction Markdown.
69
+ - Only `soul-scaffold`, `spawn`, and `retire` hooks are accepted. A hook is a
70
+ command string, or `{ command, required }`. `required: true` is valid **only
71
+ on `spawn`**: the hook's failure then fails the spawn and rolls it back,
72
+ instead of producing an instance whose capability never configured itself —
73
+ an aweb identity that could not be minted leaves an agent believing it can be
74
+ woken by mail. Every other hook stays best-effort and only warns, so advisory
75
+ work never becomes a spawn blocker. `retire` and `soul-scaffold` cannot be
76
+ required: they run outside a spawn transaction, so there is no moment to
77
+ enforce them.
78
+ - A capability declaring a **required** spawn hook should declare a `retire` hook
79
+ too. Without one, OATS has no way to undo what the spawn hook did and no way to
80
+ know whether it did anything, so a failure quarantines the home rather than
81
+ rolling it back — the operator cleans up by hand and removes it with `--force`.
82
+ - A required hook must also be **able** to run: if its capability's executable
83
+ surface is not trusted, the spawn fails with the `oats trust` remedy rather
84
+ than starting without the setup. Advisory executable hooks stay
85
+ disabled-with-warning.
86
+ - When a required hook fails and its compensation cannot finish, the instance
87
+ home is **retained**, not deleted — it holds the credentials and metadata a
88
+ retry needs, and removing it would turn a transient cleanup failure into
89
+ permanent external residue. It is marked `.oats-rollback-incomplete.json`, so
90
+ `oats status` reports it as retained state rather than a live instance, and
91
+ `oats retire <instance>` retries the cleanup — re-running the retire hooks and
92
+ the rollback-owned Git steps, and verifying both. A retry that still cannot
93
+ finish keeps the home again, names what is outstanding, and exits nonzero.
94
+ - The **escape hatch is `oats retire <instance> --force`**, for a home OATS cannot
95
+ identify at all: no `instance.json` and no **usable** cleanup descriptor. Usable
96
+ means it satisfies the versioned cleanup contract the rollback writes, checked
97
+ to the depth the retry consumes it: `version`, a context `repo`, a recognised
98
+ `work` mode (plus a `branch` for `worktree` — an unknown mode would skip the
99
+ rollback-owned Git cleanup and call it done), a real non-empty capability set,
100
+ and the record of what still owes cleanup — retire hooks by capability id, plus
101
+ the rollback-owned Git steps (`worktree`, `branch`) where the mode has them. That
102
+ record can never be empty: a quarantine exists because something is outstanding,
103
+ and one claiming otherwise would give the retry nothing to prove. A marker failing any of
104
+ that is no more retryable than a missing one, and is treated as missing so the
105
+ escape hatch works.
106
+ - A retry clears the quarantine only by **proving the outstanding work happened**:
107
+ every retire hook the marker records as owing cleanup must have run and reported
108
+ success, and every Git step it records must be re-run and verified. A retry that resolves no
109
+ capabilities — a hand-edited descriptor, or config drift since the spawn — is an
110
+ incomplete cleanup, not a clean one, and the home stays.
111
+ - Because some cleanups can never succeed (a capability offering no way to undo its
112
+ own setup, a permanently unreachable remote), **`--force` also overrides
113
+ retention**: the home is removed, and everything still outstanding is printed as
114
+ state the operator now owns. Nothing is ever permanently unremovable through OATS,
115
+ and nothing is silently dropped. Without `--force` that state fails closed with
116
+ `E_UNIDENTIFIED_INSTANCE_HOME` rather than deleting whatever credentials the
117
+ directory still holds; `--force` removes it and leaves any external state for
118
+ the operator to clean up by hand.
119
+ - `requires` declares what must exist before the capability works. Two kinds:
120
+ - a **host command** (`command`), satisfied by a binary on `PATH`;
121
+ - a **runtime package** (`runtime` + `package`, optionally `marketplace`),
122
+ satisfied by that runtime's own package manager — `npm:@scope/name` for pi,
123
+ `plugin@marketplace` for Claude Code. It is raised only for deployments that use the named
124
+ runtime — a Claude-only deployment is never asked to install a pi package —
125
+ and is verified in the runtime's package list, never on `PATH`. A version
126
+ selector is allowed and ignored for identity, so `@latest` and a pinned
127
+ version are one requirement.
128
+ A runtime package is **verified at spawn, never installed there**: installing
129
+ would mutate the operator's runtime configuration without asking, in the
130
+ middle of a spawn. A missing, uninstalled or disabled package fails the spawn
131
+ with the consent command that fixes it.
132
+ - OATS never installs a requirement silently. `oats install` prompts per
133
+ requirement with the exact argv, source and scope; automation passes
134
+ `--accept-requirement <name>` (the name is the command, or
135
+ `<runtime>:<package>`), and `--no-requirements` skips the gate. When a plan
136
+ has several steps — registering a Claude marketplace before installing from
137
+ it — every step is shown, because agreeing to a plugin also means agreeing to
138
+ the source it comes from. Declining
139
+ leaves an actionable `oats doctor` warning. Consent to install is separate
140
+ from capability trust.
141
+ - `environment` lists the exact launch variables executable trust approves;
142
+ spawn hook output must be a subset and use the capability vendor prefix.
143
+ - Target names never appear in a package manifest.
144
+
145
+ `capability` is the only manifest identity field. The machine-readable
146
+ contract is [`capability-manifest.schema.json`](capability-manifest.schema.json).
147
+
148
+ ## Config and targets
149
+
150
+ ```yaml
151
+ agent-types:
152
+ developers:
153
+ description: Agents that build the service (souls declare `type: developers`)
154
+ reviewers:
155
+ description: Agents that review changes
156
+
157
+ capabilities:
158
+ layers:
159
+ knowledge:
160
+ capability: oats.okf
161
+ from: installed
162
+ # injection-override: .agents/injections/capabilities/oats.okf.md
163
+ messaging: none
164
+ tasks: none
165
+
166
+ additive:
167
+ example.code-review:
168
+ from: installed
169
+ agent-types:
170
+ developers:
171
+ enabled: true
172
+ settings:
173
+ depth: normal
174
+ souls:
175
+ security-reviewer:
176
+ enabled: true
177
+ settings:
178
+ depth: exhaustive
179
+
180
+ example.deploy:
181
+ from: installed
182
+ global: true
183
+ agent-types:
184
+ reviewers: false # explicit exclusion
185
+ souls:
186
+ release-reviewer: true # more-specific re-enable
187
+
188
+ skill-overrides:
189
+ review: example.code-review
190
+ ```
191
+
192
+ `global` means all souls governed by the config level declaring it—not every
193
+ soul on the machine regardless of scope. Laptop, workspace, and repository
194
+ configs each govern souls beneath that level.
195
+
196
+ Composition is additive across matching global, agent-type, and soul
197
+ bindings. Settings use `soul > agent-type > global`, then closer config scope.
198
+ Conflicting values at equal specificity and scope are errors.
199
+ `enabled: false` follows the same precedence. Agent types are declared by
200
+ name in config; each soul opts in via `type:` in its soul.yaml. Tags and
201
+ selectors are not implemented, and bindings do not target individual
202
+ instances.
203
+
204
+ `capabilities` is the only activation map: fundamental integrations live
205
+ under `capabilities.layers.<layer>` (an entry or an explicit `none` that
206
+ suppresses an inherited integration), everything else under
207
+ `capabilities.additive`.
208
+
209
+ ## Exact runtime composition
210
+
211
+ Every spawned instance receives:
212
+
213
+ - canonical soul skills;
214
+ - the kernel `oats` skill; and
215
+ - skills from capabilities active for that soul.
216
+
217
+ OATS copies only those skill trees into real directories under
218
+ `<instance>/.agents/skills/` and records the names and source capability in
219
+ `instance.json`. `.claude/skills` points to
220
+ the same canonical directory. Pi launches with this directory as an explicit
221
+ skill path; ambient skills (user-level, pi packages, the work tree) coexist
222
+ with the OATS-composed set rather than being excluded — `instance.json`
223
+ records exactly what OATS composed, not everything the harness may discover.
224
+ `oats-getting-started` is the pi adapter's one ambient contribution before a workspace exists.
225
+
226
+ Duplicate skill names fail spawn unless `skill-overrides` explicitly names the
227
+ winning source. Pi and Claude therefore receive the same OATS-managed set rather
228
+ than relying on different ancestor-discovery rules.
229
+
230
+ For pi, exact isolation needs the capability-aware versions of both
231
+ `@awebai/oats` and `@awebai/oats-pi`. The kernel disables normal skill
232
+ discovery at launch. The changed adapter contributes only the instance-local
233
+ set instead of the older workspace and package roots. Install matching package
234
+ versions and upgrade them together.
235
+
236
+ The instance's `AGENTS.md` is a generated regular file containing:
237
+
238
+ 1. the canonical soul `AGENTS.md`;
239
+ 2. the kernel and work-mode blocks;
240
+ 3. active capability blocks in deterministic order; and
241
+ 4. unconditional config instruction blocks.
242
+
243
+ Its `CLAUDE.md` symlinks to `AGENTS.md`. The committed soul remains unchanged.
244
+ Edit the canonical soul, injection source, or config, then spawn a new
245
+ instance; do not edit generated blocks as source-of-truth changes.
246
+
247
+ Inspect a final composition:
248
+
249
+ ```bash
250
+ oats doctor /path/to/repo --soul api-expert
251
+ oats doctor /path/to/repo --soul api-expert --json
252
+ ```
253
+
254
+ Doctor reports active/acquired packages, target provenance, settings, skills,
255
+ hooks, trust, instruction sources, and final composed text. It cannot infer
256
+ semantic contradictions between two prose injections; review the output.
257
+
258
+ ## Distribution packages
259
+
260
+ A **distribution package** is the install/update/review unit above
261
+ capabilities: a directory with an `oats-package.json` manifest that explicitly
262
+ enumerates one or more capabilities and optional reference config templates
263
+ (schema:
264
+ `docs/oats-package.schema.json`; contract:
265
+ `docs/design/package-engine-contract.md`). A capability remains the
266
+ targeting/activation unit — every capability a package exports stays
267
+ independently addressable by ID with `from: installed`.
268
+
269
+ A Git repository *contains* that directory; `#<path>` selects which one, and
270
+ only the selected subtree is installed and hashed. Omitting it selects
271
+ `oats-package/` (the convention for every official example and scaffold); `#.`
272
+ selects the repository root. Local paths are always exact directories.
273
+
274
+ ```bash
275
+ oats install git:github.com/org/repo@v1.0.0 --dir /path/to/scope # git shorthand → oats-package/
276
+ oats install git:github.com/org/repo@v1.0.0#dist/oats # a custom contained root
277
+ oats install https://host/org/repo.git@v1.0.0#. # raw git URL, repository root
278
+ oats install ../my-package # local path (exact directory)
279
+ oats install oats.okf # official catalog id
280
+ oats install # bare: exact restore of this chain's locks
281
+ oats list # installed packages, exported capabilities, scopes
282
+ oats update <package> # transactional re-resolve + diff + trust reset
283
+ oats remove <package> # refuses while config/dependents reference it
284
+ oats migrate [--dry-run] # map v1 capability locks to package locks
285
+ ```
286
+
287
+ Installing a package materializes each capability into the owning scope's
288
+ `.agents/capabilities/installed/<id>/` (gitignored, like the capability store).
289
+ There is no persistent package store. `oats-lock.json` uses `lockfileVersion: 2`
290
+ with two maps: `packages` (exact source, commit, selected path, payload
291
+ integrity, and dependencies) and `capabilities` (each artifact's version,
292
+ provider package, path, integrity, and trust) — schema
293
+ `docs/oats-lock.schema.json`. Dependencies are pinned (official selector,
294
+ tag/commit, or local path — no semver solver). Cycles and two sources claiming
295
+ one package identity at a scope are errors with provenance. Acquisition
296
+ **activates nothing** and adopts no config template; an unpinned git source
297
+ resolves once and never advances on restore.
298
+
299
+ Trust binds to each materialized capability artifact at its exact integrity.
300
+ `oats trust <capability>` approves only that capability's commands, hooks, and
301
+ declared launch environment.
302
+ `oats trust <package> --all-capabilities` is the explicit bulk path and prints
303
+ the full executable surface first. Any artifact integrity change (including
304
+ `oats update`) resets that capability's trust.
305
+ Skill/instruction/config-only capabilities need lock integrity but no
306
+ executable approval, and official-catalog identity grants **no** executable
307
+ trust. A capability may carry a checked-in `package-lock.json` for JS runtime
308
+ dependencies; OATS materializes it with `npm ci --ignore-scripts` only — npm
309
+ lifecycle scripts never run at acquisition, and capability code/hook paths
310
+ must resolve inside the materialized capability root.
311
+
312
+ `oats migrate` converts a scope's v1 marketplace/git/path capability locks to
313
+ the revised v2 lock, preserving `from: installed` activation. It is
314
+ all-or-nothing per scope: a scope converts only when every entry maps to a
315
+ package. If any entry is held, manual, or retained, the whole scope stays
316
+ byte-identical v1 and keeps working. There is no residue container, and
317
+ executable approvals are never carried over.
318
+
319
+ All package operations are agent-callable: every command above supports
320
+ `--json` (one stdout envelope; failures carry the contract's stable error
321
+ codes) and noninteractive operation. Agents never hand-edit `oats-lock.json`
322
+ or the stores — the kernel-owned **oats-packages** skill (composed into every
323
+ instance) teaches the full lifecycle.
324
+
325
+ ## Acquisition, lock, restore, and trust (single capabilities)
326
+
327
+ ```bash
328
+ oats install oats.jira --dir /path/to/repo # official catalog id; approve executable surfaces with `oats trust`
329
+ oats install https://example.invalid/team-chat.git --dir /path/to/repo
330
+ oats install ../team-chat --dir /path/to/repo
331
+ oats install # bare: restore locked-but-missing artifacts
332
+ ```
333
+
334
+ Every acquired artifact lands in the owning scope's
335
+ `.agents/capabilities/installed/`, beside the `oats-config.yaml` and
336
+ `oats-lock.json` that govern it. Install maintains a one-line
337
+ `.agents/capabilities/.gitignore` so acquired artifacts stay uncommitted, like
338
+ `node_modules`. A fresh clone with a committed config and lock runs bare
339
+ `oats install` to reacquire everything; each restored artifact must hash to the
340
+ locked integrity or the restore fails and removes the fetched copy.
341
+
342
+ Installation acquires and locks; it does **not** activate. `oats-lock.json`
343
+ records:
344
+
345
+ - source;
346
+ - exact package version and git commit when available; and
347
+ - SHA-256 integrity of the artifact.
348
+
349
+ OATS never pulls an existing package silently. Changed integrity blocks use
350
+ until the package is deliberately reacquired. For external packages containing
351
+ commands, hooks, or launch-environment authority, approve that exact locked
352
+ artifact:
353
+
354
+ ```bash
355
+ oats trust example.team-chat --dir /path/to/repo
356
+ ```
357
+
358
+ Changing integrity invalidates approval. Skill/instruction-only packages still
359
+ require a valid lock but do not require executable approval. Manifest paths in
360
+ external packages must remain inside the locked artifact (including after
361
+ symlink resolution), so approved hooks and commands cannot execute unhashed
362
+ files. The trust boundary is structural: anything under `installed/` must have
363
+ a matching lock entry, so an installed artifact cannot masquerade as scope-owned
364
+ by dropping its lock. A committed lock's approval survives restore when the
365
+ restored artifact hashes to the locked integrity.
366
+
367
+ One narrow exception exists for the kernel's own marketplace, kept only until
368
+ official packages replace legacy `marketplace:` installs. A capability whose
369
+ lock source is `marketplace:<id>@<version>` may declare resources that live
370
+ outside its installed copy — `oats.authoring` selects framework skills with
371
+ `../../skills/<name>` — and those declarations are resolved against the
372
+ capability's directory in the kernel marketplace
373
+ (`<kernel>/capabilities/<slug>`), located by capability id rather than by the
374
+ lock selector's spelling. If that declared path names an npm dependency hoisted
375
+ by npm, OATS also checks the equivalent path from the kernel root; this is the
376
+ published `oats.aweb` layout (`node_modules/@awebai/pi/skills/...`). The shipped source must still have the same
377
+ capability identity, while its version may advance with an explicitly installed
378
+ kernel upgrade: framework-hoisted resources belong to that trusted kernel, and
379
+ this preserves valid older v1 installs until official-package migration. The
380
+ installed copy and its lock must still agree on version and integrity. If they
381
+ do not, recovery is to delete the installed copy the error names and then run
382
+ `oats install <id> --dir <scope>`, which re-acquires and rewrites the lock entry;
383
+ run with the copy still in place, that command reports `Already acquired` and
384
+ changes nothing, and legacy v1 capability entries are not removable with
385
+ `oats remove`, which services packages. Such a tree may leave the
386
+ installed copy but never the kernel package: `..` segments and symlinks that
387
+ resolve outside it are rejected exactly like any other escape. Capabilities
388
+ exported by packages, authored at a scope, or referenced by path never receive
389
+ this resolution — they stay inside their own artifact.
390
+
391
+ Bundled framework packages are trusted. Packages you author at a scope live in
392
+ `.agents/capabilities/owned/` and are config-owned trusted — trusting the
393
+ scope trusts them; review them like other repository instructions and code.
394
+ In a git-managed scope they are committed; at a non-git scope (the laptop
395
+ level, a plain workspace root) they are ordinary files whose durability is the
396
+ scope's own — they have no lock and are not restorable by `oats install`, so
397
+ back them up with whatever backs up that scope. Capabilities directly
398
+ under `.agents/capabilities/` are rejected — move them into `installed/` or
399
+ `owned/`.
400
+
401
+ ## Activation and exclusions
402
+
403
+ ```bash
404
+ oats use oats.okf --global --dir /path/to/repo
405
+ oats use example.code-review --type developers --dir /path/to/repo
406
+ oats use example.deploy --type reviewers --disable --dir /path/to/repo
407
+ oats use example.deploy --soul release-reviewer --dir /path/to/repo
408
+ ```
409
+
410
+ `--global` is the default. Choose only one target. An integration's manifest
411
+ declares its layer, so activation does not repeat it. Disable an inherited
412
+ fundamental layer with `oats use none --layer <layer>`.
413
+
414
+ ## Capability-defined agents
415
+
416
+ A manifest may declare `agents: ["agents/<name>"]` — package-relative soul
417
+ directories (`soul.yaml` + `AGENTS.md` directly inside). Wherever the
418
+ capability is **declared** in the config chain, `oats spawn <name>` resolves
419
+ these like local souls: the canonical soul stays read-only inside the package
420
+ (a fresh identity every spawn — by design for service agents like reviewers),
421
+ while instances home under the scope's `local-agents/`. Capability agents
422
+ carry their own `model:`/`runtime:` defaults in soul.yaml.
423
+
424
+ ## Commands and hooks
425
+
426
+ Operational commands resolve only when their package is active in the current
427
+ instance or soul context. Package-management commands (`install`, `trust`,
428
+ `use`, `doctor`) remain available globally.
429
+
430
+ Hooks receive `OATS_EVENT`, `OATS_CAPABILITY`, `OATS_LAYER`, `OATS_INSTANCE`,
431
+ `OATS_HOME`, `OATS_AGENT`, `OATS_SOUL`, `OATS_CONTEXT`, `OATS_WORKSPACE`,
432
+ `OATS_ROOT`, `OATS_LEVEL`, `OATS_SETTINGS`, and `OATS_META`. A final JSON line may
433
+ return `meta`, `brief`, `warning`, or runtime-specific `launch` arguments. A
434
+ **spawn hook only** may also return an `env` object for the launched process;
435
+ returning `env` from retire or soul-scaffold is an explicit contract error.
436
+
437
+ Hook environment values are strings, at most 8192 UTF-8 bytes, with no NUL or
438
+ newlines. Names use the portable environment grammar and must belong to an
439
+ unambiguous vendor namespace. Only a dotted capability ID participates: its
440
+ component before the first `.` must be lowercase alphanumeric. Thus `aweb.*`
441
+ may contribute only `AWEB_*`; `aweb@evil` and `aweb/evil` are not vendor forms
442
+ for this contract. Hyphenated vendors are also excluded because translating a
443
+ hyphen to `_` would let `aweb-evil.*` collide with names already inside
444
+ `aweb.*`'s `AWEB_*` namespace.
445
+
446
+ A hook may return only names in its manifest's exact `environment` declaration.
447
+ For acquired packages that declaration is part of the integrity-locked artifact.
448
+ Third-party install previews the future request, and `oats trust` prints the
449
+ exact request before persisting executable authority. Marketplace automatic
450
+ trust likewise prints it before writing the trusted lock. Undeclared output is
451
+ fatal. Config-owned packages receive the same exact-subset enforcement under
452
+ their existing config-owned trust. This positive authority is the contract
453
+ boundary — adding a new launch variable requires a visible manifest/trust
454
+ change.
455
+
456
+ `OATS_*`, `PI_AGENT_*`, kernel launch variables, and known shell/bootstrap/loader
457
+ names are also rejected as defense in depth. The denylist includes current Node,
458
+ JVM, .NET, Python, Perl, Ruby, Lua, PHP, ELF, and dyld surfaces, but is explicitly
459
+ not the authority boundary: runtime bootstrap names are open-ended, so the
460
+ manifest declaration and trust review enforce what an artifact may contribute.
461
+ Two capabilities claiming the same name is an error even when their values
462
+ match.
463
+
464
+ Environment names are sorted before shell-quoted command construction, and a
465
+ contributed value deliberately overrides an ambient value of the same name.
466
+ Invalid or colliding contributions abort before `instance.json` and session
467
+ launch. OATS enters the same rollback transaction as a required spawn-hook
468
+ failure: declared retire compensation runs in reverse, worktree-mode Git state
469
+ is removed and verified, and the home is deleted only after cleanup completes.
470
+ A failed compensation, unverifiable topology removal, or reported spawn state
471
+ without a retire hook uses the standard retryable quarantine instead. Ordinary
472
+ advisory hook execution failure itself contributes no environment.
473
+
474
+ The environment prefix applies to the initial Pi or Claude process. `--no-launch`
475
+ validates command preparation but has no runtime consumer. The fallback shell
476
+ after that process exits does not inherit command-scoped assignments, and OATS
477
+ has no restart command or replay policy yet. The generated command is persisted
478
+ as before; hooks must contribute locators, selectors, or broker endpoints—not
479
+ bearer tokens or private key material. An instance-lifetime local principal may
480
+ be selected by a home locator. A replaceable execution serving a durable global
481
+ identity must instead use a custody/action broker or equivalent narrow adapter;
482
+ this mechanism must never copy or expose that global identity's root keys to the
483
+ worker process. Session-scoped execution credentials need a separate lifecycle
484
+ and must not be encoded into this persisted spawn command.
485
+
486
+ Spawn/scaffold order is outer scope to inner scope, then capability ID;
487
+ retirement reverses successful spawn order. Scaffold hooks cannot modify or
488
+ delete canonical or another package's files. OATS records ownership, restores
489
+ the pre-hook snapshot, and raises a conflict instead of accepting destructive
490
+ or last-writer-wins behavior.
491
+
492
+ ## Bundled packages
493
+
494
+ | Capability | Kind | Provides |
495
+ |---|---|---|
496
+ | `oats.okf` | knowledge integration | OKF bundles, instance memory, harvest skills and command |
497
+ | `oats.aweb` | messaging integration | aweb identity lifecycle and messaging skills |
498
+ | `oats.jira` | tasks integration | Jira task protocol via `acli` |
499
+ | `oats.linear` | tasks integration | Linear GraphQL task commands and workflow |
500
+ | `oats.authoring` | additive | capability, skill, and soul authoring guidance |
501
+
502
+ The source packages live under `capabilities/`. Acquired packages live under
503
+ `<level>/.agents/capabilities/installed/` (gitignored, restorable); packages
504
+ authored at a scope live under `<level>/.agents/capabilities/owned/`
505
+ (committed where the scope is a git repo). Within one scope `owned/` overrides `installed/` on ID collision.