@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,180 @@
1
+ # OATS v0.22.0
2
+
3
+ OATS v0.22.0 is the first release under the OATS name. The framework release
4
+ includes `@awebai/oats@0.22.0`, `@awebai/oats-pi@0.22.0`, and OATS Desktop
5
+ 0.22.0.
6
+
7
+ The version number sits above every release of the OAS line (`@oas-framework/oas`
8
+ 0.21.2 is the latest as of this release) so that "OATS is at least OAS" holds
9
+ numerically. This release includes the OAS 0.20.1, 0.21.1, and 0.21.2
10
+ corrections, ported with their original authorship preserved; it does not
11
+ include the OAS 0.21.0 remote catalog fetch (see "Not included" below).
12
+
13
+ ## The rename: OAS is now OATS
14
+
15
+ Everything previously published as **OAS** (`@oas-framework/oas`,
16
+ `@oas-framework/pi`, the OAS Desktop) continues as **OATS** (`@awebai/oats`,
17
+ `@awebai/oats-pi`, OATS Desktop). The rename is a clean break: this kernel
18
+ recognizes no `oas-*` file name, no `oas:` config key, and no `oas.*`
19
+ capability id.
20
+
21
+ Deployments created by OAS must migrate, and now can:
22
+
23
+ ```bash
24
+ oats migrate --from-oas --dry-run --dir <scope> # full plan, touches nothing
25
+ oats migrate --from-oas --dir <scope> # convert this scope
26
+ ```
27
+
28
+ One transaction per scope: file renames (`oas-config.yaml`,
29
+ `oas-lock.json`, capability `oas.json` manifests, soul scaffold-owner
30
+ files), the `oas:` config key, and capability ids, then the guided package
31
+ conversion, so the scope ends on `lockfileVersion: 2` official packages.
32
+ Any failure restores the original OAS bytes; a second run is a no-op.
33
+ Executable trust is re-earned after conversion. See
34
+ [docs/migration-from-oas.md](../migration-from-oas.md).
35
+
36
+ Un-migrated OAS scopes are also **loud** now: `oats doctor` names them with
37
+ the remedy, and every `oats migrate` form exits nonzero instead of
38
+ reporting "nothing to migrate" on a scope that is actually a pre-rename
39
+ deployment.
40
+
41
+ The migration was verified against OAS 0.20.x deployments. OAS 0.21.x scopes
42
+ use the same file names, config keys, and capability ids, but the official
43
+ packages they lock may be the OAS v2.0.0 line, which the OATS catalog does not
44
+ yet carry; run the dry run first and read its plan.
45
+
46
+ ## Scope of the 0.18 upgrade guarantee, corrected
47
+
48
+ Earlier notes said existing valid v1 locks and installed capabilities
49
+ continue to work after a kernel upgrade. That claim holds for **OATS-named
50
+ scopes only** (`oats-config.yaml` / `oats-lock.json`). It was never true
51
+ for OAS-named deployments, whose files this kernel does not read; that is
52
+ exactly what `oats migrate --from-oas` is for.
53
+
54
+ ## Corrections ported from OAS 0.20.1, 0.21.1, and 0.21.2
55
+
56
+ These land here with the same behavior as in the OAS line, renamed.
57
+
58
+ - **Own-property config handling and `__proto__` rejection.** Config
59
+ parsing and diagnostics no longer consult inherited `Object.prototype`
60
+ properties anywhere: key dispatch, capability binding, command-owner lookup,
61
+ skill overrides, and shape validation are own-property. YAML keys named
62
+ `__proto__` are refused with the typed failure `unsafe-config-key`, and
63
+ the offending file is named.
64
+ - **Internal annotations cannot arrive from disk.** Underscore-prefixed
65
+ engine annotations (`_capabilityLock`, `_soulDir`, `_origin`, ...) are
66
+ stripped from every manifest and soul reader before the kernel annotates
67
+ them, so an on-disk document cannot assert its own provenance or silence
68
+ doctor's orphan warning.
69
+ - **Config writes fail closed.** Text that would change the shape of a
70
+ written config is refused with `unsafe-config-value` or
71
+ `unsafe-config-key` instead of being written: line breaks (including
72
+ U+0085, U+2028, U+2029), embedded `" #"`, empty values, leading YAML
73
+ structure indicators, and `:` or `#` in keys. This includes the scaffolded
74
+ `name:` line: `oats init`, and the first `oats use` or `oats type add` in a
75
+ fresh scope, refuse to run in a directory whose basename cannot be stored
76
+ as one YAML scalar. Home directories containing `$&`-style sequences are
77
+ expanded literally on every write path.
78
+ - **Typed CLI failure boundary.** `unsafe-config-key`, `unsafe-config-value`,
79
+ and `E_NO_CONFIG` render as one `oats:` line or one `--json` envelope
80
+ instead of a raw stack. Configless `oats use` reports `E_NO_CONFIG` with
81
+ the `oats init --raw` remedy instead of a misleading `acquired: none`.
82
+ Spawn no longer re-badges these as `E_SPAWN_FAILED`.
83
+ - **Scope-exact doctor and trust.** `oats doctor` judges each installed
84
+ artifact against the lock of the scope that installed it, reading revised-v2
85
+ `capabilities` rows directly instead of the merged chain, so a chain that
86
+ holds one package id at two scopes with different source spellings is no
87
+ longer reported as `invalid-lock`, and v2-locked capabilities are no longer
88
+ reported as orphans. Trust evaluation reads the row from the artifact's own
89
+ scope.
90
+ - **Desktop parity.** The Desktop deployment reader reads revised-v2
91
+ capability locks, refuses every lock shape the kernel refuses, and its
92
+ legacy-v1 artifact digest counts `.git` and nested lock files exactly as the
93
+ kernel does.
94
+ - **Package payload is never a deployment scope.** Bare `oats install` at a
95
+ team scope no longer reconciles config templates that live under a package
96
+ manifest (`oats-package.json`) as if they were live deployments, so a
97
+ workspace that develops packages stops failing reconciliation for
98
+ directories no operator could act on. The same walk backs
99
+ `oats migrate --official --recursive`.
100
+
101
+ ## The turn record: `oats capture | recall | setup`
102
+
103
+ The kernel now carries the turn record (`packages/record`): every
104
+ conversation an agent has, Claude Code, pi, and Codex sessions plus aw
105
+ mail and chat logs, captured as content-addressed turns in append-only,
106
+ owner-write journals, searchable with exact provenance.
107
+
108
+ ```bash
109
+ oats setup # install capture hooks + a background watcher, idempotent
110
+ oats capture # one reconciliation pass (--watch, --status, --install-hint)
111
+ oats recall <query> # full-text search over everything captured, with provenance
112
+ ```
113
+
114
+ The normative v1 format specification and its cross-language conformance
115
+ vectors ship inside the package (`packages/record/docs/`,
116
+ `packages/record/test/vectors/`).
117
+
118
+ `oats experimental <dress|spawn|segments|mind>` exists in the repo checkout
119
+ only, and deliberately never in this published package: the synthesis layer
120
+ above the record is unproven by design, and its absence from the tarball is
121
+ exactly its status.
122
+
123
+ ## Contract changes
124
+
125
+ - `oats migrate --dry-run --json` on a scope where `oas-config.yaml` /
126
+ `oas-lock.json` are visible now returns `ok: false` with code
127
+ `oas-scope-unmigrated` instead of `ok: true` with an empty plan. OATS-named
128
+ scopes see no change.
129
+ - `oats doctor --json` gains `oasScopes`, `oasRemedy`, and per-package
130
+ scope-exact rows. The exit code stays 0; automation gating on deployment
131
+ health should key on the fields, not the exit code.
132
+ - Guided migration plan rows gain `migratesTo`, and applied rows gain
133
+ `migratedTo`: the package catalog's capability aliases may carry a rename
134
+ (`"oas.okf": { "package": "oats.okf", "capability": "oats.okf" }`). All
135
+ seven ids published by OAS 0.20 are mapped.
136
+ - New typed failures: `unsafe-config-key`, `unsafe-config-value`, and
137
+ `E_NO_CONFIG` from configless `oats use`. Scripts matching error text
138
+ should match the typed codes.
139
+ - `oats init` and first-write commands refuse directory basenames that
140
+ cannot be stored as one YAML scalar (see above). Earlier releases wrote
141
+ such names verbatim.
142
+
143
+ ## Desktop
144
+
145
+ OATS Desktop 0.22.0 accepts a kernel with `desktopApi: 1` in the semver
146
+ range `>=0.22.0 <0.23.0`, probing `@awebai/oats`. The old OAS Desktop
147
+ probes for `@oas-framework/oas`; the old app and this CLI are mutually
148
+ invisible, so upgrade the CLI and the Desktop together. macOS arm64/x64
149
+ and Linux x64 installers are published on the GitHub Release with
150
+ checksums and provenance; macOS builds are ad-hoc signed (not notarized).
151
+ See [docs/desktop.md](../desktop.md) for the Gatekeeper steps.
152
+
153
+ ## Repository
154
+
155
+ - A `LICENSE` file (MIT) now ships with the kernel; `package.json` had
156
+ declared MIT without one.
157
+ - Root `npm test` is correct on a checkout without the Desktop's own
158
+ dependencies: it runs the Desktop suites when they are installed and
159
+ otherwise prints an unmissable notice with the install command.
160
+ - A runnerless release lane (`scripts/release-lane.mjs`) mirrors the release
161
+ workflow off GitHub Actions, so registry publish and hosted assets never
162
+ depend permanently on a runner.
163
+
164
+ ## Not included
165
+
166
+ - The OAS 0.21.0 **remote official catalog** (the kernel fetching
167
+ `package-catalog.json` from GitHub at resolution time). OATS resolves the
168
+ bundled catalog only. Held for a separate decision.
169
+ - The `@oas-framework/*` packages are **not deprecated** by this release;
170
+ that action belongs to their maintainer.
171
+
172
+ ## Install
173
+
174
+ ```bash
175
+ npm install -g @awebai/oats@latest
176
+ pi install npm:@awebai/oats-pi@latest
177
+ ```
178
+
179
+ Install matching kernel/adapter versions; they publish in lockstep from
180
+ one tag.
@@ -0,0 +1,344 @@
1
+ # Souls and instances
2
+
3
+ Souls and instances are the two layers the OATS kernel owns. A soul is the
4
+ expert. An instance is a named incarnation of that expert, with its own ID,
5
+ home, worktree, and lifecycle. It is not the same thing as one chat session.
6
+
7
+ ## Soul anatomy
8
+
9
+ A soul is durable and committed. It is the part you review, improve, and keep.
10
+
11
+ ```text
12
+ <agents-root>/<agent>/soul/
13
+ soul.yaml # name, repo, work mode, runtime, model
14
+ AGENTS.md # canonical operating doc
15
+ CLAUDE.md → AGENTS.md
16
+ skills/ # skills specific to this expert
17
+ knowledge/ # optional, created by the knowledge integration
18
+ ```
19
+
20
+ `soul.yaml` keys:
21
+
22
+ | Key | Meaning |
23
+ |---|---|
24
+ | `name` | Agent name. |
25
+ | `kind` | `persistent` for committed agents, `local` for full local souls under `local-agents/` (legacy `tmp` reads as `local`). |
26
+ | `description` | Short role description. |
27
+ | `repo` | Target repo, absolute or relative to the agents root's parent. |
28
+ | `work` | `worktree` or `checkout`. |
29
+ | `runtime` | `pi` or `claude` — the harness new instances launch on; a spawn can override with `--runtime`. For `claude`, the binary is `claude` unless a local-only `oats-claude-config` file (closest one walking up from the repo; one line naming the binary, e.g. `claude-personal`) selects another — a personal machine preference for account selection, never committed. With the aweb messaging integration active, claude sessions get the `aweb-channel` plugin wired at spawn for real-time push events. |
30
+ | `model` | Optional default model — a `provider/id[:thinking]` pattern or a comma-separated preference list (`github-copilot/x:high, anthropic/x:high`); at spawn the first entry whose provider/model is available wins (pi models probed via `pi --list-models`). For the `claude` runtime the value is translated to what the claude CLI accepts: `anthropic/<id>[:thinking]` becomes the bare `<id>`, aliases and bare `claude-*` ids pass through, other providers' entries are dropped, and nothing usable falls back to claude's own default. A spawn can override it. |
31
+
32
+ A soul is model-agnostic as an artifact. Its files are plain operating docs,
33
+ skills, and knowledge. `model` is only the default choice for new instances,
34
+ not part of the expert's identity.
35
+
36
+ A soul never runs by itself. It is incarnated as an instance. Editing a soul
37
+ is a code change.
38
+
39
+ Today the core soul artifacts are `AGENTS.md`, `skills/`, and any knowledge
40
+ bundle the knowledge integration creates. Future integrations may add other
41
+ expert-specific artifacts, such as Claude Code-like rule files or
42
+ runtime-specific guidance, while keeping `AGENTS.md` canonical.
43
+
44
+ ## Instance anatomy
45
+
46
+ An instance is transient, but it is not a single chat session. It is the
47
+ identity of one instantiated soul while that work is alive. Several sessions,
48
+ compactions, restarts, or model switches can happen inside the same instance
49
+ before it is retired.
50
+
51
+ An instance has a home directory, a task, and a worktree when the work mode
52
+ needs one. Its runtime setup is composed from the canonical soul plus
53
+ capabilities selected for that soul by the config scopes governing it.
54
+
55
+ A soul can have as many instances as people need. Instances are transient and
56
+ normally gitignored (`agents/*/instances/`). That matters for large or open
57
+ source repos: the expert souls can travel with the repo, while different
58
+ engineering teams instantiate those souls into their own local agent teams.
59
+ Their instance homes, logs, notes, branches, and messaging identities do not
60
+ collide because they are local runtime state, not shared soul state.
61
+
62
+ ```text
63
+ <agents-root>/<agent>/instances/<instance>/
64
+ soul → <agent>/soul/ # the agent setup for this instance
65
+ AGENTS.md # generated: canonical soul + selected blocks
66
+ CLAUDE.md → AGENTS.md
67
+ .agents/skills/ # exact soul + active capability set
68
+ .claude/skills → ../.agents/skills
69
+ work/ # worktree, checkout symlink, or attached tree
70
+ TASK.md # briefing and task
71
+ instance.json # repo/branch, spawn lineage, capabilities, skills, instructions, trust
72
+ STATE.md, log.md, notes/ # optional, from the knowledge integration
73
+ ```
74
+
75
+ Why some knowledge belongs in the soul (incarnation-invariant) and some in
76
+ the instance (this task, this branch, now) — regardless of which integration
77
+ or format you use — is covered in [knowledge theory](knowledge-theory.md).
78
+
79
+ The kernel does not define memory files. If the config resolves `knowledge:
80
+ okf`, the okf integration creates `STATE.md`, `log.md`, and `notes/`. If the
81
+ config resolves `knowledge: none`, those files do not exist.
82
+
83
+ ## Lifecycle
84
+
85
+ ### Spawn
86
+
87
+ The kernel creates the home, links the soul for reference, resolves capability
88
+ targets, generates instance instructions, materializes the exact local skill
89
+ set, prepares `work/`, runs active capability hooks, writes `TASK.md`, and
90
+ launches a full coding agent session in tmux. The committed soul is unchanged.
91
+ This is not a Claude Code subagent call; it is a normal agent process with its
92
+ own home and tools.
93
+
94
+ Examples of spawn hooks:
95
+
96
+ - `oats-okf` creates episodic memory files.
97
+ - `oats-aweb` mints a messaging identity.
98
+
99
+ ### Work
100
+
101
+ The instance works in `./work`. With oats-okf it also keeps `STATE.md` current,
102
+ appends milestones to `log.md`, and captures non-obvious insights in
103
+ `notes/`.
104
+
105
+ After committing with pending notes, the instance runs `oats okf harvest`
106
+ (its okf briefing says so). oats-okf spawns a memory-harvest agent attached to
107
+ the same work tree. The harvester promotes, merges, or drops notes, commits a
108
+ `memory-harvest:` change, deletes processed notes, and retires itself. This is
109
+ how long-lived instances feed their souls while still alive.
110
+
111
+ ### Spawning and coordinating with other agents
112
+
113
+ OATS agents can run `oats spawn` when their instructions or the
114
+ human ask them to create another expert instance. The spawned agent is another
115
+ full OATS instance, with its own soul, home, worktree, and lifecycle.
116
+
117
+ Spawn lineage is **explicit** and relation-based:
118
+ `oats spawn --relation child|sibling|parent|unrelated --relative-to <instance>`
119
+ declares what the new instance IS to an existing one (`--parent <instance>` is
120
+ sugar for `--relative-to <instance> --relation child`):
121
+
122
+ - **child** — nests under the anchor: `parentInstance` = anchor,
123
+ `spawnOrigin: instance`.
124
+ - **parent** — the NEW instance becomes the anchor's parent: it inherits the
125
+ anchor's old lineage slot, and the anchor's `instance.json` is re-pointed so
126
+ its `parentInstance` is the new instance (a reviewer/maintainer of your work
127
+ sits above you). Retirement splices lineage: when any instance retires,
128
+ instances pointing at it (parent or sibling links) inherit its COMPLETE
129
+ surviving lineage — both its parent and sibling links, whichever edge type
130
+ pointed at it — so a retired parent-relation maintainer hands its children
131
+ back to the parent it displaced (restoring absorbed sibling links too), and
132
+ no instance is left pointing at a missing one. The splice scans every agents
133
+ root in the team scope, since relations can cross member repos.
134
+ - **sibling** — a peer in the anchor's cluster: it shares the anchor's parent
135
+ when one exists; when the anchor is a root, the new instance records an
136
+ explicit `siblingInstance` link so the cluster is still derivable from
137
+ `oats status --json` (`parentInstance` + `siblingInstance` edges).
138
+ - **unrelated** (default) — no link, operator-origin, top-level.
139
+
140
+ Attached-mode spawns are ALWAYS children of the owner of the shared work tree
141
+ (design decision: an attached agent serves that owner); relation flags other
142
+ than a redundant child-of-owner are rejected. Any other spawn — including one
143
+ from a shell that inherited
144
+ an agent's environment variables — is operator-origin and appears top-level.
145
+ Agents spawning sub-agents should pass `--parent "$OATS_INSTANCE"` (or the
146
+ relation that fits).
147
+
148
+ If the workspace has a messaging integration such as aweb, spawned instances
149
+ can also receive identities and coordinate with each other automatically. The
150
+ task layer can provide shared work state while messaging provides conversation.
151
+
152
+ ### Retire
153
+
154
+ Retirement runs active capability retire hooks in reverse spawn order before the home disappears. The aweb
155
+ integration self-deletes the instance identity here. For oats-okf, retirement
156
+ is a knowledge no-op because harvest already happens after commits.
157
+
158
+ `oats retire <instance> --self` lets an instance retire itself when the human
159
+ or briefing says it is done. It runs hooks and removes the home first, then
160
+ delays the tmux window kill for a few seconds so the instance can report
161
+ final status.
162
+
163
+ ## Work modes
164
+
165
+ A work mode decides what `./work` points at and what discipline the agent must
166
+ follow. Every mode sits inside the same home/work boundary, which the generated
167
+ instructions state first (`injects/instance-boundary.md`):
168
+
169
+ - `<instance-home>` — the gitignored instance directory, `$OATS_INSTANCE_HOME` —
170
+ holds the brain (`AGENTS.md`, `soul/`), the task, the provenance
171
+ (`instance.json`) and the episodic state (`STATE.md`, `log.md`, `notes/`), and
172
+ is where OATS operational/lifecycle commands — and the commands of whatever
173
+ capabilities are active, `aw` among them when aweb messaging is — are run,
174
+ because they resolve scope from the working directory (`--dir <path>` to
175
+ target another one deliberately).
176
+ - `<instance-home>/work` — the repository or workspace view — is where
177
+ repository reading, editing, building, testing, git and commits happen, to the
178
+ extent the mode below permits.
179
+ - The home's `soul` link is to be treated as read-only: writes through it bypass
180
+ the branch and review path. Durable soul edits go through tracked paths under
181
+ `work/`, or through the harvester when the soul lives outside the repo.
182
+
183
+ Agents move between the two as the task needs; the boundary is what each
184
+ directory is for, not a place to settle in.
185
+
186
+ ### `worktree` — isolated branch
187
+
188
+ `work/` is a git worktree on the instance's own branch, by default
189
+ `agents/<instance>`.
190
+
191
+ Use this for agents that will edit code or docs independently.
192
+
193
+ Rules:
194
+
195
+ - Build, test, and commit from `work/`, on your own branch.
196
+ - Never run git from the repo's main checkout — it resolves to the wrong branch
197
+ and skips review.
198
+ - Do not create extra worktrees. Ask for another instance if parallel work is
199
+ needed.
200
+
201
+ A config may define `work-modes.worktree.setup`. The kernel runs that command
202
+ inside each fresh worktree. Failures warn but do not block spawn.
203
+
204
+ ### `checkout` — shared current branch
205
+
206
+ `work/` is a symlink to the repo checkout itself.
207
+
208
+ Use this for maintainers, coordinators, auditors, or agents working on the
209
+ repo's current state.
210
+
211
+ Rules:
212
+
213
+ - Stay on the currently checked-out branch.
214
+ - Do not switch branches unless explicitly asked.
215
+ - Avoid destructive git operations unless the human explicitly asks.
216
+
217
+ ### `attached` — another instance's tree
218
+
219
+ `work/` points at **another instance's work tree** — same branch, same
220
+ uncommitted state. Spawning attached requires `workDir` (the owning
221
+ instance's `<home>/work`); it is usually a spawn-time choice for service
222
+ agents (the memory-harvest agent uses it so its promotion commit lands on
223
+ the source instance's branch), but a soul whose role is always-attached
224
+ service work may declare it as identity too.
225
+
226
+ Attached agents are guests: never switch branches or rewrite history, touch
227
+ only what the briefing names, keep commits small and attributable. Retiring
228
+ an attached instance never removes the shared tree. The packaged
229
+ `work-attached` instruction source carries this discipline into each generated instance AGENTS.md.
230
+
231
+ ### `workspace` — cross-repo coordinator
232
+
233
+ `work/` is a symlink to the **whole workspace** (the team scope declared by
234
+ `team:`, else the workspace-scope config directory) — not a repo. Every
235
+ member repo is read-context; the instance's product is coordination:
236
+ routing, analysis, task-writing, messaging, spawning specialists.
237
+
238
+ Use this for free agents that support cross-repo work but are not tied to
239
+ any one repo — coordinators, dispatchers, architects. The soul itself still
240
+ lives in (and is committed to) its home repo (e.g. a workspace's
241
+ `lfx-agents/` repo); where the soul lives and where it works are decoupled.
242
+
243
+ Rules:
244
+
245
+ - Read freely across member repos; **never edit or commit inside them** —
246
+ route changes to the owning repo's agents or the human.
247
+ - No git state operations in any member repo.
248
+ - The one exception is the soul's own home repo: knowledge promotion writes
249
+ there via the knowledge layer's harvest, **as a PR on a branch**, never a
250
+ direct push (the OKF integration does this automatically for
251
+ workspace-mode instances).
252
+
253
+ Spawning workspace mode requires a declared boundary (a `team:` block or a
254
+ workspace-scope config); the instance records no branch — the workspace is
255
+ not a git tree.
256
+
257
+ ## Agents root
258
+
259
+ The agents root is the nearest `agents/` directory walking upward from the
260
+ current directory. `PI_AGENTS_ROOT` overrides the search.
261
+
262
+ **Where instances are stored is a separate question from where you invoked
263
+ OATS.** Discovery finds the root from your current directory, but instance homes
264
+ always live in the **soul-owning repo's primary checkout**: when the root you
265
+ discovered is inside a *linked git worktree*, storage maps to the equivalent
266
+ path in that repository's primary checkout, so homes survive the worktree, stay
267
+ visible to the whole deployment, and never depend on where a command happened to
268
+ run. An agent that spawns after `cd work/` reaches the same home as one spawning
269
+ from the deployment root.
270
+
271
+ Three things stay independent, and are meant to:
272
+
273
+ - **Invocation** — where you ran the command;
274
+ - **Config/package scope** — resolved from the context directory, and steerable
275
+ with an explicit `--dir <path>`;
276
+ - **`work/`** — the instance's repository view, which may well be a linked
277
+ worktree; only *storage* is redirected, never your work tree.
278
+
279
+ Roots that Git does not own are unaffected: a non-Git agents root stores
280
+ instances exactly where it sits.
281
+
282
+ Every instance is told its own home as **`OATS_INSTANCE_HOME`** (absolute), and
283
+ instructions refer to it as `<instance-home>`. The two environments differ, so
284
+ they are stated separately:
285
+
286
+ - **Runtime session**: `OATS_INSTANCE_HOME` and `PI_AGENT_HOME` (plus
287
+ `OATS_INSTANCE`/`PI_AGENT_INSTANCE`). The `PI_`-prefixed names are
288
+ compatibility aliases for the separately published pi extension.
289
+ - **Lifecycle hooks**: `OATS_INSTANCE_HOME` and `OATS_HOME`, alongside the rest of
290
+ the hook contract. `OATS_HOME` predates `OATS_INSTANCE_HOME` and is kept because
291
+ shipped capability hooks read it; it is **not** exported to runtime sessions.
292
+
293
+ Neither is `OATS_HOME_DIR`, which is the package store root — do not conflate
294
+ them.
295
+
296
+ When placement cannot be established — Git owns the location but the repository
297
+ cannot be read, a linked worktree whose primary checkout is missing, or a
298
+ resolved destination outside the agent's own directory — the spawn fails closed
299
+ with **`E_NO_CANONICAL_ROOT`** and creates nothing.
300
+
301
+ ### Deployment prerequisite: the agents directory must be operator-owned
302
+
303
+ The canonical deployment (the agents root, `local-agents/`, and the instance
304
+ homes under them) **must be owned by the operator and not writable by untrusted
305
+ users or processes.** OATS validates resolved destinations and re-checks the home
306
+ immediately before creating anything in it, but it cannot defeat a concurrent
307
+ local attacker who already has write access there: Node offers no
308
+ `openat`/`O_NOFOLLOW`-relative directory creation, so a path can in principle be
309
+ swapped between the check and the creation. Anyone with that access also
310
+ controls souls, generated instructions, hook declarations and instance state, so
311
+ this is a deployment prerequisite — filesystem ownership and permissions — not
312
+ something the kernel can close from inside.
313
+
314
+ Default layout:
315
+
316
+ ```text
317
+ <scope>/
318
+ agents/ # committed souls
319
+ docs-expert/
320
+ soul/
321
+ instances/
322
+ local-agents/ # local souls — same shape, never committed
323
+ scratch-agent/
324
+ soul/
325
+ instances/
326
+ ```
327
+
328
+ `local-agents/` sits BESIDE `agents/` at the scope level and holds **full local
329
+ souls**: complete souls (memory, skills, knowledge, instances) that are not
330
+ committed to the repo. `oats create <name> --local` creates one — the directory
331
+ is created on first use, and when the scope is a git repo the kernel adds
332
+ `local-agents/` to its `.gitignore` automatically. A scope with only
333
+ `local-agents/` is fully operable: people can use OATS with local agents alone.
334
+ Ad hoc agents from `oats spawn --instructions-file`/`--def-file` land here too.
335
+ Legacy nested `agents/local-agents/` and `agents/tmp-agents/` are still read
336
+ for compatibility.
337
+
338
+ Instances of a local soul receive a `local-soul` briefing: work and commits
339
+ are normal, but soul updates are plain file edits (nothing to commit), and
340
+ durability is the machine's — promote the soul to `agents/` when it starts to
341
+ matter beyond one machine.
342
+
343
+ Alternative agents-root layouts are planned but not built. Today the default
344
+ layout is the only implemented layout.
@@ -0,0 +1,7 @@
1
+ ## OATS framework workspace (sticky)
2
+
3
+ You are an OATS framework agent. The framework's generic skills govern your work:
4
+ **okf** (knowledge bundles), **memory-harvest** (promotion judgment),
5
+ **skill-craft** and **soul-craft** (creating/maintaining skills and souls).
6
+ The implementation you steward lives in this repo (`extension/`, `skills/`, `injects/`), installed via `pi install`.
7
+ Changes to the framework are proposed to the human before landing.
@@ -0,0 +1,43 @@
1
+ ## Your two directories
2
+
3
+ **`<instance-home>` is where this session starts** — the specific gitignored OATS
4
+ instance directory you woke up in, given to your runtime and to every lifecycle
5
+ hook as `$OATS_INSTANCE_HOME`. It is not your user home (`~`), not the repository
6
+ root, and not the work tree. Anything that says "your home" means this directory.
7
+
8
+ - **Your brain and your state live here**: `AGENTS.md` (your composed
9
+ instructions), `soul/` (your durable knowledge), `TASK.md` (this task),
10
+ `instance.json` (what you were given and from where), and whatever working
11
+ state your role keeps — your knowledge layer names those files, if you have
12
+ one. They belong here, not in the work tree.
13
+ - **Run OATS operational/lifecycle commands, and commands from active
14
+ capabilities, from instance home** — `oats status`, `oats doctor`, `oats spawn`,
15
+ `oats retire`, and whatever your own capabilities add; for example, when the
16
+ aweb messaging capability is active, run `aw` there too. They resolve their
17
+ scope from the directory you run them in, so running them from the work tree
18
+ points them at the wrong deployment. To act on a different package or config
19
+ scope deliberately, pass an explicit resolved path: `oats <cmd> --dir <path>`.
20
+ - **The home's `soul` link is not your edit surface.** It is there so you can
21
+ READ your durable knowledge. Writing through it changes durable state outside
22
+ your branch, where no review sees it and nothing records what changed or why.
23
+ If your TASK is to change soul content that lives in this repository, that is
24
+ ordinary code work — do it on tracked paths under `work/`, reviewed like the
25
+ rest. How your own learnings reach your soul is your knowledge layer's
26
+ business, and its instructions below say so if you have one.
27
+
28
+ **`<instance-home>/work` is your repository or workspace view** — whatever your
29
+ work mode grants you of the code.
30
+
31
+ - **Repository work happens there and only there**: reading, editing, building,
32
+ testing, git and commits, on repository content. Never from the main checkout
33
+ or from your home root.
34
+ - **What your mode permits is the mode block's call**, immediately below. Some
35
+ modes are read-only, some share a tree with others, and that block is the
36
+ authority on which operations are yours to perform.
37
+ - This is about where the *repository's* content lives, not a ban on writing
38
+ anywhere else: the episodic files above, and whatever artifacts your role
39
+ calls for (a report written to a temp file before mailing it, a scratch
40
+ script), go where your task and tooling direct.
41
+
42
+ Move between the two as the task needs — the boundary is what each directory is
43
+ *for*, not a place to settle in.
@@ -0,0 +1,19 @@
1
+ ## Local soul (uncommitted)
2
+
3
+ You are a **local agent**: a full OATS soul that lives in your deployment's
4
+ `local-agents/` directory, beside the committed `agents/` roster. The only
5
+ difference from a committed soul is custody: **your soul is not committed to
6
+ any repo** — it exists only on this machine, ignored by version control.
7
+
8
+ What this changes — and what it does not:
9
+
10
+ - **Work is unchanged.** Your `./work`, branches, commits, and task flow are
11
+ exactly those of any other instance. Commit your repository work normally.
12
+ - **Custody changes delivery, not your job.** Whatever updates your soul writes
13
+ here directly — no git commit, no PR, because this directory is not
14
+ version-controlled — and the change takes effect for every future instance of
15
+ this soul on this machine immediately. There is no branch to review it on,
16
+ which is the reason the `soul` link is not yours to edit by hand.
17
+ - **Durability is your machine's.** Your soul has no remote backup; if it
18
+ matters long-term, tell your human it deserves promotion to a committed
19
+ soul in `agents/`.
@@ -0,0 +1,11 @@
1
+ ## You run on OATS
2
+
3
+ You are an agent instance in the OATS (Open Agent Team Specification) framework.
4
+ You incarnate a durable soul (`./soul/`), you work in `./work/`, and you can
5
+ be retired when your task ends. The **oats** skill teaches the essentials —
6
+ your home layout, the agent roster (`oats status`), spawning and
7
+ retiring instances (only when instructed), inspecting your configuration
8
+ (`oats doctor`, `./instance.json`), and your lifecycle. **Load the oats skill
9
+ before your first `oats` command of a session** and any time you reason about
10
+ agents, spawning, or the framework itself — do not guess `oats` flags or
11
+ subcommands from memory.
@@ -0,0 +1,16 @@
1
+ ## Work mode: attached
2
+
3
+ Your `./work` is a symlink to **another instance's work tree** — you share
4
+ their branch and their uncommitted state. You are a guest in their workspace.
5
+
6
+ - **Never switch branches, never rebase, never reset** — the tree belongs to
7
+ its owner; your job is focused additions on top of their current state.
8
+ - Keep your changes and commits **small and clearly attributable** (your
9
+ instance name in commit messages where ambiguity is possible).
10
+ - Do not touch files the owner is mid-editing unless your task says so; when
11
+ in doubt, coordinate through your messaging layer or your spawner.
12
+ - Retiring you never removes the shared tree — cleanup of the tree is the
13
+ owner's concern, not yours.
14
+
15
+ This mode fits service agents (harvesters, reviewers, fixers) that operate
16
+ on a live instance's work in flight.
@@ -0,0 +1,12 @@
1
+ ## Work mode: checkout
2
+
3
+ Your `./work` is a symlink to the repo's **shared checkout** — you are working
4
+ in the same tree as the human and possibly other agents.
5
+
6
+ - **Work on the currently checked-out branch; never switch branches unless
7
+ explicitly asked.**
8
+ - No destructive git operations (reset --hard, rebase, force-push, checkout
9
+ of another branch) without an explicit human instruction.
10
+ - This mode fits integrator/coordinator/advisory roles operating on the
11
+ repo's *current state*; if your task needs its own branch, ask your human
12
+ for a worktree-mode instance instead.
@@ -0,0 +1,22 @@
1
+ ## Work mode: workspace
2
+
3
+ Your `./work` is the **whole workspace** (the deployment/team scope), not a
4
+ single repo. Every member repo under it is visible context. You are a
5
+ cross-repo coordinator: your product is routing, analysis, and coordination —
6
+ not code changes.
7
+
8
+ - **Read freely across all member repos; never edit or commit inside them.**
9
+ Repo changes are routed to that repo's own agents (see `oats status --team`,
10
+ your task layer, or messaging) or to the human.
11
+ - No git state operations in any member repo: no branch switching, no
12
+ commits, no worktrees, no resets.
13
+ - Your own working state lives in your instance home, not in any member repo,
14
+ and needs no git ceremony.
15
+ - If one of your capabilities delivers durable updates into a repo, its own
16
+ instructions define where and how — including whether anything is committed at
17
+ all, and by whom. That is its business, not an exception you take into a
18
+ member repo yourself.
19
+
20
+ This mode fits coordinators, dispatchers, architects, and analysts whose
21
+ scope is the workspace itself; if a task needs actual edits in one repo, ask
22
+ for (or route to) a worktree-mode instance of that repo's agent instead.