@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,482 @@
1
+ # Configuration
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.
7
+
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.
14
+
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
36
+
37
+ ```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
+ harvest-model: github-copilot/gpt-5.5
62
+ # injection-override: .agents/injections/capabilities/oats.okf.md
63
+ messaging: none
64
+ tasks:
65
+ capability: oats.linear
66
+ from: installed
67
+ agent-types:
68
+ developers:
69
+ enabled: true
70
+ settings: {team: ENG}
71
+ # injection-override: .agents/injections/capabilities/oats.linear.md
72
+
73
+ # Additive capabilities — non-exclusive; target global, agent-types, or souls.
74
+ additive:
75
+ example.review:
76
+ from: installed
77
+ agent-types:
78
+ developers:
79
+ enabled: true
80
+ settings:
81
+ depth: normal
82
+ souls:
83
+ security-reviewer:
84
+ enabled: true
85
+ settings:
86
+ depth: exhaustive
87
+ # injection-override: .agents/injections/capabilities/example.review.md
88
+
89
+ skill-overrides:
90
+ review: example.review
91
+
92
+ # ── Work modes — optional per-mode env bootstrap (briefings are packaged, not overridable).
93
+ work-modes:
94
+ worktree:
95
+ # Runs inside each NEW worktree right after `git worktree add` — env setup
96
+ # scripts (installs, .env copying, direnv/mise). Relative to this config's dir.
97
+ setup: scripts/setup-worktree.sh
98
+
99
+ # ── OATS defaults — the framework's baseline instruction block.
100
+ oats:
101
+ # injection-override: .agents/injections/oats-defaults/oats.md
102
+
103
+ # Extra unconditional instruction blocks for every instance at this scope.
104
+ agents-md-injection:
105
+ repository: injects/repository.md
106
+ ```
107
+
108
+ ### `team`
109
+
110
+ `team:` declares the deployment boundary — typically at the workspace scope.
111
+ The closest scope declaring it wins, so every repo under `~/lfx` resolves the
112
+ same team. `name:` is required; `id:` optionally pins the provider team id
113
+ (for aweb, the canonical `<name>:<namespace>` form). Three things hang off
114
+ it:
115
+
116
+ - **Identity**: instances record their team in `instance.json` and their
117
+ TASK.md briefing; hooks receive `OATS_TEAM_NAME`/`OATS_TEAM_ID`/`OATS_TEAM_SCOPE`.
118
+ - **Discovery**: `oats status --team` lists agents across every `agents/`
119
+ root in the team scope (the scope's own plus each member repo's), so an
120
+ agent in one repo can see teammates defined at the workspace level or in
121
+ sibling repos. There is no explicit member list — every repo under the
122
+ team scope is a member by construction.
123
+ - **Cross-repo spawn/retire**: `oats spawn <soul>` and `oats retire <instance>`
124
+ resolve across the team scope's repos when the name isn't found locally
125
+ (unique match wins; ambiguity errors with guidance to pass `--dir`). The
126
+ instance homes with the soul's own repo, works in that repo, and resolves
127
+ that repo's config chain — spawning from elsewhere changes nothing about
128
+ the instance itself.
129
+ - **Messaging**: the aweb integration joins spawned instances into the
130
+ resolved team (id wins over name; a bare name is resolved against the aweb
131
+ root's memberships), with the instance name as the discoverable alias.
132
+ Because every instance joins with its own name, the aweb team roster is
133
+ also the **cross-machine directory**: `oats aweb roster` lists team members
134
+ wherever they run, complementing the local `oats status --team`.
135
+
136
+ ### `agent-types`
137
+
138
+ Agent types are agent families. Config declares type names (optionally with a
139
+ description); membership is **not** listed in config — each soul opts in with
140
+ an optional single `type: <name>` in its `soul.yaml` (`oats create --type <t>`
141
+ sets it; `oats type add <name>` declares it in config). A type is identity: what kind of agent a soul is travels with the
142
+ soul, while config decides what each type gets. Tags, dynamic selectors, and
143
+ instance names are not supported.
144
+
145
+ ### `capabilities.layers`
146
+
147
+ The three fundamental layers — `knowledge`, `messaging`, `tasks` — are
148
+ exclusive slots with an explicit home. Each slot holds either a capability
149
+ entry (`capability: <id>` plus optional `from`, targets, `settings`,
150
+ `injection-override`) or the explicit string `none`, which suppresses an integration
151
+ inherited from an outer scope. A slot absent from a config inherits from
152
+ outer scopes; `oats init` writes all three so the resolution is visible.
153
+
154
+ The entry's capability must declare the same layer in its manifest; a
155
+ mismatch is an error, as is a layer-declaring capability placed under
156
+ `additive`. A layer entry with no explicit targets is globally enabled at
157
+ that scope.
158
+
159
+ ### `capabilities.additive`
160
+
161
+ Additive capabilities are non-exclusive packages keyed by capability ID. A
162
+ declaration without `global`, `agent-types`, or `souls` is acquired but
163
+ inactive. A target value can be `true`, `false`, or an object containing
164
+ `enabled` and `settings`.
165
+
166
+ For a soul, matching global, agent-type, and soul bindings compose. Setting
167
+ precedence is:
168
+
169
+ 1. soul;
170
+ 2. matching agent-type;
171
+ 3. global;
172
+ 4. at equal target specificity, closer config scope.
173
+
174
+ Conflicting values at equal specificity and the same scope are errors. OATS
175
+ never uses YAML order as an implicit winner. `enabled: false` uses the same
176
+ precedence, allowing global enable → type exclusion → soul re-enable.
177
+
178
+ ### `from` (provenance)
179
+
180
+ `from:` documents where the artifact must come from, and resolution enforces
181
+ it: `installed` (acquired into `.agents/capabilities/installed/`,
182
+ lock-governed — from the official marketplace by id, a git URL, or a local
183
+ path), `owned` (authored at this scope under `.agents/capabilities/owned/`),
184
+ or `path:<dir>` (development declaration pointing at a manifest directory).
185
+ A mismatch between `from:` and the discovered artifact origin is an error.
186
+ `from: bundled` was removed. Official capabilities are acquired like any other
187
+ package, and acquisition never grants executable trust — approve executable
188
+ surfaces explicitly with `oats trust <capability>`.
189
+
190
+ ### `injection-override`
191
+
192
+ Every injectable item — each capability entry, each work mode, and the `oats:`
193
+ kernel block — accepts an `injection-override:` key: a config-relative path replaces
194
+ the packaged instruction file, `none` suppresses it, and `default` restores
195
+ it. The closest scope declaring the key wins. Scaffolded configs carry these
196
+ as commented-out lines pointing at the conventional locations:
197
+
198
+ ```text
199
+ .agents/injections/capabilities/<capability-id>.md
200
+ .agents/injections/oats-defaults/oats.md
201
+ ```
202
+
203
+ The clean path is `oats inject eject <capability|oats>`: it copies
204
+ the packaged default to the conventional path and sets the key — the ejected
205
+ file then deliberately stops tracking package updates. Overrides are not
206
+ allowed on `from: owned`/`path:` entries: the scope owns the package source,
207
+ so its `injects/` file is edited directly.
208
+
209
+ ### `skill-overrides`
210
+
211
+ Spawn fails when two sources contribute the same skill directory name. An
212
+ explicit override maps that name to the winning source (`soul`, `kernel`, a
213
+ capability ID, or a config source shown by doctor). Overrides are deliberate;
214
+ OATS never keeps whichever filesystem entry happened to be discovered first.
215
+
216
+ ### Instruction sources
217
+
218
+ `agents-md-injection` adds unconditional config-owned instruction files (it
219
+ adds content; it does not override packaged defaults — that is `injection-override:`).
220
+ Capability packages can ship an `inject`; work modes have their own source.
221
+
222
+ OATS reads the canonical soul `AGENTS.md`, composes selected blocks in a new
223
+ instance file, and records every source. It never reconciles deployment
224
+ instructions into the committed soul; spawn and doctor are the composition
225
+ boundaries.
226
+
227
+ ### Work modes
228
+
229
+ Work modes remain soul/instance topology, not capability packages:
230
+
231
+ - `worktree`: dedicated branch/worktree;
232
+ - `checkout`: shared current checkout;
233
+ - `attached`: another instance's work tree;
234
+ - `workspace`: the whole team scope — cross-repo coordinators that read all
235
+ member repos but never edit them (their soul's knowledge updates arrive as
236
+ PRs to the soul's home repo).
237
+
238
+ Work-mode briefings are packaged with the kernel and are not overridable;
239
+ the only work-mode configuration is `setup:` — an env-bootstrap command that
240
+ runs inside each fresh worktree after creation (a lot of teams prefer a
241
+ script that sets up the environment: installs, .env copying, direnv/mise).
242
+ Its failure warns without hiding the instance.
243
+
244
+ ## Acquisition and lockfile
245
+
246
+ External acquisition writes `oats-lock.json` beside the declaring config in
247
+ `lockfileVersion: 2`. It records two levels — a `packages` map (source, exact
248
+ commit, selected path, payload integrity, dependencies) and a `capabilities`
249
+ map (each materialized capability's version, provider package, path, artifact
250
+ integrity, and executable trust):
251
+
252
+ ```json
253
+ {
254
+ "lockfileVersion": 2,
255
+ "packages": {
256
+ "example.engineering": {
257
+ "source": "git:https://example.invalid/engineering.git@v1.4.2",
258
+ "version": "1.4.2",
259
+ "commit": "0123456789abcdef0123456789abcdef01234567",
260
+ "path": "oats-package",
261
+ "integrity": "sha256-…",
262
+ "dependencies": []
263
+ }
264
+ },
265
+ "capabilities": {
266
+ "example.review": {
267
+ "version": "1.4.2",
268
+ "package": "example.engineering",
269
+ "path": "capabilities/example-review",
270
+ "integrity": "sha256-…",
271
+ "trusted": false
272
+ }
273
+ }
274
+ }
275
+ ```
276
+
277
+ No command silently updates this record. Changed capability integrity blocks the
278
+ artifact and resets its trust. `oats trust <id>` approves commands, hooks, and
279
+ launch-environment authority only for the exact locked artifact integrity, and
280
+ official identity never grants it.
281
+ Declarative skill/instruction capabilities need a valid lock but no executable
282
+ approval. Capabilities authored under a scope's `.agents/capabilities/owned/`
283
+ follow their reviewed source provenance. Materialized artifacts live in
284
+ `.agents/capabilities/installed/<id>/` beside their lock, stay gitignored, and
285
+ are re-materialized by bare `oats install` with integrity verification.
286
+
287
+ Legacy `lockfileVersion: 1` locks (per-capability marketplace installs) remain
288
+ readable and usable. `oats migrate` converts a scope to the revised v2 lock
289
+ **all-or-nothing**: if any entry cannot map to a package yet, the whole scope
290
+ stays byte-identical v1 and keeps working, and a successful run converts the
291
+ entire scope at once. There is no residue container — a converted lock never
292
+ carries leftover v1 entries. The earlier transitional v2 shape — capability
293
+ lists on package rows, a persistent `.agents/packages/installed/` store — is
294
+ rejected as an invalid lock and recreated by a fresh acquisition, never
295
+ migrated. See `docs/capabilities.md` (“Distribution packages”), the schemas
296
+ `docs/oats-package.schema.json` / `docs/oats-lock.schema.json`, and
297
+ `docs/design/package-engine-contract.md`.
298
+
299
+ ## CLI
300
+
301
+ ```bash
302
+ oats init [--raw] [--template <name|path|git-url>] [--knowledge <id|none>] [--messaging <id|none>] [--tasks <id|none>]
303
+ oats install [<id|git-url|path>] [--dir <dir>] # acquire; bare form restores; inactive by default
304
+ oats trust <capability> [--dir <dir>]
305
+ oats use <capability> [--global|--type <t>|--soul <s>] [--disable] [--settings k=v [k2=v2 ...]]
306
+ oats use none --layer <layer>
307
+ oats type add <name> [--description <d>] # declare an agent type
308
+ oats type list
309
+ oats inject eject <capability|oats> # materialize an injection override
310
+ oats create <name> --type <agent-type> ...
311
+ oats doctor [context] --soul <name> [--json]
312
+ ```
313
+
314
+ `oats init` writes only explicitly selected defaults, acquiring marketplace
315
+ layer capabilities into this scope's installed/ store as needed; it does not
316
+ activate every acquired package. `oats use`
317
+ places a layer-declaring capability under `capabilities.layers.<layer>` and
318
+ everything else under `capabilities.additive`, regenerating the conventional
319
+ injection comments; custom comments inside the `capabilities:` block are not
320
+ preserved.
321
+
322
+ `oats use` activates **into a config file**, so it needs one at this scope or an
323
+ outer one. In a scope with no `oats-config.yaml` anywhere in its chain, a
324
+ capability already present in that scope's own `installed/` or `owned/` store
325
+ fails with `E_NO_CONFIG` naming the initialization to run first — exactly
326
+ `oats init --raw --dir <scope>`, which is offline, deterministic and writes only
327
+ the minimal config — and then the same `oats use` command again. It never
328
+ reports the capability as unacquired, and it writes nothing: authoring a
329
+ scope's first config is `oats init`'s job.
330
+
331
+ ### Templates
332
+
333
+ `oats init --template <name|path|git-url>` seeds the new config from a template
334
+ config file: a local path, a git URL whose default branch carries an
335
+ `oats-config.yaml`, or a name resolved through a `templates:` map declared in an
336
+ outer scope (typically the laptop config):
337
+
338
+ ```yaml
339
+ # ~/oats-config.yaml
340
+ templates:
341
+ personal: ~/templates/personal-oats-config.yaml
342
+ team: https://example.invalid/oats-templates.git
343
+ ```
344
+
345
+ A template seed is copied once. `init` copies the content, records provenance in
346
+ a leading `# template:` comment, rewrites `name:`, strips the `templates:` map,
347
+ and runs a restore so declared external capabilities are present. Later template
348
+ edits never propagate silently.
349
+
350
+ ### Package config templates
351
+
352
+ When the config and its capability providers travel together, prefer
353
+ `oats init --package <source> [--config <name>]`. It validates a reference config
354
+ template shipped by a distribution package and writes it as your local
355
+ `oats-config.yaml`, recording the exact template as a commit-safe adopted base
356
+ with package, template, and commit provenance. `oats config diff` and
357
+ `oats config sync` compare against that base later. Installing the package alone
358
+ adopts no template. See [Distribution packages](packages.md).
359
+
360
+ ## Fundamental-layer disable
361
+
362
+ An inner scope can suppress an inherited integration without selecting a
363
+ replacement:
364
+
365
+ ```yaml
366
+ capabilities:
367
+ layers:
368
+ tasks: none
369
+ ```
370
+
371
+ `oats use none --layer tasks` writes this. Pre-v0.9 spellings (`groups:`,
372
+ top-level `layers:`, flat `capabilities.<id>` maps, `source:`,
373
+ `agents-md-injection` on capability entries) are rejected with pointed
374
+ migration errors. Key names are matched as own properties only, so a key
375
+ spelled `constructor` or `toString` is reported as an unsupported key, never as
376
+ a renamed one. `__proto__` is refused outright by every YAML reader — the
377
+ kernel's and the desktop app's own read-only reader — and by the commands that
378
+ WRITE config keys (`oats use --settings`, `--soul`, `--type`), all with
379
+ `unsafe-config-key`: assigning it rewrites the parsed mapping's prototype
380
+ instead of becoming data, which would hide the entry from every key validator.
381
+ The kernel fails closed and reports the offending file; the desktop reader
382
+ degrades that document to "not visible", per its read-only contract.
383
+
384
+ Text that cannot be written as ONE YAML scalar on one line is refused. The
385
+ policed inputs are exactly: `oats use --settings` keys and values, `oats use
386
+ --soul` and `--type` names, `oats type add --description`, and the scaffolded
387
+ `name:` value that `oats init` (in every form) and the first `oats use` / `oats
388
+ type add` at a fresh scope take from the target directory's basename — a
389
+ basename is filesystem input, so one carrying a newline would otherwise write
390
+ arbitrary top-level blocks into the config.
391
+
392
+ Refused: a control character (a newline in a `--settings` value used to inject
393
+ whole extra capability entries into the file) or one of the three line breaks
394
+ outside that range (U+0085, U+2028, U+2029 — U+2028/U+2029 made the reader drop
395
+ the written line entirely, so the command reported success for a setting that
396
+ was not there afterwards); leading or trailing whitespace a read would strip; a
397
+ leading YAML structure indicator (`#`, `|`, `>`, `&`, `*`, `!`, `%`, `@`,
398
+ `` ` ``, `,`, a quote, a flow bracket, or `- `/`? `/`: `); for a VALUE, an
399
+ embedded `" #"` (which opens a trailing comment, so the rest would be dropped
400
+ on read) and an empty value (`key:` with nothing after it reads back as an
401
+ empty map, not an empty string); and — for keys and `--soul`/`--type` names —
402
+ the `:` and `#` that end a key token. Those fail with `unsafe-config-value`
403
+ (values, the scaffolded name included) or `unsafe-config-key` (keys and names),
404
+ and nothing is written.
405
+
406
+ The guarantee is a round trip through the OATS reader, not conformance to an
407
+ external YAML parser: ordinary values are untouched because those characters
408
+ are structural only in first position, so `expr=2 > 1`, `tag=v1.0#build`,
409
+ `list=a,b` and even `mode=a: b` come back exactly as they were written.
410
+
411
+ ## Worked examples
412
+
413
+ ### All souls use OKF; only developers use Linear
414
+
415
+ ```yaml
416
+ agent-types:
417
+ developers:
418
+ description: Souls with type: developers in their soul.yaml
419
+ capabilities:
420
+ layers:
421
+ knowledge:
422
+ capability: oats.okf
423
+ from: installed
424
+ tasks:
425
+ capability: oats.linear
426
+ from: installed
427
+ agent-types:
428
+ developers:
429
+ enabled: true
430
+ settings: {team: ENG, project: Product}
431
+ ```
432
+
433
+ ### Laptop default with repository exclusion
434
+
435
+ Laptop:
436
+
437
+ ```yaml
438
+ capabilities:
439
+ layers:
440
+ messaging:
441
+ capability: oats.aweb
442
+ from: installed
443
+ ```
444
+
445
+ Solo repository:
446
+
447
+ ```yaml
448
+ capabilities:
449
+ layers:
450
+ messaging: none
451
+ ```
452
+
453
+ ### One marketplace capability for one soul
454
+
455
+ ```yaml
456
+ capabilities:
457
+ additive:
458
+ vendor.security-review:
459
+ from: installed
460
+ souls:
461
+ security-reviewer: true
462
+ ```
463
+
464
+ Acquire and trust executable surfaces before spawn; target activation alone
465
+ does not download, update, or approve code.
466
+
467
+ ## Tmux scrolling during init
468
+
469
+ Interactive `oats init` offers to add `set -g mouse on` to the existing
470
+ `~/.tmux.conf` or XDG tmux config so agent windows scroll normally with a mouse
471
+ or trackpad. It never changes terminal keyboard mappings. Agent-led and
472
+ scripted setup should pass the user's answer explicitly:
473
+
474
+ ```bash
475
+ oats init --tmux-mouse
476
+ oats init --no-tmux-mouse
477
+ oats init --raw --tmux-mouse
478
+ ```
479
+
480
+ An accepted change is idempotent and reloads a running tmux server when
481
+ possible. This machine preference is separate from capability acquisition and
482
+ activation.
@@ -0,0 +1,73 @@
1
+ # Conventions — canonical files and generated views
2
+
3
+ OATS uses one canonical source for durable soul content and generated,
4
+ instance-local views for deployment composition.
5
+
6
+ ## Operating documents
7
+
8
+ ```text
9
+ soul/AGENTS.md # canonical role instructions
10
+ soul/CLAUDE.md -> AGENTS.md
11
+ instance/AGENTS.md # generated regular file
12
+ instance/CLAUDE.md -> AGENTS.md
13
+ ```
14
+
15
+ Never maintain an independent soul `CLAUDE.md`. Config-dependent capability,
16
+ work-mode, and workspace instructions belong only in generated instance
17
+ `AGENTS.md`; they must not be reconciled into the committed soul.
18
+
19
+ Generated blocks use `<!-- oats:<source> src=<file> -->` markers for
20
+ provenance. Edit the canonical soul, source file, or target binding, then spawn
21
+ a new instance. `oats doctor --soul <name>` previews the same final composition.
22
+
23
+ ## Skills
24
+
25
+ The only OATS-managed runtime skill root is the instance:
26
+
27
+ ```text
28
+ instance/.agents/skills/ # canonical exact set
29
+ instance/.claude/skills -> ../.agents/skills
30
+ ```
31
+
32
+ Spawn copies kernel + soul-private + active capability skills into real
33
+ instance-local directories there. Directory symlinks are not used because
34
+ harness recursive discovery may not descend through them. Packages retain
35
+ skills in their own artifact; activation selects them for materialization. Config-level `.agents/skills` is not an OATS capability source
36
+ or an ambient runtime discovery root.
37
+
38
+ Pi starts spawned sessions with ambient skill and context discovery disabled
39
+ and the one instance path explicit; its globally configured extensions remain
40
+ enabled. Claude runs provider-native: it reads the instance's `.claude/skills`
41
+ and `CLAUDE.md` symlinks, and the operator's own user and project
42
+ configuration — skills, plugins, settings — stays in effect. Neither runtime
43
+ gets a redirected config home. `composition.materialized.runtimePosture` in
44
+ `instance.json` records what each instance actually exposes.
45
+ `oats-getting-started` is the sole pre-workspace ambient bootstrap.
46
+
47
+ Duplicate skill directory names are errors unless config's `skill-overrides`
48
+ selects a source.
49
+
50
+ ## Package locations
51
+
52
+ ```text
53
+ <package>/capabilities/<name>/oats.json # the official marketplace (install source, not ambient)
54
+ <level>/.agents/capabilities/installed/<name>/oats.json # acquired (gitignored, restorable)
55
+ <level>/.agents/capabilities/owned/<name>/oats.json # authored at this scope (source; committed where the scope is a repo)
56
+ <level>/oats-lock.json # external source/integrity/trust
57
+ ```
58
+
59
+ ## Quick map
60
+
61
+ | Thing | Canonical location |
62
+ |---|---|
63
+ | Config | `<level>/oats-config.yaml` |
64
+ | Acquisition lock | `<level>/oats-lock.json` |
65
+ | Soul operating doc | `soul/AGENTS.md` |
66
+ | Soul Claude view | `soul/CLAUDE.md -> AGENTS.md` |
67
+ | Soul-private skills | `soul/skills/` |
68
+ | Instance operating doc | `instance/AGENTS.md` (generated) |
69
+ | Instance skill set | `instance/.agents/skills/` |
70
+ | Instance metadata | `instance/instance.json` |
71
+
72
+ Symlinks prevent compatibility paths from drifting. Generated regular files
73
+ separate canonical portable identity from scope-dependent runtime policy.