@awebai/oats 0.24.13 → 0.25.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/bin/oats.mjs +994 -2837
  2. package/docs/capabilities.md +136 -323
  3. package/docs/configuration.md +68 -533
  4. package/docs/conventions.md +51 -24
  5. package/docs/design/2026-09-16-fresh-operator-walkthrough.md +19 -14
  6. package/docs/design/2026-09-16-portable-migration-evidence.md +2 -0
  7. package/docs/design/2026-09-16-portable-onboarding.md +4 -2
  8. package/docs/design/2026-09-20-redesign-program-board.md +1 -1
  9. package/docs/design/2026-09-20-workspace-and-portable-adoption-plan.md +2 -0
  10. package/docs/design/2026-09-23-simplified-workspace-model.md +711 -0
  11. package/docs/design/2026-09-23-workspace-module-contracts.md +460 -0
  12. package/docs/design/2026-09-23-workspace-v2-implementation-plan.md +65 -0
  13. package/docs/design/README.md +20 -8
  14. package/docs/design/operations-contract.md +1 -0
  15. package/docs/design/package-engine-contract.md +1 -1
  16. package/docs/design/package-runtime-api.md +1 -1
  17. package/docs/desktop-cli-api.md +356 -5
  18. package/docs/desktop-succession.md +12 -6
  19. package/docs/desktop.md +9 -4
  20. package/docs/execution-targets.md +16 -4
  21. package/docs/first-team.md +107 -224
  22. package/docs/implementation.md +41 -11
  23. package/docs/integrations.md +50 -47
  24. package/docs/knowledge-capability-authoring.md +10 -4
  25. package/docs/knowledge-migration.md +21 -12
  26. package/docs/knowledge-reference/package-craft.md +11 -3
  27. package/docs/knowledge.md +60 -18
  28. package/docs/layers.md +3 -3
  29. package/docs/migration-from-oas.md +20 -9
  30. package/docs/oats-local.schema.json +50 -0
  31. package/docs/oats-membership.schema.json +23 -0
  32. package/docs/oats-workspace.schema.json +133 -48
  33. package/docs/official-marketplace.md +9 -6
  34. package/docs/packages.md +229 -440
  35. package/docs/rebuild-to-v2.md +347 -0
  36. package/docs/release-notes/v0.25.0.md +99 -0
  37. package/docs/release-notes/v0.25.1.md +94 -0
  38. package/docs/schedules.md +12 -6
  39. package/docs/soul.schema.json +41 -68
  40. package/docs/souls-and-instances.md +175 -108
  41. package/docs/workspace-adoption.md +70 -345
  42. package/docs/workspaces.md +436 -119
  43. package/lib/core.mjs +462 -61
  44. package/lib/instance-resolution.mjs +387 -0
  45. package/lib/materialize.mjs +580 -0
  46. package/lib/operator-dispatch.mjs +117 -0
  47. package/lib/packages.mjs +558 -1269
  48. package/lib/remote.mjs +718 -0
  49. package/lib/resolve.mjs +638 -0
  50. package/lib/schedule.mjs +90 -16
  51. package/lib/workspace.mjs +654 -0
  52. package/package.json +1 -1
  53. package/lib/portable-migration-artifacts.mjs +0 -135
  54. package/lib/portable-migration-evidence.mjs +0 -305
  55. package/lib/portable-migration-store.mjs +0 -199
  56. package/lib/portable-migration.mjs +0 -104
  57. package/lib/portable-onboarding-acceptance.mjs +0 -66
  58. package/lib/setup-expert-source.mjs +0 -100
@@ -1,557 +1,92 @@
1
- # Configuration
1
+ # Configuration — `oats-local.yaml`
2
2
 
3
- OATS configuration lives in `oats-config.yaml` at a laptop, workspace, or
4
- repository root. It owns deployment policy: agent-type declarations, the three
5
- fundamental layer slots, additive capability activations, settings,
6
- exclusions, instruction overrides, and work modes.
3
+ A deployment has **one** per-machine file: `oats-local.yaml`. It says which
4
+ workspace this machine realizes and holds the few facts that are true of this
5
+ host only. Everything shared — members, packages and their versions, teams,
6
+ defaults, stores, the messaging policy — lives in the workspace repo's
7
+ `oats-workspace.yaml`; everything about a soul lives in its `soul.yaml`
8
+ ([workspaces.md](workspaces.md)).
7
9
 
