@happyvertical/smrt-playbooks 0.44.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.
package/AGENTS.md ADDED
@@ -0,0 +1,174 @@
1
+ # smrt-playbooks
2
+
3
+ Layered playbook registry, app/tenant overrides, and plan resolution. A
4
+ playbook is a named, described, layered sequence of steps an agent follows;
5
+ browser agents, in-app agents, the Node MCP server, and the CLI all follow the
6
+ same resolved plan. Fourth instance of the `smrt-prompts` layered-override
7
+ pattern — keep it consistent with `prompts`, `languages`, and `features`.
8
+
9
+ ## Core pieces
10
+
11
+ - `definePlaybook()` registers code defaults in a global process registry
12
+ (`globalThis.__smrtPlaybookRegistry`), so a package-bundled playbook resolves
13
+ with no application registration
14
+ - `resolvePlaybook()` merges the layers and returns a `PlaybookResolution`
15
+ - `PlaybookOverride` (`_smrt_playbook_overrides`) stores partial app-level and
16
+ tenant-level overrides with write-time validation
17
+ - `PlaybookOverrideCollection` exposes the standard SmrtCollection CRUD surface
18
+
19
+ ## Resolution layers (priority low → high)
20
+
21
+ 1. Code default — `definePlaybook({ key, title, description, steps })`
22
+ 2. File/config override — `getPackageConfig<PlaybookPackageConfig>('playbooks', defaults)`
23
+ 3. App-level stored override — `PlaybookOverride` row with `tenantId = null`
24
+ 4. Tenant-level stored override — `PlaybookOverride` row with the current tenant
25
+ 5. Runtime override — passed to `resolvePlaybook(key, { override })`
26
+
27
+ Inheritance is field-by-field: a stored column is nullable, and `null` means
28
+ "use the lower layer".
29
+
30
+ ## Script semantics
31
+
32
+ A playbook resolves to a plan the agent executes step by step. **It never
33
+ executes as a unit** (epic #2585 invariant 4), so it is never an authority
34
+ boundary and adds no new security object to review. Each step is authorized
35
+ independently — at the REST boundary in the browser, or by
36
+ `PrincipalRun.assertToolAllowed()` server-side. Nothing in this package
37
+ executes a step, and there is deliberately no executor export.
38
+
39
+ Playbooks are consequently never atomic and have no compensation.
40
+ `onStepFailure` (`'abort'` | `'continue'`) is the whole of the contract for
41
+ what an agent does when step 3 of 5 fails.
42
+
43
+ ## Steps
44
+
45
+ Exactly two kinds in v1, and playbooks cannot nest:
46
+
47
+ - `{ kind: 'operation', model: '@happyvertical/smrt-commerce:Order', action: 'submit' }`
48
+ — the qualified pair already used by STI discriminators and
49
+ `@crossPackageRef`. **Never a generated tool name**: that is derived from
50
+ model, action, and namespace, and would silently orphan stored tenant
51
+ overrides on a namespace change.
52
+ - `{ kind: 'intent', id }` — a view intent named by its declared #2588
53
+ identity. Valid only where a surface is mounted.
54
+
55
+ A step referencing another playbook is rejected in `normalizeSteps()` at
56
+ definition time.
57
+
58
+ ### Classification is inherited, never self-declared
59
+
60
+ A step never classifies itself. `resolvePlaybook()` takes a
61
+ `classifier` (and, for intents, an `intents` registry) supplied by the host,
62
+ which returns the `CapabilityDeclaration` emitted for the referenced operation
63
+ by `@happyvertical/smrt-types`. Anything undeclared resolves fail-closed to
64
+ `{ effect: 'destructive', idempotent: false, openWorld: true }`. The
65
+ vocabulary itself is older and lower and shared with model tools — it lives in
66
+ `smrt-types`, not here (owning it here would close a
67
+ core → playbooks → core cycle).
68
+
69
+ ## Plane validity
70
+
71
+ A playbook declares `planes: readonly ('browser' | 'server')[]`. Resolution for
72
+ a caller on an undeclared plane fails closed with reason
73
+ `'plane-not-declared'`.
74
+
75
+ - Operation-only playbooks default to both planes.
76
+ - A playbook containing a view-intent step defaults to `['browser']`. Server
77
+ validity rides the shipped #2446 browser command/ack bridge, which lets a
78
+ server-side agent drive mounted surfaces with acknowledgement — it must be
79
+ **declared explicitly**, never assumed.
80
+ - The same default applies one level down: a `PlaybookIntentRecord` that
81
+ declares no `planes` is browser-only, so server validity must be declared at
82
+ **both** the playbook and the intent. Silence from the intent registry never
83
+ widens a plane (`'intent-plane-not-declared'`).
84
+
85
+ The `#2588` intent registry does not exist yet, so an intent step with no
86
+ `intents` resolver supplied fails closed with
87
+ `'intent-registry-unavailable'`. That resolver is the seam #2588 wires into.
88
+
89
+ ## Editability
90
+
91
+ `editable` defaults **all-false**, matching `normalizeEditableConfig` in
92
+ `smrt-prompts`. Every stored column has a flag — `title`, `description`,
93
+ `planes`, `onStepFailure`, `enabled`, `metadata` — and `save()` rejects a
94
+ non-null value for any field the definition has not opted in. `onStepFailure`
95
+ is gated like the rest: flipping a locked playbook from `'abort'` to
96
+ `'continue'` would change what an agent does after a failed prerequisite.
97
+
98
+ `steps` is **structurally** non-editable, not merely defaulted false:
99
+
100
+ - `PlaybookEditableConfig` has no `steps` key, and marking one throws at
101
+ definition time
102
+ - `_smrt_playbook_overrides` has **no `steps` column**, so no write of any kind
103
+ has anywhere to put a step list
104
+ - `PlaybookOverride.save()` rejects a `steps` property assigned through the
105
+ untyped option bag rather than dropping it silently
106
+ - `normalizePlaybookLayer()` throws on a `steps` key from the config or runtime
107
+ layer
108
+ - the resolver reads steps only from `PlaybookRegistry`
109
+
110
+ The reason is not escalation — under the script model a tenant cannot escalate,
111
+ since every step is authorized independently regardless of who wrote the list.
112
+ It is that an agent announcing "checking out your cart" while an overridden
113
+ step list does something else is a description-behavior mismatch.
114
+
115
+ Enablement overrides are one-directional: a layer may disable, never re-enable
116
+ what a lower layer disabled. Enforced in `mergePlaybookLayers()` (`enabled &&
117
+ layer.enabled`) and rejected at `save()` with a specific message. Plane lists
118
+ narrow the same way.
119
+
120
+ ## Caching
121
+
122
+ Resolutions are cached per `(key, tenantId, db)` with a TTL. The cache is
123
+ invalidated on `PlaybookOverride.save()` and `.delete()`; an app-level write
124
+ (`tenantId = null`) clears every tenant's entry for that key, because each
125
+ tenant inherits from it. Use `clearPlaybookCache()` in tests.
126
+
127
+ A monotonic per-`(db, key)` invalidation generation closes the read-racing-a-
128
+ write window; see the Gotchas entry below before touching `cache.ts`.
129
+
130
+ ## Gotchas
131
+
132
+ - **`context` carries the tenant scope.** `save()` sets
133
+ `this.context = this.tenantId ?? '__app__'` and `conflictColumns` is
134
+ `['key', 'context']`. `tenantId` is nullable, and a unique index over it
135
+ would let multiple NULL rows coexist on PostgreSQL and DuckDB. The `context`
136
+ trick (from `smrt-languages`) is what makes the same upsert correct on all
137
+ three dialects — do not "simplify" it to `['key', 'tenantId']`.
138
+ - **Identity changes need the delete-then-insert dance.** Changing `key` or
139
+ `tenantId` on an existing row changes the conflict identity, so a plain
140
+ `super.save()` writes the old primary key under a new one. Same handling as
141
+ `PromptOverride` / `LanguageOverride`: a transaction where the driver has
142
+ one, otherwise a staged replacement row deleted only after the new row is
143
+ durable.
144
+ - **JSON fields are stored as strings.** `planes` and `metadata` are text
145
+ columns with guarded `getPlanes()` / `setPlanes()` / `getMetadata()` /
146
+ `setMetadata()` helpers that swallow parse errors. Never override
147
+ `toJSON()`; extend serialization through `transformJSON()`.
148
+ - **`resolvePlaybook()` returns a result, it does not throw for policy.**
149
+ Unknown key, disabled, wrong plane, and unresolvable intents all come back as
150
+ `{ ok: false, reason, message }`. It *does* throw for programming errors —
151
+ notably a `steps` key on an override layer.
152
+ - **The cache carries an invalidation generation, and this is where it
153
+ diverges from `smrt-prompts`.** A resolution captures
154
+ `getPlaybookCacheGeneration(key, db)` before its asynchronous layer loads and
155
+ hands it back to `setCachedPlaybookBase()`; a concurrent `save()` / `delete()`
156
+ bumps the generation, and the in-flight resolution is then refused the cache
157
+ write instead of repopulating the key it just invalidated with the pre-write
158
+ value. Without it, "a stale entry is never served after a write" held only
159
+ until a read raced a write, and then failed for the full 30s TTL. Generations
160
+ are tracked per `(db, key)`, not per tenant, because an app-level row is
161
+ inherited by every tenant. `clearPlaybookCache()` bumps rather than resets
162
+ them, so a resolution that started before the clear cannot write back either.
163
+ `smrt-prompts` and `smrt-languages` still carry the unguarded version of this
164
+ race; fixing them is separate work.
165
+ - **Restart vitest after adding a decorated class**; the manifest is generated
166
+ at startup.
167
+
168
+ ## Related
169
+
170
+ - `@happyvertical/smrt-prompts` — the pattern this package clones
171
+ - `@happyvertical/smrt-languages` — source of the `context` column convention
172
+ - `@happyvertical/smrt-features` — parallel package for feature flags
173
+ - Epic #2585 — declared agent surface; #2587 capability vocabulary,
174
+ #2588 view intents, #2590 preflight, #2591 manifest emission
package/CLAUDE.md ADDED
@@ -0,0 +1 @@
1
+ @AGENTS.md
package/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright <2025> <Happy Vertical Corporation>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,95 @@
1
+ # @happyvertical/smrt-playbooks
2
+
3
+ Layered playbook definitions, tenant-aware overrides, and plan resolution for
4
+ s-m-r-t agents.
5
+
6
+ A playbook is a named, described sequence of steps an agent follows. It gives a
7
+ multi-step intent — "check out this cart" — a home that is neither a custom
8
+ model action nor a view intent, and browser agents, in-app agents, the Node MCP
9
+ server, and the CLI all follow the same resolved plan.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ pnpm add @happyvertical/smrt-playbooks
15
+ ```
16
+
17
+ ## Quick start
18
+
19
+ ```typescript
20
+ import { definePlaybook, resolvePlaybook } from '@happyvertical/smrt-playbooks';
21
+
22
+ // 1. Register a playbook's defaults at startup
23
+ definePlaybook({
24
+ key: 'commerce.cart.checkout',
25
+ title: 'Check out this cart',
26
+ description: 'Submits the order and captures payment.',
27
+ steps: [
28
+ {
29
+ kind: 'operation',
30
+ model: '@happyvertical/smrt-commerce:Order',
31
+ action: 'submit',
32
+ },
33
+ {
34
+ kind: 'operation',
35
+ model: '@happyvertical/smrt-commerce:Payment',
36
+ action: 'capture',
37
+ },
38
+ ],
39
+ onStepFailure: 'abort',
40
+ });
41
+
42
+ // 2. Resolve a plan for a caller on a plane
43
+ const resolution = await resolvePlaybook('commerce.cart.checkout', {
44
+ db,
45
+ plane: 'server',
46
+ });
47
+
48
+ if (!resolution.ok) {
49
+ // Fails closed with a specific reason: unknown-playbook, disabled,
50
+ // plane-not-declared, intent-registry-unavailable, unknown-intent.
51
+ throw new Error(resolution.message);
52
+ }
53
+
54
+ for (const step of resolution.plan.steps) {
55
+ // The agent executes each step itself; this package never does.
56
+ // step.classification is inherited from the referenced operation.
57
+ }
58
+ ```
59
+
60
+ ## What this package provides
61
+
62
+ - **`definePlaybook()`** — code-first playbook registration in a global process
63
+ registry, so a package ships its own playbooks
64
+ - **`resolvePlaybook()`** — layered resolution: code default → config override →
65
+ stored app override → stored tenant override → runtime override
66
+ - **`PlaybookOverride`** — CRUD model for app-level and tenant-level playbook
67
+ settings, stored in `_smrt_playbook_overrides`
68
+ - **Plane validity** — a playbook declares `browser`, `server`, or both, and
69
+ resolution on an undeclared plane fails closed
70
+ - **TTL cache** keyed by `(key, tenantId)`, invalidated on override save/delete
71
+
72
+ ## Guarantees
73
+
74
+ - **A playbook is a script, never a call.** Resolution returns a plan; nothing
75
+ here executes a step. A playbook is therefore never an authority boundary —
76
+ each step is authorized independently where it runs.
77
+ - **Step lists are never editable.** No override layer, including a direct
78
+ model write, can change a playbook's steps. An agent's description of what it
79
+ is about to do always matches the steps it will follow.
80
+ - **Enablement narrows only.** A tenant may disable a playbook; it can never
81
+ enable one a lower layer disabled.
82
+ - **Undeclared classification fails closed** to
83
+ `{ effect: 'destructive', idempotent: false, openWorld: true }`. Steps never
84
+ classify themselves; classification is inherited from the referenced
85
+ operation.
86
+
87
+ ## Documentation
88
+
89
+ - See [`AGENTS.md`](./AGENTS.md) for package-internal patterns
90
+ - See [`docs/content/standards.md`](../../docs/content/standards.md) for
91
+ monorepo conventions
92
+ - See related: [`@happyvertical/smrt-prompts`](../prompts) (the layered-override
93
+ pattern this package mirrors),
94
+ [`@happyvertical/smrt-languages`](../languages),
95
+ [`@happyvertical/smrt-features`](../features)
@@ -0,0 +1,345 @@
1
+ import { CapabilityClassification } from '@happyvertical/smrt-types';
2
+ import { CapabilityDeclaration } from '@happyvertical/smrt-types';
3
+ import { SmrtClassOptions } from '@happyvertical/smrt-core';
4
+ import { SmrtCollection } from '@happyvertical/smrt-core';
5
+ import { SmrtObject } from '@happyvertical/smrt-core';
6
+ import { SmrtObjectOptions } from '@happyvertical/smrt-core';
7
+
8
+ export declare function clearPlaybookCache(): void;
9
+
10
+ /**
11
+ * Registers a code-default playbook. Packages call this at import time so a
12
+ * bundled playbook resolves without any application registration.
13
+ */
14
+ export declare function definePlaybook(input: PlaybookDefinitionInput): PlaybookDefinition;
15
+
16
+ /**
17
+ * Fail-closed capability classification, per epic #2585 invariant 3. Applied
18
+ * whenever the host cannot tell us how a referenced operation is classified.
19
+ */
20
+ export declare const FAIL_CLOSED_CLASSIFICATION: CapabilityClassification;
21
+
22
+ export declare function getPlaybookCacheTtlMs(): number;
23
+
24
+ export declare function normalizeEditableConfig(editable?: Partial<PlaybookEditableConfig>): PlaybookEditableConfig;
25
+
26
+ /* Excluded from this release type: PACKAGE_VERSION_INITIALIZED */
27
+
28
+ export declare const PLAYBOOK_PLANES: readonly PlaybookPlane[];
29
+
30
+ export declare interface PlaybookAcceptance {
31
+ ok: true;
32
+ plan: PlaybookPlan;
33
+ }
34
+
35
+ export declare interface PlaybookCacheValue {
36
+ key: string;
37
+ title: string;
38
+ description: string;
39
+ planes: readonly PlaybookPlane[];
40
+ onStepFailure: PlaybookFailurePolicy;
41
+ enabled: boolean;
42
+ metadata: PlaybookMetadata;
43
+ }
44
+
45
+ /**
46
+ * A partial override from any layer above the code default. There is no
47
+ * `steps` key, and supplying one is rejected rather than ignored.
48
+ */
49
+ export declare interface PlaybookConfigOverrideInput {
50
+ title?: string | null;
51
+ description?: string | null;
52
+ planes?: readonly PlaybookPlane[] | null;
53
+ onStepFailure?: PlaybookFailurePolicy | null;
54
+ enabled?: boolean | null;
55
+ metadata?: PlaybookMetadata | null;
56
+ [key: string]: unknown;
57
+ }
58
+
59
+ export declare interface PlaybookDefinition {
60
+ key: string;
61
+ title: string;
62
+ description: string;
63
+ steps: readonly PlaybookStep[];
64
+ planes: readonly PlaybookPlane[];
65
+ onStepFailure: PlaybookFailurePolicy;
66
+ enabled: boolean;
67
+ metadata: PlaybookMetadata;
68
+ editable: PlaybookEditableConfig;
69
+ }
70
+
71
+ export declare interface PlaybookDefinitionInput {
72
+ key: string;
73
+ title: string;
74
+ description: string;
75
+ steps: readonly PlaybookStep[];
76
+ /**
77
+ * Planes this playbook is valid on. Defaults to both planes when every step
78
+ * is a model operation, and to `['browser']` when any step is a view intent
79
+ * — server validity for an intent-bearing playbook rides the #2446 browser
80
+ * command/ack bridge and must be declared explicitly.
81
+ */
82
+ planes?: readonly PlaybookPlane[];
83
+ onStepFailure?: PlaybookFailurePolicy;
84
+ enabled?: boolean;
85
+ metadata?: PlaybookMetadata | null;
86
+ editable?: Partial<PlaybookEditableConfig>;
87
+ }
88
+
89
+ /**
90
+ * Fields a stored override layer may change when the definition opts in.
91
+ *
92
+ * `steps` is deliberately absent: it is structurally non-editable, not merely
93
+ * defaulted false. No override layer can carry a step list at all.
94
+ */
95
+ export declare interface PlaybookEditableConfig {
96
+ title: boolean;
97
+ description: boolean;
98
+ planes: boolean;
99
+ onStepFailure: boolean;
100
+ enabled: boolean;
101
+ metadata: boolean;
102
+ }
103
+
104
+ /**
105
+ * What an agent does when a step fails partway through a plan. Playbooks are
106
+ * scripts, never atomic units, so there is no compensation: the definition
107
+ * says only whether the remainder of the plan is abandoned.
108
+ */
109
+ export declare type PlaybookFailurePolicy = 'abort' | 'continue';
110
+
111
+ /**
112
+ * Record returned by an intent registry for a declared view intent.
113
+ *
114
+ * Seam for #2588: until an intent registry exists, no resolver is supplied and
115
+ * an intent step fails resolution closed.
116
+ */
117
+ export declare interface PlaybookIntentRecord {
118
+ id: string;
119
+ classification?: CapabilityDeclaration | null;
120
+ planes?: readonly PlaybookPlane[] | null;
121
+ }
122
+
123
+ /** Seam for #2588. */
124
+ export declare type PlaybookIntentResolver = (id: string) => PlaybookIntentRecord | null | undefined;
125
+
126
+ /**
127
+ * A step naming a declared view intent by its identity (#2588). Valid only
128
+ * where a surface is mounted.
129
+ */
130
+ export declare interface PlaybookIntentStep {
131
+ kind: 'intent';
132
+ /** Declared intent identity from the #2588 intent registry. */
133
+ id: string;
134
+ label?: string;
135
+ description?: string;
136
+ optional?: boolean;
137
+ }
138
+
139
+ /** One normalized override layer. `null` means "clear"; `undefined` means "inherit". */
140
+ export declare interface PlaybookLayer {
141
+ title?: string | null;
142
+ description?: string | null;
143
+ planes?: readonly PlaybookPlane[] | null;
144
+ onStepFailure?: PlaybookFailurePolicy | null;
145
+ enabled?: boolean | null;
146
+ metadata?: PlaybookMetadata | null;
147
+ }
148
+
149
+ export declare type PlaybookMetadata = Record<string, unknown>;
150
+
151
+ /**
152
+ * Resolves the capability classification of a referenced model operation.
153
+ *
154
+ * Playbooks never classify a step themselves. A host that knows the emitted
155
+ * build-time classification (core's `tool-schema.ts` output, or the runtime
156
+ * manifest) supplies it here; anything it does not know resolves fail-closed
157
+ * to `{ effect: 'destructive', idempotent: false, openWorld: true }`.
158
+ */
159
+ export declare type PlaybookOperationClassifier = (step: PlaybookOperationStep) => CapabilityDeclaration | null | undefined;
160
+
161
+ /**
162
+ * A step naming a model operation by qualified pair — the same qualified
163
+ * form STI discriminators and `@crossPackageRef` already use. Never a
164
+ * generated tool name: that is derived from model, action, and namespace and
165
+ * would silently orphan stored tenant overrides on a namespace change.
166
+ *
167
+ * The step never classifies itself; classification is inherited from the
168
+ * referenced operation (see {@link PlaybookOperationClassifier}).
169
+ */
170
+ export declare interface PlaybookOperationStep {
171
+ kind: 'operation';
172
+ /** Qualified model name, e.g. `@happyvertical/smrt-commerce:Order`. */
173
+ model: string;
174
+ /** Operation name exposed by the model's `@smrt({ api })` surface. */
175
+ action: string;
176
+ /** Human-facing label for the agent's narration of this step. */
177
+ label?: string;
178
+ /** Longer human-facing description of the step. */
179
+ description?: string;
180
+ /** When true, an agent may skip this step without abandoning the plan. */
181
+ optional?: boolean;
182
+ }
183
+
184
+ /**
185
+ * Stored app-level (`tenantId = null`) and tenant-level playbook overrides.
186
+ *
187
+ * There is deliberately **no `steps` column**. `steps` is structurally
188
+ * non-editable: an override layer has nowhere to put a step list, and
189
+ * assigning one is rejected in `save()` rather than silently dropped. That is
190
+ * the description-behavior guarantee from epic #2585 — an agent announcing
191
+ * "checking out your cart" must not be following a rewritten script.
192
+ */
193
+ export declare class PlaybookOverride extends SmrtObject {
194
+ key: string;
195
+ tenantId: string | null;
196
+ title: string | null;
197
+ description: string | null;
198
+ /** JSON array of plane names; null inherits the lower layer. */
199
+ planes: string | null;
200
+ onStepFailure: string | null;
201
+ /** Tri-state: null inherits, false disables. True can never widen. */
202
+ enabled: boolean | null;
203
+ /** JSON object; stored as a string with guarded get/set helpers. */
204
+ metadata: string | null;
205
+ constructor(options?: PlaybookOverrideOptions);
206
+ getMetadata(): PlaybookMetadata;
207
+ setMetadata(metadata: PlaybookMetadata | null): void;
208
+ getPlanes(): readonly PlaybookPlane[] | null;
209
+ setPlanes(planes: readonly PlaybookPlane[] | null): void;
210
+ toPlaybookLayer(): PlaybookLayer;
211
+ save(): Promise<this>;
212
+ private saveAfterIdentityChange;
213
+ private saveAfterIdentityChangeInTransaction;
214
+ private saveAfterIdentityChangeWithDeferredDelete;
215
+ delete(): Promise<void>;
216
+ private validatePlaybookOverride;
217
+ private getLowerPrecedenceLayers;
218
+ private normalizeForPersistence;
219
+ private getPersistedIdentity;
220
+ }
221
+
222
+ export declare class PlaybookOverrideCollection extends SmrtCollection<PlaybookOverride> {
223
+ static readonly _itemClass: typeof PlaybookOverride;
224
+ private excludeOverrideId;
225
+ getAppOverride(key: string, options?: {
226
+ excludeId?: string;
227
+ }): Promise<PlaybookOverride | null>;
228
+ getTenantOverride(key: string, tenantId: string, options?: {
229
+ excludeId?: string;
230
+ }): Promise<PlaybookOverride | null>;
231
+ getResolutionLayers(key: string, tenantId?: string | null, options?: {
232
+ excludeId?: string;
233
+ }): Promise<{
234
+ app: PlaybookOverride | null;
235
+ tenant: PlaybookOverride | null;
236
+ }>;
237
+ }
238
+
239
+ export declare interface PlaybookOverrideOptions extends SmrtObjectOptions, PlaybookOverrideOptions_2 {
240
+ }
241
+
242
+ declare interface PlaybookOverrideOptions_2 {
243
+ key?: string;
244
+ tenantId?: string | null;
245
+ title?: string | null;
246
+ description?: string | null;
247
+ planes?: string | readonly PlaybookPlane[] | null;
248
+ onStepFailure?: PlaybookFailurePolicy | null;
249
+ enabled?: boolean | null;
250
+ metadata?: string | PlaybookMetadata | null;
251
+ }
252
+
253
+ export declare interface PlaybookPackageConfig {
254
+ playbooks?: Record<string, PlaybookConfigOverrideInput>;
255
+ [key: string]: unknown;
256
+ }
257
+
258
+ /**
259
+ * The output of resolution: a plan an agent follows step by step. Nothing in
260
+ * this package executes a step, and the plan is not an authority boundary —
261
+ * every step is authorized independently where it runs.
262
+ */
263
+ export declare interface PlaybookPlan {
264
+ key: string;
265
+ title: string;
266
+ description: string;
267
+ plane: PlaybookPlane;
268
+ planes: readonly PlaybookPlane[];
269
+ onStepFailure: PlaybookFailurePolicy;
270
+ metadata: PlaybookMetadata;
271
+ steps: readonly PlaybookPlanStep[];
272
+ }
273
+
274
+ /**
275
+ * Execution planes a playbook can declare validity for.
276
+ *
277
+ * `browser` covers WebMCP / in-page agents driving mounted surfaces;
278
+ * `server` covers Node MCP, CLI, and in-app agents running under
279
+ * `executeAsPrincipal`.
280
+ */
281
+ export declare type PlaybookPlane = 'browser' | 'server';
282
+
283
+ /** One step of a resolved plan, with its inherited classification. */
284
+ export declare interface PlaybookPlanStep {
285
+ index: number;
286
+ step: PlaybookStep;
287
+ classification: CapabilityClassification;
288
+ /** True when the classification is the fail-closed default. */
289
+ classificationDeclared: boolean;
290
+ }
291
+
292
+ /**
293
+ * Global process registry of code-default playbooks, keyed by namespaced key.
294
+ *
295
+ * Held on `globalThis` so it survives HMR, mirroring `PromptRegistry`.
296
+ */
297
+ export declare const PlaybookRegistry: {
298
+ register(input: PlaybookDefinitionInput): PlaybookDefinition;
299
+ get(key: string): PlaybookDefinition | undefined;
300
+ has(key: string): boolean;
301
+ getAll(): PlaybookDefinition[];
302
+ clear(): void;
303
+ };
304
+
305
+ export declare interface PlaybookRejection {
306
+ ok: false;
307
+ reason: PlaybookRejectionReason;
308
+ message: string;
309
+ key: string;
310
+ /** Index of the offending step, when the rejection is step-scoped. */
311
+ stepIndex?: number;
312
+ }
313
+
314
+ export declare type PlaybookRejectionReason = 'unknown-playbook' | 'disabled' | 'plane-not-declared' | 'intent-registry-unavailable' | 'unknown-intent' | 'intent-plane-not-declared';
315
+
316
+ /** Resolution fails closed: every rejection carries a specific reason. */
317
+ export declare type PlaybookResolution = PlaybookAcceptance | PlaybookRejection;
318
+
319
+ /** A playbook step. Exactly two kinds exist in v1; playbooks cannot nest. */
320
+ export declare type PlaybookStep = PlaybookOperationStep | PlaybookIntentStep;
321
+
322
+ /**
323
+ * Resolves a playbook to a plan for a caller on a given plane.
324
+ *
325
+ * Returns a discriminated result rather than throwing: resolution fails closed
326
+ * and every rejection names a specific reason. Nothing here executes a step —
327
+ * the plan is followed step by step by the agent, and each step is authorized
328
+ * independently at the REST boundary or by `PrincipalRun.assertToolAllowed()`.
329
+ */
330
+ export declare function resolvePlaybook(key: string, options?: ResolvePlaybookOptions): Promise<PlaybookResolution>;
331
+
332
+ export declare interface ResolvePlaybookOptions {
333
+ db?: SmrtClassOptions['db'];
334
+ tenantId?: string | null;
335
+ /** Plane the calling agent runs on. Defaults to `'server'`. */
336
+ plane?: PlaybookPlane;
337
+ /** Highest-precedence layer, supplied per call. */
338
+ override?: PlaybookConfigOverrideInput;
339
+ /** Host-supplied classification source for model-operation steps. */
340
+ classifier?: PlaybookOperationClassifier;
341
+ /** Host-supplied intent registry (#2588). */
342
+ intents?: PlaybookIntentResolver;
343
+ }
344
+
345
+ export { }