@awebai/oats 0.24.1 → 0.24.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/core.mjs CHANGED
@@ -51,6 +51,7 @@ import { buildCapturedInvocationContext, withCapturedInvocationContextFile } fro
51
51
  import { readCapturedInstanceIndex, readCapturedInstanceMetadata, readCapturedInstanceAuthority, assertCapturedInstanceCustody,
52
52
  recordCapturedCustodyFailure, markCapturedNativeScaffold, failCapturedNativeIntent, observeCapturedNativeTarget, setCapturedInstanceStatus, admitCapturedInstanceAction, beginCapturedIntent, settleCapturedIntent } from "./captured-instance-index.mjs";
53
53
  import { validateExecutionBinding } from "./schedule-capsule.mjs";
54
+ import { parsePortableSource } from "./source-spec.mjs";
54
55
  import { validateIntentRef } from "./captured-admission-shape.mjs";
55
56
  export { readCapturedInstanceIndex, readCapturedInstanceMetadata, beginCapturedIntent, settleCapturedIntent };
56
57
  export { buildCapturedInvocationContext, withCapturedInvocationContextFile };
@@ -112,6 +113,18 @@ export const OATS_VERSION = JSON.parse(readFileSync(join(PKG_ROOT, "package.json
112
113
  /** Skills shipped with the kernel. Only oats-getting-started is ambient; spawn composes selected skills locally. */
113
114
  export const PACKAGED_SKILLS_DIR = join(PKG_ROOT, "skills");
114
115
 
116
+ function soulRequirements(soulDir) {
117
+ const file = soulDir && join(soulDir, "soul.yaml");
118
+ return file && existsSync(file) ? withConfigFile(file, () => parseYamlNested(readFileSync(file, "utf8"))).requires : undefined;
119
+ }
120
+ function declaredOperationalCapabilities(soulDir) {
121
+ const capabilities = soulRequirements(soulDir)?.capabilities ?? {};
122
+ return ["oats.core", "oats.setup"].filter(id => Object.hasOwn(capabilities, id));
123
+ }
124
+ function legacyOperationalSkills(soulDir) {
125
+ return declaredOperationalCapabilities(soulDir).length ? [] : ["oats", "oats-config", "oats-packages"].map(name => ({ id: "kernel", path: join(PACKAGED_SKILLS_DIR, name) }));
126
+ }
127
+
115
128
  // ---------- shell helpers ----------
116
129
  function sh(cmdline) { return execSync(cmdline, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim(); }
117
130
  function shTry(cmdline) { try { return sh(cmdline); } catch { return undefined; } }
@@ -4083,6 +4096,10 @@ export function composeInstanceAgentsMd(soulDir, contextDir, soulName, workMode,
4083
4096
  if (!existsSync(agentsMd)) throw new Error(`canonical soul instructions missing: ${agentsMd}`);
4084
4097
  const resolved = resolveOatsConfig(contextDir, soulName);
4085
4098
  const wanted = [];
4099
+ const declaredOperations = declaredOperationalCapabilities(soulDir);
4100
+ const oatsCoreDeclared = declaredOperations.includes("oats.core");
4101
+ if (declaredOperations.length) resolved.kernelInjection = { inject: undefined,
4102
+ provenance: `declared ${declaredOperations.join(", ")} ${declaredOperations.length === 1 ? "capability" : "capabilities"}` };
4086
4103
  const kernelInject = resolved.kernelInjection?.inject;
4087
4104
  if (kernelInject && existsSync(kernelInject)) wanted.push(["kernel:oats", kernelInject]);
4088
4105
  if (kind === "local") {
@@ -4104,7 +4121,7 @@ export function composeInstanceAgentsMd(soulDir, contextDir, soulName, workMode,
4104
4121
  }
4105
4122
  for (const inj of resolved.injects) wanted.push([`config:${inj.source}`, inj.file]);
4106
4123
  const blocks = wanted.map(([source, file]) => ({ source, file, content: readFileSync(file, "utf8").trim() }));
4107
- return { text: renderInstructionText(readFileSync(agentsMd, "utf8"), blocks), blocks, resolved };
4124
+ return { text: renderInstructionText(readFileSync(agentsMd, "utf8"), blocks), blocks, resolved, oatsCoreDeclared };
4108
4125
  }
4109
4126
 
4110
4127
  /** The skill entries a tree contributes — THE discovery rule, shared by preflight
@@ -4162,7 +4179,7 @@ export function planInstanceResources({ resolved, soulDir, agent, contextDir, co
4162
4179
  }
4163
4180
  };
4164
4181
 
4165
- for (const path of [join(PACKAGED_SKILLS_DIR, "oats"), join(PACKAGED_SKILLS_DIR, "oats-config"), join(PACKAGED_SKILLS_DIR, "oats-packages")]) {
4182
+ for (const { path } of legacyOperationalSkills(soulDir)) {
4166
4183
  add({ type: "skill-tree", source: "kernel", declared: basename(path), path: existsSync(path) ? path : undefined });
4167
4184
  }
4168
4185
  const soulSkills = soulDir && join(soulDir, "skills");
@@ -5110,15 +5127,31 @@ export function resolveYolo(value) {
5110
5127
  throw new Error("yolo must be true or false");
5111
5128
  }
5112
5129
 
5113
- export function writeSoul(root, { name, kind, repo, work, runtime, model, yolo, description, type, instructions }) {
5130
+ /** Creation chooses a declared source, never acquisition/activation or a made-up
5131
+ * future release. Existing definitions (including deliberate removal) are kept. */
5132
+ function defaultOatsCoreRequirement() {
5133
+ const mapping = officialCapabilityPackage("oats.core");
5134
+ const entry = mapping.available && mapping.migratedCapability === "oats.core" && officialPackageCatalog()[mapping.package];
5135
+ if (entry && typeof entry.url === "string" && typeof entry.ref === "string" && entry.ref) {
5136
+ const parsed = parsePortableSource(`git:${entry.url}@${entry.ref}#${entry.path ?? DEFAULT_PACKAGE_PATH}`);
5137
+ return { requires: { capabilities: { "oats.core": { source: `${parsed.source}#${parsed.path}` } } }, notes: [] };
5138
+ }
5139
+ return { requires: undefined, notes: [{ code: "needs-configuration", message: "oats.core has no published revision in the official package catalog; no source was invented. Add its explicit requirement after the catalog entry is available, or use --no-oats-core to opt out at creation." }] };
5140
+ }
5141
+
5142
+ export function writeSoul(root, { name, kind, repo, work, runtime, model, yolo, description, type, instructions, oatsCore = true }) {
5114
5143
  yolo = resolveYolo(yolo);
5144
+ if (typeof oatsCore !== "boolean") throw oatsError("E_BAD_ARGS", "oatsCore must be a boolean");
5115
5145
  const agentDir = agentDirOf(root, name, kind);
5116
- const soulDir = soulOf(agentDir);
5146
+ const soulDir = soulOf(agentDir), soulFile = join(soulDir, "soul.yaml");
5147
+ const { requires, notes } = existsSync(soulFile)
5148
+ ? { requires: soulRequirements(soulDir), notes: [] }
5149
+ : oatsCore ? defaultOatsCoreRequirement() : { requires: undefined, notes: [] };
5117
5150
  mkdirSync(soulDir, { recursive: true });
5118
5151
  mkdirSync(join(agentDir, "instances"), { recursive: true });
5119
- writeFileSync(join(soulDir, "soul.yaml"), yamlFlat({
5152
+ writeFileSync(soulFile, yamlFlat({
5120
5153
  name, kind, description, type, repo, work: work || "checkout", runtime: runtime || "pi", model, yolo,
5121
- }));
5154
+ }) + (requires === undefined ? "" : `requires: ${JSON.stringify(requires)}\n`));
5122
5155
  const agentsMd = join(soulDir, "AGENTS.md");
5123
5156
  if (instructions !== undefined || !existsSync(agentsMd)) {
5124
5157
  writeFileSync(agentsMd, instructions ?? defaultSoulAgentsMd(name, description));
@@ -5132,7 +5165,7 @@ export function writeSoul(root, { name, kind, repo, work, runtime, model, yolo,
5132
5165
  home: soulDir, instance: name, agentName: name, soulDir,
5133
5166
  contextDir: ctx, workspaceDir: workspaceOf(root), rootDir: root, resolved,
5134
5167
  });
5135
- return { agentDir, soulDir };
5168
+ return { agentDir, soulDir, ...(notes.length ? { notes } : {}) };
5136
5169
  }
5137
5170
  function defaultSoulAgentsMd(name, description) {
5138
5171
  return `# ${name}
@@ -5154,8 +5187,8 @@ export function createAgent(root, o) {
5154
5187
  // kind: "local" → a FULL soul (memory, skills, instances) under the scope's
5155
5188
  // local-agents/ — uncommitted by contract; otherwise a committed persistent soul.
5156
5189
  const kind = o.local || o.kind === "local" ? "local" : "persistent";
5157
- const { agentDir } = writeSoul(root, { ...o, name, kind });
5158
- return { agent: name, kind, soul: soulOf(agentDir) };
5190
+ const { agentDir, notes } = writeSoul(root, { ...o, name, kind });
5191
+ return { agent: name, kind, soul: soulOf(agentDir), ...(notes ? { notes } : {}) };
5159
5192
  }
5160
5193
 
5161
5194
  /** Upsert a local agent soul (from raw instructions or a Claude-style def file).
@@ -5182,13 +5215,13 @@ export function upsertLocalAgent(root, o) {
5182
5215
  const existing = findAgent(root, name);
5183
5216
  if (existing && existing.kind !== "local") throw new Error(`"${name}" is a persistent agent — spawn it instead`);
5184
5217
  if (!existing && instructions === undefined) throw new Error(`local agent "${name}" needs instructions (none on disk yet)`);
5185
- writeSoul(root, {
5186
- name, kind: "local",
5218
+ const { notes } = writeSoul(root, {
5219
+ name, kind: "local", oatsCore: o.oatsCore,
5187
5220
  repo: repo ?? existing?.repo, work: work ?? existing?.work,
5188
5221
  runtime: runtime ?? existing?.runtime, model: model ?? existing?.model, yolo: yolo ?? existing?.yolo,
5189
5222
  description: description ?? existing?.description, instructions,
5190
5223
  });
5191
- return findAgent(root, name);
5224
+ return { ...findAgent(root, name), ...(notes ? { notes } : {}) };
5192
5225
  }
5193
5226
  /** Back-compat alias: older installed capabilities (oats-okf ≤1.3.x) call this. */
5194
5227
  export const upsertTmpAgent = upsertLocalAgent;
@@ -6136,7 +6169,7 @@ export function spawnInstance(root, agent, o = {}) {
6136
6169
  symlinkSync("AGENTS.md", join(home, "CLAUDE.md"));
6137
6170
 
6138
6171
  // Runtime-neutral exact skill materialization. No harness receives ambient workspace/package skills.
6139
- const sources = [{ id: "kernel", path: join(PACKAGED_SKILLS_DIR, "oats") }, { id: "kernel", path: join(PACKAGED_SKILLS_DIR, "oats-config") }, { id: "kernel", path: join(PACKAGED_SKILLS_DIR, "oats-packages") }];
6172
+ const sources = legacyOperationalSkills(soulDir);
6140
6173
  const soulSkills = join(soulDir, "skills");
6141
6174
  if (existsSync(soulSkills)) sources.push({ id: "soul", path: soulSkills });
6142
6175
  for (const cap of resolvedCfg.capabilities) for (const path of cap.skills || []) sources.push({ id: cap.id, path });
@@ -1,6 +1,8 @@
1
1
  /** Execute only an approved retained provider command. Preparation does not need
2
2
  * a fabricated complete resolution merely to obtain its binding. */
3
3
  import { spawnSync } from 'node:child_process';
4
+ import { realpathSync } from 'node:fs';
5
+ import { fileURLToPath } from 'node:url';
4
6
  import { canonicalJson } from './portable-values.mjs';
5
7
  import { objectAt } from './portable-shape.mjs';
6
8
  import { validateArtifactSet } from './resolution-shape.mjs';
@@ -12,6 +14,9 @@ import { validateBindingInterface } from './provider-binding.mjs';
12
14
  import { BINDING_LIMITS, validateBindingRequest, decodeBindingResponse } from './provider-binding-wire.mjs';
13
15
  import { oatsError } from './errors.mjs';
14
16
 
17
+ // Same kernel-owned CLI locator as lifecycle hooks; never caller env or PATH.
18
+ const CLI_BIN=fileURLToPath(new URL('../bin/oats.mjs',import.meta.url));
19
+
15
20
  export function invokeProviderBinding(options,codecs) {
16
21
  canonicalJson(options);
17
22
  objectAt(options,['deployment','artifacts','capability','phase','settings','input','timeoutMs'],['deployment','artifacts','capability','phase','settings','input']);
@@ -46,7 +51,7 @@ export function invokeProviderBinding(options,codecs) {
46
51
  const [script,...args]=spec.trim().split(/\s+/),file=codecs.executable(manifest,script);
47
52
  if (!file) throw oatsError('resource-not-found','provider codec executable is unavailable');
48
53
  const environment=Object.fromEntries(Object.entries(process.env).filter(([key])=>! /^(OATS_|OAS_|PI_)/.test(key)));
49
- Object.assign(environment,{OATS_CAPABILITY:capability,OATS_CAPABILITY_ROOT:root,OATS_SETTINGS:canonicalJson(settings,BINDING_LIMITS)});
54
+ Object.assign(environment,{OATS_CAPABILITY:capability,OATS_CAPABILITY_ROOT:root,OATS_SETTINGS:canonicalJson(settings,BINDING_LIMITS),OATS_CLI_BIN:realpathSync(CLI_BIN)});
50
55
  let result;
51
56
  try {
52
57
  result=spawnSync(process.execPath,[file,...args],{cwd:root,env:environment,input:canonicalJson(request,BINDING_LIMITS),
@@ -0,0 +1,76 @@
1
+ /** Read the setup edition as data for a CLASSIC local bootstrap copy.
2
+ * No provider code, workspace activation, enrollment or captured identity. */
3
+ import { lstatSync, mkdtempSync, readFileSync, readdirSync, readlinkSync, realpathSync, rmSync } from 'node:fs';
4
+ import { dirname, join } from 'node:path';
5
+ import { tmpdir } from 'node:os';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { parsePortableSoul } from './portable-soul.mjs';
8
+ import { parseRepositorySource, parsePortableSource } from './source-spec.mjs';
9
+ import { createRepositoryTransaction } from './repository-observation.mjs';
10
+ import { createWorkspaceDiscovery } from './workspace-discovery.mjs';
11
+ import { packageIntegrity } from './core.mjs';
12
+ import { oatsError } from './errors.mjs';
13
+
14
+ export const SETUP_EXPERT = 'oats-setup-expert';
15
+ export const SETUP_CAPABILITIES = Object.freeze(['oats.core', 'oats.setup']);
16
+ const EXPORT = `souls/${SETUP_EXPERT}`;
17
+ function validateEdition(bytes) {
18
+ const { declaration: soul } = parsePortableSoul(bytes);
19
+ const required = soul.requires || {}, caps = required.capabilities || {};
20
+ if (soul.name !== SETUP_EXPERT || soul.work !== 'directory'
21
+ || Object.keys(required).some(key => key !== 'capabilities')
22
+ || Object.keys(caps).length !== 2 || SETUP_CAPABILITIES.some(id => caps[id]?.source !== 'repo:oats-package' || Object.keys(caps[id]).some(key => key !== 'source'))
23
+ || ['knowledge', 'messaging', 'tasks'].some(slot => soul.defaults?.[slot] !== 'none')
24
+ || Object.keys(soul.defaults || {}).some(key => !['knowledge', 'messaging', 'tasks'].includes(key))
25
+ || soul.knowledge || soul.teams?.length || soul.resources?.length || soul.yolo === true || soul.backend || soul['launch-config']) {
26
+ throw oatsError('needs-configuration', 'classic setup bootstrap needs the provider-independent directory edition with only oats.core/oats.setup; use explicit portable preparation for other requirements');
27
+ }
28
+ return soul;
29
+ }
30
+ function repositoryRequest(source) {
31
+ if (typeof source !== 'string' || source.includes('#')) throw oatsError('invalid-source', '--workspace needs a Git repository source, optionally @revision, without a package fragment');
32
+ try { return { source: parseRepositorySource(source).normalized }; }
33
+ catch {
34
+ const parsed = parsePortableSource(source);
35
+ if (parsed.kind !== 'git') throw oatsError('invalid-source', '--workspace needs an explicit Git repository source');
36
+ return { source: `git:${parsed.url}`, revision: parsed.selector };
37
+ }
38
+ }
39
+
40
+ export function loadSetupExpertEdition(workspace, repositoryOptions = {}) {
41
+ if (workspace === undefined) {
42
+ const root = fileURLToPath(new URL(`../${EXPORT}/`, import.meta.url));
43
+ return { declaration: validateEdition(readFileSync(join(root, 'soul.yaml'))), instructions: readFileSync(join(root, 'AGENTS.md'), 'utf8'),
44
+ source: { kind: 'packaged-definition', captured: false }, packageIntegrity: null };
45
+ }
46
+ const request = repositoryRequest(workspace), scratch = realpathSync(mkdtempSync(join(tmpdir(), 'oats-setup-source-'))), owned = lstatSync(scratch);
47
+ let transaction;
48
+ try {
49
+ transaction = createRepositoryTransaction({ ...repositoryOptions, directory: scratch, accessContextKey: 'explicit-setup-source' });
50
+ const discovery = createWorkspaceDiscovery(transaction), origin = { kind: 'operator', document: { kind: 'operator', id: 'oats-onboard' }, pointer: '/workspace' };
51
+ const observed = transaction.observe(request.source, { ...request, origin });
52
+ const workspaceDoc = transaction.readFile(observed, 'oats-workspace.yaml', { optional: true });
53
+ const view = workspaceDoc ? discovery.readWorkspace({ ...request, origin }) : null;
54
+ const reference = view?.parsed.imports.find(item => item.alias === SETUP_EXPERT)
55
+ ?? { source: request.source, revision: observed.source.commit, soul: EXPORT, alias: SETUP_EXPERT };
56
+ // A selected workspace import never falls back if its exact source fails.
57
+ const imported = discovery.importSoul(reference, { origin });
58
+ if (reference.adoption) throw oatsError('needs-configuration', 'classic setup copies an edition only; provider adoption values require the portable preparation path');
59
+ const declaration = validateEdition(transaction.readFile(imported.observation, imported.definition).bytes);
60
+ const projection = join(scratch, 'edition');
61
+ transaction.materialize(imported.observation, imported.roots, projection);
62
+ const soulRoot = join(projection, dirname(imported.definition)), body = join(soulRoot, 'AGENTS.md'), alias = join(soulRoot, 'CLAUDE.md');
63
+ if (!lstatSync(body).isFile() || !lstatSync(alias).isSymbolicLink() || readlinkSync(alias) !== 'AGENTS.md'
64
+ || readdirSync(soulRoot).some(name => !['soul.yaml', 'AGENTS.md', 'CLAUDE.md'].includes(name))) {
65
+ throw oatsError('source-incomplete', 'classic setup edition must have canonical AGENTS.md/CLAUDE.md and no omitted private skill or knowledge trees');
66
+ }
67
+ return { declaration, instructions: readFileSync(body, 'utf8'), packageIntegrity: packageIntegrity(join(projection, 'oats-package')),
68
+ source: { kind: 'exported-edition-copy', source: imported.reference.source, revision: imported.observation.source.commit,
69
+ path: imported.reference.soul, workspaceRevision: view?.source.commit ?? null, captured: false } };
70
+ } finally {
71
+ transaction?.close();
72
+ const current = lstatSync(scratch);
73
+ if (!current.isDirectory() || current.dev !== owned.dev || current.ino !== owned.ino) throw oatsError('source-unavailable', 'setup source scratch ownership changed');
74
+ rmSync(scratch, { recursive: true });
75
+ }
76
+ }
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "oats.aweb": {
10
10
  "url": "https://github.com/awebai/oats-aweb.git",
11
- "ref": "v1.10.3",
11
+ "ref": "v1.11.0",
12
12
  "path": "oats-package"
13
13
  },
14
14
  "oats.jira": {
@@ -31,9 +31,9 @@
31
31
  "ref": "v1.0.0",
32
32
  "path": "oats-package"
33
33
  },
34
- "oats.knowledge-theory": {
34
+ "oats.framework": {
35
35
  "url": "https://github.com/awebai/oats.git",
36
- "ref": "v0.23.0",
36
+ "ref": "oats-framework/v1.1.1",
37
37
  "path": "oats-package"
38
38
  }
39
39
  },
@@ -66,6 +66,9 @@
66
66
  "oas.review": {
67
67
  "package": "oats.dev",
68
68
  "capability": "oats.review"
69
- }
69
+ },
70
+ "oats.knowledge-theory": "oats.framework",
71
+ "oats.core": "oats.framework",
72
+ "oats.setup": "oats.framework"
70
73
  }
71
74
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@awebai/oats",
3
- "version": "0.24.1",
3
+ "version": "0.24.2",
4
4
  "description": "OATS (Open Agent Team Specification) — durable souls, disposable instances, targetable capability packages, and the runtime-neutral oats CLI/kernel.",
5
5
  "keywords": [
6
6
  "agents",
@@ -36,6 +36,8 @@
36
36
  "docs/",
37
37
  "README.md",
38
38
  "package-catalog.json",
39
+ "souls/oats-setup-expert/soul.yaml",
40
+ "souls/oats-setup-expert/AGENTS.md",
39
41
  "packages/record/bin/",
40
42
  "packages/record/lib/",
41
43
  "packages/record/docs/",
@@ -0,0 +1,60 @@
1
+ # OATS Setup Expert
2
+
3
+ Help an operator turn an empty deployment into a deliberately configured OATS
4
+ workspace. Explain the next small decision, inspect the existing state, obtain
5
+ approval for effects, and verify the result before moving on. Do not replace
6
+ working deployments or turn setup into an implicit enrollment operation.
7
+
8
+ ## Your supplied procedures
9
+
10
+ - Load **oats-workspace-setup** for workspace/source discovery and adoption:
11
+ declare, inspect, prepare, approve, scaffold and start are different steps.
12
+ - Load **oats-config** for version-scoped classic configuration and targeting;
13
+ never use its cascade to fill a missing captured input.
14
+ - Load **oats-packages** for official package discovery, acquisition, exact locks,
15
+ executable approval and updates.
16
+ - Load **oats-operate** for lifecycle, directory boundaries and supported CLI
17
+ operations; load **oats-souls** for source editions, roster and relations.
18
+
19
+ Use the procedures actually included in your composition. Do not fetch a current
20
+ skill or invent a command when an older installed version lacks a feature.
21
+
22
+ ## Setup sequence
23
+
24
+ 1. Establish the operator's intended deployment, work target and workspace/source
25
+ separately. Inspect existing configuration, locks and souls before proposing
26
+ changes. A workspace is a shared definition, not a shared live runtime.
27
+ 2. Explain `oats-workspace.yaml` and each member's separate `oats.yaml` exports
28
+ and backlink. Check reciprocal observations; discovery is neither membership
29
+ enrollment nor capability activation. Pin imports only after a source is
30
+ published at a real reviewed revision; never invent a future commit or tag.
31
+ 3. Select capabilities and their exact sources with the operator. New souls
32
+ declare removable `oats.core` explicitly. Do not add knowledge, messaging or
33
+ tasks merely because the package was discovered or acquired.
34
+ 4. Keep package acquisition, executable approval, provider configuration and
35
+ native account/team authorization distinct. Inspect the exact artifact and
36
+ its effects before asking for approval. An official catalog entry is not a
37
+ blanket grant to execute hooks or change credentials.
38
+ 5. Use the supported prepare/approve/scaffold/start path for retained portable
39
+ adoption. Verify complete resources and required provider readiness before
40
+ native effects. A successful inspection, scaffold or submitted command is
41
+ not proof of a working session, message delivery or accepted learning.
42
+
43
+ ## Bootstrap and safety boundaries
44
+
45
+ This setup role has no hard knowledge or messaging dependency: it must be useful
46
+ before OKF or aweb is configured. Its defaults permit none. That does NOT permit
47
+ removing another soul's hard requirements to make a failing launch appear ready.
48
+
49
+ A classic local bootstrap copy is not a captured preparation or retained source
50
+ identity. Say which path created your current soul and do not claim one path's
51
+ receipts as evidence for the other. Keep a source edition and an operator-local
52
+ configuration distinct; never commit live identities, machine paths, accounts,
53
+ private bindings or credentials into exported source definitions.
54
+
55
+ Never auto-launch a model session, enable dangerous permissions, enroll an
56
+ identity, install a host service, overwrite an existing soul or migrate knowledge
57
+ without the operator's explicit instruction. Use ordinary native runtime auth;
58
+ missing auth is a human login step, not permission to inspect, copy or wrap
59
+ credentials. Preserve existing instances, pending jobs, locks and failed receipts.
60
+ Report unsupported operations or infrastructure faults instead of bypassing them.
@@ -0,0 +1,14 @@
1
+ schemaVersion: 1
2
+ name: oats-setup-expert
3
+ description: Guide an operator through OATS workspace adoption and explicit capability setup.
4
+ work: directory
5
+ requires:
6
+ capabilities:
7
+ oats.core:
8
+ source: repo:oats-package
9
+ oats.setup:
10
+ source: repo:oats-package
11
+ defaults:
12
+ knowledge: none
13
+ messaging: none
14
+ tasks: none