8
- The CLI is the primary config author: `oats init` scaffolds the full shape,
9
- `oats use` writes capability entries, `oats create --type` sets a soul's type.
10
- Hand-editing is valid but never required. Packages never declare their
11
- targets. See the machine-readable
12
- [`oats-config.schema.json`](oats-config.schema.json) alongside the examples
13
- below.
10
+ **`oats-config.yaml` no longer exists.** Its `capabilities.layers` /
11
+ `additive` / `from:` / `global` / `agent-types` blocks are gone — activation is
12
+ derived from workspace defaults plus each soul's `capabilities:` — and its
13
+ `souls:` blocks are gone — per-instance provider content moved to
14
+ `oats spawn … --provider`. There is no `oats init`, no `oats use`, no config
15
+ scope chain, no adopted config templates. A 0.24.x deployment is rebuilt, not
16
+ converted: [rebuild-to-v2.md](rebuild-to-v2.md).
14
17
 
15
- ## Scopes
16
-
17
- Resolution walks from the soul's repository upward:
18
-
19
- 1. repository;
20
- 2. containing workspace(s); and
21
- 3. laptop/home.
22
-
23
- A `global` binding applies to all souls governed by the level that declares
24
- it. It does not escape that scope. This lets a laptop set defaults, a workspace
25
- add shared team capabilities, and one repository make a narrower choice.
26
-
27
- ```text
28
- ~/oats-config.yaml
29
- ~/workspace/oats-config.yaml
30
- ~/workspace/service/oats-config.yaml
31
- ```
32
-
33
- Use `oats doctor <context> --soul <name>` to inspect the result.
34
-
35
- ## Schema
18
+ ## The file
36
19
 
37
20
  ```yaml
38
- name: example-service
39
-
40
- # ── Team — the deployment boundary. The closest scope declaring team: wins;
41
- # every repo under it resolves the same team (identity, discovery, messaging).
42
- team:
43
- name: example-engineering
44
- # id: example-engineering:example.com # explicit provider team id (e.g. aweb <name>:<namespace>)
45
-
46
- # ── Agent types (families) ── declared here by name; each soul opts in via
47
- # `type: <name>` in its soul.yaml. Capability entries can target them.
48
- agent-types:
49
- developers:
50
- description: Agents that build and maintain the service
51
- reviewers:
52
- description: Agents that review changes
53
-
54
- capabilities:
55
- # Fundamental layers — exclusive slots; a capability entry or an explicit none.
56
- layers:
57
- knowledge:
58
- capability: oats.okf
59
- from: installed
60
- settings:
61
- bindings-file: /absolute/config/okf-bindings.json
62
- harvest-runtime: pi
63
- # harvest-model: provider/model # optional; default is runtime-selected
64
- # injection-override: .agents/injections/capabilities/oats.okf.md
65
- messaging: none
66
- tasks:
67
- capability: oats.linear
68
- from: installed
69
- agent-types:
70
- developers:
71
- enabled: true
72
- settings: {team: ENG}
73
- # injection-override: .agents/injections/capabilities/oats.linear.md
74
-
75
- # Additive capabilities — non-exclusive; target global, agent-types, or souls.
76
- additive:
77
- example.review:
78
- from: installed
79
- agent-types:
80
- developers:
81
- enabled: true
82
- settings:
83
- depth: normal
84
- souls:
85
- security-reviewer:
86
- enabled: true
87
- settings:
88
- depth: exhaustive
89
- # injection-override: .agents/injections/capabilities/example.review.md
90
-
91
- skill-overrides:
92
- review: example.review
93
-
94
- # ── Work modes — optional per-mode env bootstrap (briefings are packaged, not overridable).
95
- work-modes:
96
- worktree:
97
- # Runs inside each NEW worktree right after `git worktree add` — env setup
98
- # scripts (installs, .env copying, direnv/mise). Relative to this config's dir.
99
- setup: scripts/setup-worktree.sh
100
-
101
- # ── OATS defaults — the framework's baseline instruction block.
102
- oats:
103
- # injection-override: .agents/injections/oats-defaults/oats.md
104
-
105
- # Extra unconditional instruction blocks for every instance at this scope.
106
- agents-md-injection:
107
- repository: injects/repository.md
108
- ```
109
-
110
- ### `team`
111
-
112
- `team:` declares the deployment boundary — typically at the workspace scope.
113
- The closest scope declaring it wins, so every repo under `~/lfx` resolves the
114
- same team. `name:` is required; `id:` optionally pins the provider team id
115
- (for aweb, the canonical `<name>:<namespace>` form). Three things hang off
116
- it:
117
-
118
- - **Identity**: instances record their team in `instance.json` and their
119
- TASK.md briefing; hooks receive `OATS_TEAM_NAME`/`OATS_TEAM_ID`/`OATS_TEAM_SCOPE`.
120
- - **Discovery**: `oats status --team` lists agents across every `agents/`
121
- root in the team scope (the scope's own plus each member repo's), so an
122
- agent in one repo can see teammates defined at the workspace level or in
123
- sibling repos. There is no explicit member list — every repo under the
124
- team scope is a member by construction.
125
- - **Cross-repo spawn/retire**: `oats spawn <soul>` and `oats retire <instance>`
126
- resolve across the team scope's repos when the name isn't found locally
127
- (unique match wins; ambiguity errors with guidance to pass `--dir`). The
128
- instance homes with the soul's own repo, works in that repo, and resolves
129
- that repo's config chain — spawning from elsewhere changes nothing about
130
- the instance itself.
131
- - **Messaging**: the aweb integration joins spawned instances into the
132
- resolved team (id wins over name; a bare name is resolved against the aweb
133
- root's memberships), with the instance name as the discoverable alias.
134
- Because every instance joins with its own name, the aweb team roster is
135
- also the **cross-machine directory**: `oats aweb roster` lists team members
136
- wherever they run, complementing the local `oats status --team`.
137
-
138
- ### `agent-types`
139
-
140
- Agent types are agent families. Config declares type names (optionally with a
141
- description); membership is **not** listed in config — each soul opts in with
142
- an optional single `type: <name>` in its `soul.yaml` (`oats create --type <t>`
143
- sets it; `oats type add <name>` declares it in config). A type is identity: what kind of agent a soul is travels with the
144
- soul, while config decides what each type gets. Tags, dynamic selectors, and
145
- instance names are not supported.
146
-
147
- ### `capabilities.layers`
148
-
149
- The three fundamental layers — `knowledge`, `messaging`, `tasks` — are
150
- exclusive slots with an explicit home. Each slot holds either a capability
151
- entry (`capability: <id>` plus optional `from`, targets, `settings`,
152
- `injection-override`) or the explicit string `none`, which suppresses an integration
153
- inherited from an outer scope. A slot absent from a config inherits from
154
- outer scopes; `oats init` writes all three so the resolution is visible.
21
+ schemaVersion: 2
22
+ workspace: git:github.com/acme/agents # REQUIRED — the workspace host, observed over the remote
155
23
 
156
- The entry's capability must declare the same layer in its manifest; a
157
- mismatch is an error, as is a layer-declaring capability placed under
158
- `additive`. A layer entry with no explicit targets is globally enabled at
159
- that scope.
24
+ clones: # optional — member clones outside the <name>-workspace/ convention
25
+ github.com/acme/platform: /Users/ana/src/acme-platform
160
26
 
161
- ### `capabilities.additive`
27
+ settings: # optional — host-owned values per capability
28
+ oats.okf:
29
+ bindings-file: /Users/ana/.oats/okf-bindings.json
30
+ state-dir: /Users/ana/.oats/okf
31
+ oats.aweb:
32
+ delivery: channel
162
33
 
163
- Additive capabilities are non-exclusive packages keyed by capability ID. A
164
- declaration without `global`, `agent-types`, or `souls` is acquired but
165
- inactive. A target value can be `true`, `false`, or an object containing
166
- `enabled` and `settings`.
167
-
168
- For a soul, matching global, agent-type, and soul bindings compose. Setting
169
- precedence is:
170
-
171
- 1. soul;
172
- 2. matching agent-type;
173
- 3. global;
174
- 4. at equal target specificity, closer config scope.
175
-
176
- Conflicting values at equal specificity and the same scope are errors. OATS
177
- never uses YAML order as an implicit winner. `enabled: false` uses the same
178
- precedence, allowing global enable → type exclusion → soul re-enable.
179
-
180
- ### `from` (provenance)
181
-
182
- `from:` documents where the artifact must come from, and resolution enforces
183
- it: `installed` (acquired into `.agents/capabilities/installed/`,
184
- lock-governed — from the official marketplace by id, a git URL, or a local
185
- path), `owned` (authored at this scope under `.agents/capabilities/owned/`),
186
- or `path:<dir>` (development declaration pointing at a manifest directory).
187
- A mismatch between `from:` and the discovered artifact origin is an error.
188
- `from: bundled` was removed. Official capabilities are acquired like any other
189
- package, and acquisition never grants executable trust — approve executable
190
- surfaces explicitly with `oats trust <capability>`.
191
-
192
- ### `injection-override`
193
-
194
- Every injectable item — each capability entry, each work mode, and the `oats:`
195
- kernel block — accepts an `injection-override:` key: a config-relative path replaces
196
- the packaged instruction file, `none` suppresses it, and `default` restores
197
- it. The closest scope declaring the key wins. Scaffolded configs carry these
198
- as commented-out lines pointing at the conventional locations:
199
-
200
- ```text
201
- .agents/injections/capabilities/<capability-id>.md
202
- .agents/injections/oats-defaults/oats.md
34
+ souls: # optional — souls this machine does not run
35
+ disabled: [data-analyst]
203
36
  ```
204
37
 
205
- The clean path is `oats inject eject <capability|oats>`: it copies
206
- the packaged default to the conventional path and sets the key — the ejected
207
- file then deliberately stops tracking package updates. Overrides are not
208
- allowed on `from: owned`/`path:` entries: the scope owns the package source,
209
- so its `injects/` file is edited directly.
210
-
211
- ### `skill-overrides`
212
-
213
- Spawn fails when two sources contribute the same skill directory name. An
214
- explicit override maps that name to the winning source (`soul`, `kernel`, a
215
- capability ID, or a config source shown by doctor). Overrides are deliberate;
216
- OATS never keeps whichever filesystem entry happened to be discovered first.
217
-
218
- ### Instruction sources
219
-
220
- `agents-md-injection` adds unconditional config-owned instruction files (it
221
- adds content; it does not override packaged defaults — that is `injection-override:`).
222
- Capability packages can ship an `inject`; work modes have their own source.
38
+ Schema: [`oats-local.schema.json`](oats-local.schema.json). Unknown keys are
39
+ refused (`E_WORKSPACE_SCHEMA`).
223
40
 
224
- OATS reads the canonical soul `AGENTS.md`, composes selected blocks in a new
225
- instance file, and records every source. It never reconciles deployment
226
- instructions into the committed soul; spawn and doctor are the composition
227
- boundaries.
41
+ | key | meaning |
42
+ |---|---|
43
+ | `workspace` | Repo ref of the workspace host (`git:host/org/repo`, `https://…`, `git@host:…`, `file:///…`, `/abs/bare.git`). Read with your own Git credentials; the repo need not be cloned. |
44
+ | `clones` | `<canonical repo key>: <absolute path>` — where a member's clone lives when it is not at `<deployment>/<repo-name>/`. Only a soul's **work target** needs a clone. |
45
+ | `settings.<cap>.<key>` | Host-owned provider values the capability's manifest asks for — absolute paths, state roots, delivery modes. The workspace file **refuses** absolute paths; this is where they go. Merged into the capability's provider payload after the soul's own payload and before any `--provider` flag (see [three homes](workspaces.md#provider-payloads-have-three-homes)). |
46
+ | `souls.disabled` | Soul names not run on this machine; reported by `oats sync` ("disabled here"). |
228
47
 
229
- ### Work modes
48
+ ## Where it sits and how it is found
230
49
 
231
- Work modes remain soul/instance topology, not capability packages:
50
+ Every `oats` command that needs the workspace (`sync`, `workspace status`,
51
+ `capabilities`, `souls`, `spawn`, `status` drift) walks **up** from the current
52
+ directory (or `--dir`) to the nearest `oats-local.yaml`; its directory is the
53
+ deployment. Not found → `E_LOCAL_MISSING`. Beside it:
232
54
 
233
- - `worktree`: dedicated branch/worktree;
234
- - `checkout`: shared current checkout;
235
- - `attached`: another instance's work tree;
236
- - `workspace`: the whole team scope — cross-repo coordinators that read all
237
- member repos but never edit them (their soul's knowledge updates arrive as
238
- PRs to the soul's home repo).
239
-
240
- Work-mode briefings are packaged with the kernel and are not overridable;
241
- the only work-mode configuration is `setup:` — an env-bootstrap command that
242
- runs inside each fresh worktree after creation (a lot of teams prefer a
243
- script that sets up the environment: installs, .env copying, direnv/mise).
244
- Its failure warns without hiding the instance.
245
-
246
- ### `launch-configs`
247
-
248
- A named way to start a harness, independent of any soul: which runtime, an
249
- executable (a wrapper, another binary), literal arguments, environment, a
250
- model and yolo. Souls keep their own defaults; a launch configuration is
251
- selected by name at spawn or when an existing instance is started or
252
- restarted, so the same home can move between configurations without
253
- being replaced.
254
-
255
- ```yaml
256
- launch-configs:
257
- personal:
258
- runtime: claude
259
- executable: ./bin/claude-personal # relative: against THIS scope's directory
260
- args:
261
- - "--settings"
262
- - "/Users/me/.claude-personal/settings.json" # a native config file is an ordinary
263
- # argument the harness reads from the
264
- # INSTANCE HOME it starts in: absolute
265
- env:
266
- ANTHROPIC_API_KEY:
267
- fromEnv: PERSONAL_ANTHROPIC_KEY # resolved on the execution host at start
268
- CLAUDE_CONFIG_DIR: "/Users/me/.claude-personal"
269
- model: claude-opus-5
270
- yolo: true
271
- fast:
272
- runtime: codex
273
- model: gpt-5.5
274
55
  ```
275
-
276
- - The closest scope declaring a name provides the **whole** entry; a farther
277
- declaration of the same name is shadowed, never merged into.
278
- - `executable`: a bare name is looked up on `PATH` on the execution host; a
279
- path with a slash is resolved against the declaring scope when relative.
280
- It must exist and be executable; it is never run just to probe it.
281
- - `args` and literal `env` values are passed byte-exact: spaces, quotes and
282
- shell metacharacters are literal, never interpreted. A path among them is
283
- read by the harness from the instance home it starts in, not from the
284
- declaring scope: write native configuration paths absolute.
285
- - `env` values are either literals (non-secret by contract, but no answer ever
286
- shows them: `oats launch-config list` and `preview` redact them) or
287
- `{fromEnv: NAME}` references, which is the way to hand a secret to a
288
- harness. Only the reference is recorded in an instance's launch recipe and
289
- receipts; the value is read from the execution host's environment at start
290
- time, and a missing reference refuses the start before anything stops.
291
- - `model` and `yolo` override the soul's defaults when the configuration is
292
- selected; explicit `--model`/`--yolo` flags override the configuration.
293
-
294
- The CLI authors the block:
295
-
296
- ```sh
297
- oats launch-config list [--dir <scope> | --home <abs> | --soul <name>] --json
298
- oats launch-config set personal --file personal.json [--keep-env] --dir <scope>
299
- oats launch-config remove personal --dir <scope>
56
+ ~/acme-workspace/
57
+ ├── oats-local.yaml
58
+ ├── oats-lock.json # written by `oats sync` (lock v3; docs/packages.md)
59
+ ├── agents/ # instance homes + fetched member-soul sources
60
+ └── <member clones>/ # only where someone works IN a repo
300
61
  ```
301
62
 
302
- `set` and `remove` rewrite only the `launch-configs` block of that scope's
303
- `oats-config.yaml`; every other byte stays. `--keep-env` copies the
304
- environment of the definition effective at that scope for the name (its own,
305
- or the inherited one being overridden) into the complete new entry, once: an
306
- editor that saw only redacted values omits `env` from its definition. It is a
307
- copy at save time, not inheritance; the new entry shadows whole. `list --home`
308
- reads the home's recorded context; `list --soul` reads the soul's own member
309
- scope.
310
-
311
- ## Acquisition and lockfile
312
-
313
- External acquisition writes `oats-lock.json` beside the declaring config in
314
- `lockfileVersion: 2`. It records two levels — a `packages` map (source, exact
315
- commit, selected path, payload integrity, dependencies) and a `capabilities`
316
- map (each materialized capability's version, provider package, path, artifact
317
- integrity, and executable trust):
318
-
319
- ```json
320
- {
321
- "lockfileVersion": 2,
322
- "packages": {
323
- "example.engineering": {
324
- "source": "git:https://example.invalid/engineering.git@v1.4.2",
325
- "version": "1.4.2",
326
- "commit": "0123456789abcdef0123456789abcdef01234567",
327
- "path": "oats-package",
328
- "integrity": "sha256-…",
329
- "dependencies": []
330
- }
331
- },
332
- "capabilities": {
333
- "example.review": {
334
- "version": "1.4.2",
335
- "package": "example.engineering",
336
- "path": "capabilities/example-review",
337
- "integrity": "sha256-…",
338
- "trusted": false
339
- }
340
- }
341
- }
342
- ```
343
-
344
- No command silently updates this record. Changed capability integrity blocks the
345
- artifact and resets its trust. `oats trust <id>` approves commands, hooks, and
346
- launch-environment authority only for the exact locked artifact integrity, and
347
- official identity never grants it.
348
- Declarative skill/instruction capabilities need a valid lock but no executable
349
- approval. Capabilities authored under a scope's `.agents/capabilities/owned/`
350
- follow their reviewed source provenance. Materialized artifacts live in
351
- `.agents/capabilities/installed/<id>/` beside their lock, stay gitignored, and
352
- are re-materialized by bare `oats install` with integrity verification.
353
-
354
- Legacy `lockfileVersion: 1` locks (per-capability marketplace installs) remain
355
- readable and usable. `oats migrate` converts a scope to the revised v2 lock
356
- **all-or-nothing**: if any entry cannot map to a package yet, the whole scope
357
- stays byte-identical v1 and keeps working, and a successful run converts the
358
- entire scope at once. There is no residue container — a converted lock never
359
- carries leftover v1 entries. The earlier transitional v2 shape — capability
360
- lists on package rows, a persistent `.agents/packages/installed/` store — is
361
- rejected as an invalid lock and recreated by a fresh acquisition, never
362
- migrated. See `docs/capabilities.md` (“Distribution packages”), the schemas
363
- `docs/oats-package.schema.json` / `docs/oats-lock.schema.json`, and
364
- `docs/design/package-engine-contract.md`.
365
-
366
- ## CLI
367
-
368
- ```bash
369
- oats init [--raw] [--template <name|path|git-url>] [--knowledge <id|none>] [--messaging <id|none>] [--tasks <id|none>]
370
- oats install [<id|git-url|path>] [--dir <dir>] # acquire; bare form restores; inactive by default
371
- oats trust <capability> [--dir <dir>]
372
- oats use <capability> [--global|--type <t>|--soul <s>] [--disable] [--settings k=v [k2=v2 ...]]
373
- oats use none --layer <layer>
374
- oats type add <name> [--description <d>] # declare an agent type
375
- oats type list
376
- oats inject eject <capability|oats> # materialize an injection override
377
- oats create <name> --type <agent-type> ...
378
- oats doctor [context] --soul <name> [--json]
379
- ```
380
-
381
- `oats init` writes only explicitly selected defaults, acquiring marketplace
382
- layer capabilities into this scope's installed/ store as needed; it does not
383
- activate every acquired package. `oats use`
384
- places a layer-declaring capability under `capabilities.layers.<layer>` and
385
- everything else under `capabilities.additive`, regenerating the conventional
386
- injection comments; custom comments inside the `capabilities:` block are not
387
- preserved.
388
-
389
- `oats use` activates **into a config file**, so it needs one at this scope or an
390
- outer one. In a scope with no `oats-config.yaml` anywhere in its chain, a
391
- capability already present in that scope's own `installed/` or `owned/` store
392
- fails with `E_NO_CONFIG` naming the initialization to run first — exactly
393
- `oats init --raw --dir <scope>`, which is offline, deterministic and writes only
394
- the minimal config — and then the same `oats use` command again. It never
395
- reports the capability as unacquired, and it writes nothing: authoring a
396
- scope's first config is `oats init`'s job.
397
-
398
- ### Templates
399
-
400
- `oats init --template <name|path|git-url>` seeds the new config from a template
401
- config file: a local path, a git URL whose default branch carries an
402
- `oats-config.yaml`, or a name resolved through a `templates:` map declared in an
403
- outer scope (typically the laptop config):
404
-
405
- ```yaml
406
- # ~/oats-config.yaml
407
- templates:
408
- personal: ~/templates/personal-oats-config.yaml
409
- team: https://example.invalid/oats-templates.git
410
- ```
411
-
412
- A template seed is copied once. `init` copies the content, records provenance in
413
- a leading `# template:` comment, rewrites `name:`, strips the `templates:` map,
414
- and runs a restore so declared external capabilities are present. Later template
415
- edits never propagate silently.
416
-
417
- ### Package config templates
418
-
419
- When the config and its capability providers travel together, prefer
420
- `oats init --package <source> [--config <name>]`. It validates a reference config
421
- template shipped by a distribution package and writes it as your local
422
- `oats-config.yaml`, recording the exact template as a commit-safe adopted base
423
- with package, template, and commit provenance. `oats config diff` and
424
- `oats config sync` compare against that base later. Installing the package alone
425
- adopts no template. See [Distribution packages](packages.md).
426
-
427
- ## Fundamental-layer disable
428
-
429
- An inner scope can suppress an inherited integration without selecting a
430
- replacement:
431
-
432
- ```yaml
433
- capabilities:
434
- layers:
435
- tasks: none
436
- ```
437
-
438
- `oats use none --layer tasks` writes this. Pre-v0.9 spellings (`groups:`,
439
- top-level `layers:`, flat `capabilities.<id>` maps, `source:`,
440
- `agents-md-injection` on capability entries) are rejected with pointed
441
- migration errors. Key names are matched as own properties only, so a key
442
- spelled `constructor` or `toString` is reported as an unsupported key, never as
443
- a renamed one. `__proto__` is refused outright by every YAML reader — the
444
- kernel's and the desktop app's own read-only reader — and by the commands that
445
- WRITE config keys (`oats use --settings`, `--soul`, `--type`), all with
446
- `unsafe-config-key`: assigning it rewrites the parsed mapping's prototype
447
- instead of becoming data, which would hide the entry from every key validator.
448
- The kernel fails closed and reports the offending file; the desktop reader
449
- degrades that document to "not visible", per its read-only contract.
450
-
451
- Text that cannot be written as ONE YAML scalar on one line is refused. The
452
- policed inputs are exactly: `oats use --settings` keys and values, `oats use
453
- --soul` and `--type` names, `oats type add --description`, and the scaffolded
454
- `name:` value that `oats init` (in every form) and the first `oats use` / `oats
455
- type add` at a fresh scope take from the target directory's basename — a
456
- basename is filesystem input, so one carrying a newline would otherwise write
457
- arbitrary top-level blocks into the config.
458
-
459
- Refused: a control character (a newline in a `--settings` value used to inject
460
- whole extra capability entries into the file) or one of the three line breaks
461
- outside that range (U+0085, U+2028, U+2029 — U+2028/U+2029 made the reader drop
462
- the written line entirely, so the command reported success for a setting that
463
- was not there afterwards); leading or trailing whitespace a read would strip; a
464
- leading YAML structure indicator (`#`, `|`, `>`, `&`, `*`, `!`, `%`, `@`,
465
- `` ` ``, `,`, a quote, a flow bracket, or `- `/`? `/`: `); for a VALUE, an
466
- embedded `" #"` (which opens a trailing comment, so the rest would be dropped
467
- on read) and an empty value (`key:` with nothing after it reads back as an
468
- empty map, not an empty string); and — for keys and `--soul`/`--type` names —
469
- the `:` and `#` that end a key token. Those fail with `unsafe-config-value`
470
- (values, the scaffolded name included) or `unsafe-config-key` (keys and names),
471
- and nothing is written.
472
-
473
- The guarantee is a round trip through the OATS reader, not conformance to an
474
- external YAML parser: ordinary values are untouched because those characters
475
- are structural only in first position, so `expr=2 > 1`, `tag=v1.0#build`,
476
- `list=a,b` and even `mode=a: b` come back exactly as they were written.
477
-
478
- ## Worked examples
479
-
480
- ### All souls use OKF; only developers use Linear
481
-
482
- For OKF v2, every working soul needs an explicit `okf.json` owner declaration
483
- and provisioned external nodes. A `bindings-file` alone is not initialization.
484
- See [knowledge setup](knowledge.md#acquire-bind-and-provision-explicitly) and
485
- [v1 migration](knowledge-migration.md); target only ready souls if the rest of
486
- the scope is not yet configured. These examples describe the prepared v2 path.
487
-
488
- ```yaml
489
- agent-types:
490
- developers:
491
- description: Souls with type: developers in their soul.yaml
492
- capabilities:
493
- layers:
494
- knowledge:
495
- capability: oats.okf
496
- from: installed
497
- settings:
498
- bindings-file: /absolute/config/okf-bindings.json
499
- tasks:
500
- capability: oats.linear
501
- from: installed
502
- agent-types:
503
- developers:
504
- enabled: true
505
- settings: {team: ENG, project: Product}
506
- ```
507
-
508
- ### Laptop default with repository exclusion
509
-
510
- Laptop:
511
-
512
- ```yaml
513
- capabilities:
514
- layers:
515
- messaging:
516
- capability: oats.aweb
517
- from: installed
518
- ```
519
-
520
- Solo repository:
521
-
522
- ```yaml
523
- capabilities:
524
- layers:
525
- messaging: none
526
- ```
527
-
528
- ### One marketplace capability for one soul
529
-
530
- ```yaml
531
- capabilities:
532
- additive:
533
- vendor.security-review:
534
- from: installed
535
- souls:
536
- security-reviewer: true
537
- ```
63
+ Never commit `oats-local.yaml` to a shared repo: it names one machine's paths.
64
+ Two operators of the same workspace share the declarations through Git and
65
+ nothing else.
538
66
 
539
- Acquire and trust executable surfaces before spawn; target activation alone
540
- does not download, update, or approve code.
67
+ ## What is NOT in it
541
68
 
542
- ## Tmux scrolling during init
69
+ - **Which capabilities a soul gets** — the soul's `capabilities:` plus the
70
+ workspace `defaults` (and `defaults.byTeam`). There is no per-deployment
71
+ activation or targeting.
72
+ - **Versions** — `packages:` in the workspace file; exact commits in
73
+ `oats-lock.json`.
74
+ - **Trust** — membership for members; per-version approval in the lock for
75
+ packages. No per-operator trust list.
76
+ - **Per-instance provider facts** (a retained messaging seat, a one-off state
77
+ root) — `oats spawn <soul> --provider <cap> key=value`, recorded in
78
+ `instance.json.providers`.
79
+ - **Team labels, stores, messaging policy** — the workspace file.
543
80
 
544
- Interactive `oats init` offers to add `set -g mouse on` to the existing
545
- `~/.tmux.conf` or XDG tmux config so agent windows scroll normally with a mouse
546
- or trackpad. It never changes terminal keyboard mappings. Agent-led and
547
- scripted setup should pass the user's answer explicitly:
81
+ ## Inspecting the effective configuration
548
82
 
549
83
  ```bash
550
- oats init --tmux-mouse
551
- oats init --no-tmux-mouse
552
- oats init --raw --tmux-mouse
84
+ oats workspace status # membership table, locked packages, approval state, external souls
85
+ oats sync # confirm, resolve, approve, report the diff
86
+ oats capabilities | oats souls # everything a soul may name, with origin and team
87
+ oats spawn <soul> --preview # the exact modules (from/commit/changedSince), team, resolution revision
88
+ oats doctor # this deployment's oats-local.yaml and lock, plus kernel diagnostics
553
89
  ```
554
90
 
555
- An accepted change is idempotent and reloads a running tmux server when
556
- possible. This machine preference is separate from capability acquisition and
557
- activation.
91
+ Environment knobs the kernel honours: `OATS_REMOTE_CACHE` (relocates the
92
+ invisible fetch cache), `OATS_PACKAGE_CATALOG` (an alternative catalog file).