@gregiteen/ssss-cli 0.12.1 → 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1959 @@
1
+ # SSSS — Structured Semantic Syntax System
2
+
3
+ **Specification v0.9**
4
+
5
+ > This is the canonical, vendor-neutral specification for SSSS. It is the ground
6
+ > truth on which all SSSS implementations are built. It is intended to be vendored
7
+ > byte-for-byte into any repository that implements SSSS.
8
+ >
9
+ > Status: **Stable for 0.9**. The format, type registry, and conformance contract
10
+ > are settled for this version; until v1.0 a later version MAY still introduce
11
+ > breaking changes.
12
+ >
13
+ > Revision: 2026-09-24. Editorial alignment with the 0.9 reference kernel
14
+ > (`@gregiteen/ssss-cli`). This revision documents behavior that already ships:
15
+ > the verified-principal model, the real stage order, the canonical event
16
+ > record, and symbolic error codes. It changes no wire format. Every example
17
+ > document in this file is validated by the conformance suite (§12).
18
+ >
19
+ > Implementation-specific detail (routes, services, storage backends, deployment)
20
+ > does **not** belong in this document — it belongs in each implementation's own
21
+ > `SKILL.md`. This file describes *what SSSS is*, never *how one product wires it up*.
22
+
23
+ ---
24
+
25
+ ## 1. Abstract
26
+
27
+ SSSS — the Structured Semantic Syntax System — is a **database-free, Markdown-first
28
+ schema and mutation contract for AI agent state**.
29
+
30
+ Every unit of agent-relevant state — a memory, a skill, a conversation, a workflow
31
+ run, an assistant definition, a runtime task — is a plain Markdown file with YAML
32
+ frontmatter. There is no relational database of record, no binary format, and no
33
+ proprietary container. A relational store MAY exist, but only as a *disposable
34
+ projection* rebuildable from the Markdown.
35
+
36
+ SSSS additionally defines the **Operation Contract**: a single, validated, idempotent
37
+ envelope through which all agent-generated mutations must flow. This makes
38
+ AI-generated state changes deterministic, replayable, conflict-safe, and auditable.
39
+
40
+ Its semantic runtime turns the same canonical files into a deterministic searchable
41
+ graph, while multilingual embedding and render adapters localize presentation without
42
+ mutating symbolic control fields or private operational data.
43
+
44
+ Any tool, IDE, agent framework, daemon, or CLI that can read Markdown can
45
+ interoperate with an SSSS vault. The only thing that distinguishes a memory engine,
46
+ a chat runtime, and a workflow orchestrator is *which primitive types they read and
47
+ write* — the underlying file format and mutation contract are identical.
48
+
49
+ ---
50
+
51
+ ## 2. Conformance Terminology
52
+
53
+ The key words **MUST**, **MUST NOT**, **REQUIRED**, **SHALL**, **SHALL NOT**,
54
+ **SHOULD**, **SHOULD NOT**, **RECOMMENDED**, **MAY**, and **OPTIONAL** in this
55
+ document are to be interpreted as described in RFC 2119.
56
+
57
+ Defined terms used throughout:
58
+
59
+ | Term | Meaning |
60
+ |------|---------|
61
+ | **Host** | A system that implements SSSS — stores SSSS files and/or processes the Operation Contract. |
62
+ | **Vault** | The version-controlled directory tree of SSSS files. The source of truth. |
63
+ | **VFS** | Virtual File System — the addressable namespace of paths within a vault. |
64
+ | **Primitive** | A defined `type` of SSSS file or contract structure (see §5). |
65
+ | **Document primitive** | A primitive that exists as an addressable Markdown file. |
66
+ | **Contract primitive** | A primitive that exists only as a protocol structure (envelope, lease, event). |
67
+ | **Projection** | A derived, disposable representation of vault state (e.g. an SQL table, a search index). Never source-of-truth. |
68
+ | **Agent** | Any human or AI actor issuing operations. |
69
+ | **Envelope** | A JSON command submitted to the Operation Contract: `operation`, `patch`, `event`, or `delete` (§6). |
70
+ | **Kernel** | The component that runs the §6.3 pipeline. It owns stage order and semantics; storage is delegated to adapters. |
71
+ | **Adapter** | A host-supplied implementation of one storage or policy contract: VFS, event store, idempotency store, lease store, authorizer, projections, or resource coordinator (§6.7). |
72
+ | **Verified principal** | The authenticated identity a host attaches to an envelope *outside* the envelope body (§6.6). Never taken from client-supplied fields. |
73
+ | **Capability** | A permission string of the form `<scope>:<action>` held by a principal and required by a primitive (§6.6). |
74
+ | **Qualified type** | A primitive identity prefixed by its registry namespace: `ssss:assistant` for core, `<ext>:<type>` for an extension (§5.6). |
75
+ | **Portability class** | `structural`, `tenant_private`, or `resource_bound`: whether a document may leave the workspace (§5.5). |
76
+ | **Bundle** | A `.ucw` package of vault files plus a manifest (§16). |
77
+ | **Commit point** | The moment a mutation becomes durable: the canonical event is appended to the event log (§6.3). |
78
+
79
+ A host is **conformant** if it satisfies every MUST in this document and passes the
80
+ conformance fixtures of §12.
81
+
82
+ ---
83
+
84
+ ## 3. Design Principles
85
+
86
+ | Principle | Rule |
87
+ |-----------|------|
88
+ | **No database of record** | Product-meaningful state MUST live in Markdown files, not in a relational database. A database MAY hold projections only. |
89
+ | **Markdown is law** | Every state primitive exists as a `.md` file (document primitives) or as a JSON envelope over the contract (contract primitives). |
90
+ | **Semantic frontmatter** | Every SSSS file MUST carry YAML frontmatter with a `type` field that identifies how engines interpret it. |
91
+ | **One mutation contract** | All agent-generated mutations MUST flow through the Operation Contract (§6). Direct, unvalidated writes by agents are forbidden. |
92
+ | **Deterministic validation** | Every mutation MUST be validated against the primitive's schema before commit. Validation MUST be deterministic — same input, same verdict. |
93
+ | **Idempotent by key** | Every operation carries an idempotency key. Replays MUST NOT double-apply. |
94
+ | **Append-only history** | The event log is immutable, and so are the records in append-type documents. Neither is ever updated or deleted. |
95
+ | **Disposable indexes** | Derived indexes and projections are ephemeral caches, fully rebuildable from the vault. They may be deleted at any time. |
96
+ | **Git-versioned** | The vault is version-controlled. History is provenance. |
97
+ | **Portable** | A vault is interpretable by any Markdown-capable tool. No host is privileged. |
98
+
99
+ ---
100
+
101
+ ## 4. The SSSS File
102
+
103
+ ### 4.1 Anatomy
104
+
105
+ A document primitive is a UTF-8 Markdown file with two regions:
106
+
107
+ ```text
108
+ ---
109
+ type: <primitive-type>
110
+ <frontmatter fields...>
111
+ ---
112
+
113
+ <Markdown body>
114
+ ```
115
+
116
+ 1. **Frontmatter** — a YAML block delimited by a leading `---` line and a closing
117
+ `---` line. It MUST be the first content in the file. It is machine-readable
118
+ structured data.
119
+ 2. **Body** — everything after the closing `---`. It is human-readable Markdown
120
+ prose, and for append-type primitives (§5.3) it carries the ordered records.
121
+
122
+ A Markdown file with no frontmatter, or with frontmatter that omits `type`, is **not
123
+ an SSSS file** — it is an ordinary Markdown file (e.g. a `README`) and is out of SSSS
124
+ scope. Where a context *requires* an SSSS file — a write through the Operation
125
+ Contract (§6) to an SSSS path — a missing or unrecognized `type` MUST be rejected.
126
+
127
+ ### 4.2 Universal Frontmatter Fields
128
+
129
+ Every SSSS document primitive MUST include:
130
+
131
+ | Field | Type | Description |
132
+ |-------|------|-------------|
133
+ | `type` | string | The primitive type. MUST match an entry in the Type Registry (§5). |
134
+ | `title` | string | Human-readable title of the document. |
135
+ | `description` | string | One-sentence summary of the document's purpose. |
136
+ | `timestamp` | string | ISO 8601 timestamp of last modification. |
137
+
138
+ For OKF-compatible discovery, SSSS document primitives SHOULD also include:
139
+
140
+ | Field | Type | Description |
141
+ |-------|------|-------------|
142
+ | `resource` | string | Canonical URI for the underlying asset, when the primitive describes one. |
143
+ | `tags` | array | Array of string tags for categorization and routing. |
144
+ | `aliases` | array | Array of alternative names for this concept, used for wiki autolinking. |
145
+
146
+ For stable semantic identity and graph projection, documents SHOULD also include:
147
+
148
+ | Field | Type | Description |
149
+ |-------|------|-------------|
150
+ | `semantic_id` | string | Stable concept identity that survives file moves and localized presentation. |
151
+ | `relations` | array | Explicit semantic edges to other vault-relative document paths or semantic ids. |
152
+ | `language` | string | BCP-47 tag of the authored natural-language surface, when known (e.g. `ja`, `es-MX`). |
153
+
154
+ `resource`, `tags`, and `aliases` serve both OKF discovery and the semantic layer.
155
+ These fields are recommendations, not new universal requirements. Earlier drafts
156
+ called the last field `locale`; a host SHOULD read `locale` as a fallback when
157
+ `language` is absent, and MUST write `language`.
158
+
159
+ Every primitive type defines its own additional REQUIRED and OPTIONAL fields
160
+ (§5.4). The four universal fields above are REQUIRED **in addition to** each
161
+ type's own list. To maintain forward compatibility and allow agents scratchpad
162
+ space, hosts MUST NOT reject documents containing unknown frontmatter keys.
163
+ Unknown fields MUST be preserved.
164
+
165
+ Directory index files (`index.md`, §4.3) are the one exemption. They carry no
166
+ frontmatter and are not validated as primitives.
167
+
168
+ ### 4.3 Linking & Progressive Disclosure
169
+
170
+ SSSS adopts the OKF standards for hyperlinking and directory indices:
171
+
172
+ 1. **Absolute Bundle-Relative Links**: Links to other primitives SHOULD be absolute paths starting from the vault root (e.g., `[Customer Assistant](/assistants/support.md)`).
173
+ 2. **The `# Citations` Section**: If a primitive's body makes claims sourced from other primitives or external data, it SHOULD include a `# Citations` heading at the bottom with numbered reference links.
174
+ 3. **Index Files (`index.md`)**: A host MAY generate `index.md` files in directories to provide progressive disclosure of the vault's contents. These files contain no frontmatter and exist solely to serve as a table of contents for agents traversing the VFS.
175
+
176
+ ### 4.4 Canonical Filenames
177
+
178
+ Document primitives that have a fixed role in a directory use an **uppercase
179
+ canonical filename** that signals the primitive at a glance:
180
+
181
+ | Filename | Primitive |
182
+ |----------|-----------|
183
+ | `SKILL.md` | `skill` |
184
+ | `ASSISTANT.md` | `assistant` |
185
+ | `WORKFLOW.md` | `workflow` |
186
+ | `MODEL.md` | `model` |
187
+ | `CONVERSATION.md` | `conversation` |
188
+ | `RUN.md` | `run` |
189
+ | `ROLE.md` | `security_role` (canonically `roles/<role>/ROLE.md`) |
190
+
191
+ Free-standing primitives (e.g. `memory`, `task`) instead use a `kebab-case` slug
192
+ filename matching their `slug` field. Governed `primitive` definitions live at
193
+ `primitives/<namespace>/<id>.md`. The frontmatter `type` is always
194
+ authoritative; the filename is a convention, not a substitute for validation.
195
+
196
+ ### 4.5 The Frontmatter Subset
197
+
198
+ Frontmatter is YAML, but a conformant host is only required to accept the subset
199
+ below. A document that stays inside it round-trips identically through every
200
+ conformant parser. The reference parser is dependency-free and implements
201
+ exactly this subset.
202
+
203
+ - **Scalars**: strings (bare, `"double"`, or `'single'` quoted), integers,
204
+ decimals, `true`/`false`, and `null`/`~`. ISO 8601 timestamps are read as
205
+ **strings**, not native dates, so they round-trip byte-for-byte.
206
+ - **Inline arrays**: `[a, b, "c d"]`.
207
+ - **Block arrays**: `- item` lines.
208
+ - **Nested maps**: indented `key: value` blocks.
209
+ - **Arrays of maps**: `- key: value` entries whose further keys are indented
210
+ under the first. A map entry may itself hold an inline array.
211
+ - **Folded strings**: `>` and `>-` block scalars.
212
+
213
+ Anchors, aliases, tags, and multi-document streams are outside the subset.
214
+ Flow maps (`{a: 1}`) and JSON-style inline values (`[{"a": 1}]`) are also
215
+ outside it, but the reference parser reads them because other tools write them
216
+ (for example Total Recall's JSON-shaped metadata). A host MAY accept any of
217
+ these but MUST NOT require them, and authors SHOULD NOT use them in documents
218
+ that leave the host.
219
+
220
+ Where the reference parser reads a form YAML 1.2 also defines, it follows YAML:
221
+ keys may contain `-`, `.` and `@`; a `:` only splits a key when whitespace or
222
+ end of line follows, so `context:universal` is a value; plain and quoted
223
+ scalars may wrap onto indented continuation lines; a trailing ` # comment` on
224
+ an unquoted value is dropped; and a block list may sit at its key's indent.
225
+ Two deliberate deviations keep values lossless: an integer with a leading zero
226
+ (`07885`) stays a **string**, since it is a code and not a number, and
227
+ timestamps stay strings, as above.
228
+
229
+ ---
230
+
231
+ ## 5. Primitive Type Registry
232
+
233
+ SSSS defines two families of primitive: **document primitives** (addressable files)
234
+ and **contract primitives** (protocol structures). A host need not implement every
235
+ primitive — it implements the subset its product requires — but any primitive it
236
+ *does* implement MUST conform to the schema below.
237
+
238
+ ### 5.1 Document Primitives
239
+
240
+ | `type` | Family | Portability | Purpose |
241
+ |--------|--------|-------------|---------|
242
+ | `memory` | knowledge | structural | A single unit of agent knowledge (rule, pattern, fact, preference). |
243
+ | `skill` | capability | structural | A skill package manifest. |
244
+ | `asset` | capability | structural | A text-encoded code, vector, or binary asset payload or pointer. |
245
+ | `resource` | capability | resource_bound | An external infrastructure, cloud asset, domain, database, or API dependency. |
246
+ | `rule` | governance | structural | A workspace-scoped behavior rule applied to assistants/agents. |
247
+ | `role` | governance | structural | A security role definition for role-based access control (RBAC). |
248
+ | `security_role` | governance | structural | A security role definition for role-based access control (RBAC). Legacy alias of `role`. |
249
+ | `task` | work | tenant_private | A unit of submitted work — one step or many. The universal work primitive. |
250
+ | `assistant` | actor | structural | The definition of an AI assistant/persona. |
251
+ | `workflow` | work | structural | A reusable **task template**: a defined procedure. Firing a workflow submits a `task`. |
252
+ | `trigger` | work | structural | A standalone schedule or event-driven trigger that fires a workflow. |
253
+ | `model` | catalog | structural | The definition of an inference model. |
254
+ | `thread` | transcript | tenant_private | An append-only chat transcript. |
255
+ | `conversation` | transcript | tenant_private | An append-only chat transcript. Legacy alias of `thread`. |
256
+ | `run` | transcript | tenant_private | An append-only workflow execution record. |
257
+ | `conflict` | meta | tenant_private | A record of two contradicting primitives, blocking promotion. |
258
+ | `page` | capability | structural | A VFS-native sandboxed custom workspace page. |
259
+ | `migration` | meta | structural | An SSSS schema migration state record. |
260
+ | `release` | meta | structural | An SSSS system schema version release record. |
261
+ | `primitive` | meta | structural | A governed, versioned definition for a namespaced SSSS primitive. |
262
+
263
+ The **Portability** column is the primitive's default portability class (§5.5); a host
264
+ resolves it from `registry/core.json`. Extension registries assign their own primitives a
265
+ class — notably `resource_bound` for things like domains and phone numbers.
266
+
267
+ ### 5.2 Contract Primitives
268
+
269
+ | `type` | Purpose |
270
+ |--------|---------|
271
+ | `operation` | A full atomic file write (create or full replace) — see §6. |
272
+ | `patch` | A partial merge into an existing file — see §6. |
273
+ | `event` | An append-only immutable log entry — see §6, §8. |
274
+ | `delete` | A tombstoning removal of a replace-type file — see §6. |
275
+ | `lease` | A file-level write lock — see §7. |
276
+
277
+ ### 5.3 Append-Type vs. Replace-Type Documents
278
+
279
+ Document primitives are either:
280
+
281
+ - **Replace-type** — the whole file represents current state; a write replaces it
282
+ entirely (`memory`, `skill`, `rule`, `security_role`, `task`, `assistant`,
283
+ `workflow`, `model`, `conflict`, `page`, `migration`, `release`, `primitive`).
284
+ - **Append-type** — the file is an ordered, append-only log; writes add records to
285
+ the body and MUST NOT rewrite prior records (`conversation`, `run`).
286
+
287
+ Append-type documents MUST be mutated only by appending. A host MUST reject an
288
+ operation that would rewrite or remove existing records of an append-type document.
289
+
290
+ ### 5.4 Per-Type Schemas
291
+
292
+ Each schema lists the type's REQUIRED fields. These are in addition to the
293
+ universal fields of §4.2 (`type`, `title`, `description`, `timestamp`), which
294
+ every example carries. All other fields are OPTIONAL. Examples are minimal, and
295
+ each one passes the reference validator (§12).
296
+
297
+ #### `memory`
298
+
299
+ The knowledge primitive. Categories: `invariants`, `patterns`, `anti-patterns`,
300
+ `preferences`, `decisions`, `concepts`, `facts`, `lore`.
301
+
302
+ REQUIRED: `type`, `slug`, `category`, `title`, `status`, `schema_version`.
303
+
304
+ Knowledge-graph fields, REQUIRED when `schema_version: 2`: `confidence` (0..1),
305
+ `importance` (1..5), `modality` (`must|must_not|should|should_not|descriptive|preference`),
306
+ `subject`, `predicate`, `object`, `sentiment_polarity`
307
+ (`directive_must|directive_must_not|descriptive|preference`).
308
+
309
+ The `subject`/`predicate`/`object` triple SHOULD use stable, language-neutral
310
+ concept identifiers (not localized prose), so the triple is a semantic anchor
311
+ independent of the document's authoring language — see §11.
312
+
313
+ ```markdown
314
+ ---
315
+ type: memory
316
+ slug: prefer-atomic-writes
317
+ category: patterns
318
+ title: "Always write files atomically (write-then-rename)"
319
+ description: "Write to a temporary file, then rename it over the target."
320
+ timestamp: 2026-05-16T14:00:00Z
321
+ status: active
322
+ schema_version: 2
323
+ confidence: 0.92
324
+ importance: 4
325
+ modality: must
326
+ subject: agent
327
+ predicate: use_atomic_write
328
+ object: file_system
329
+ sentiment_polarity: directive_must
330
+ ---
331
+
332
+ Write to a temporary file, then `rename()` to the target. `rename()` is atomic on
333
+ POSIX filesystems; direct writes risk partial-file corruption on crash.
334
+ ```
335
+
336
+ Memory nodes in the `invariants` category additionally carry `priority: absolute`
337
+ and `immutable: true`. The full `priority` enum is `absolute|high|normal|low`;
338
+ `priority` is OPTIONAL on non-invariant categories (defaults to `normal`).
339
+
340
+ #### `skill`
341
+
342
+ A capability package manifest. SSSS skill manifests are compatible with the open
343
+ Agent Skills standard: the minimal REQUIRED frontmatter is `name` and `description`.
344
+ The `type: skill` discriminator is REQUIRED for SSSS-managed manifests so the
345
+ registry can route them.
346
+
347
+ REQUIRED: `type`, `name`, `description`.
348
+
349
+ ```markdown
350
+ ---
351
+ type: skill
352
+ name: deploy
353
+ title: "Deploy"
354
+ description: >-
355
+ Deploy services with zero downtime. Use when the user mentions deploy,
356
+ release, ship, or production push.
357
+ timestamp: 2026-05-16T14:00:00Z
358
+ ---
359
+
360
+ # Deploy
361
+ ...
362
+ ```
363
+
364
+ #### `asset`
365
+
366
+ A text-encoded asset payload: source code, vector graphics, or base64-encoded binary content, or pointer metadata for large files.
367
+
368
+ REQUIRED: `type`, `name`, `mime_type`, `encoding` (`base64|utf-8|none`).
369
+ OPTIONAL: `slug`, `description`, `hash`, `size_bytes`, `storage_uri`, `resource_ref`.
370
+
371
+ ```markdown
372
+ ---
373
+ type: asset
374
+ name: "logo-icon"
375
+ title: "Brand Logo Icon"
376
+ description: "A 1x1 pixel PNG icon encoded in base64."
377
+ timestamp: 2026-05-16T14:00:00Z
378
+ mime_type: "image/png"
379
+ encoding: "base64"
380
+ ---
381
+
382
+ iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==
383
+ ```
384
+
385
+ A file too large to carry in the vault is stored as a **pointer**: `encoding: none`
386
+ and an empty body. A pointer REQUIRES `storage_uri`, the URI of the stored object,
387
+ and `x_portability` set to `resource_bound` or `tenant_private` (§5.5), so a
388
+ template or sale export never ships the seller's storage location: the exporter
389
+ replaces `storage_uri` with `REQUIREMENT` and the buyer binds their own copy at
390
+ provision. `resource_ref`, when present, is the vault path of the `resource`
391
+ document (bucket, object store) that holds the object. `hash` (`sha256:<hex>`) and
392
+ `size_bytes` pin the object's content and survive export, so the buyer can verify
393
+ the file they supply.
394
+
395
+ ```markdown
396
+ ---
397
+ type: asset
398
+ name: "training-video"
399
+ title: "Onboarding Video"
400
+ description: "Staff onboarding video, stored in object storage."
401
+ timestamp: 2026-09-28T00:00:00Z
402
+ mime_type: "video/mp4"
403
+ encoding: "none"
404
+ storage_uri: "s3://media-bucket/training/onboarding.mp4"
405
+ resource_ref: "resources/media-bucket.md"
406
+ hash: "sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
407
+ size_bytes: 734003200
408
+ x_portability: resource_bound
409
+ ---
410
+ ```
411
+
412
+ #### `resource`
413
+
414
+ An external infrastructure, cloud asset, domain, database, or API dependency bound to the workspace. Carries `portability: resource_bound`.
415
+
416
+ REQUIRED: `type`, `name`, `kind`, `status` (`bound|unbound|pending|error`).
417
+
418
+ ```markdown
419
+ ---
420
+ type: resource
421
+ name: "Primary Database"
422
+ title: "Primary Database"
423
+ description: "Application production PostgreSQL database."
424
+ timestamp: 2026-05-16T14:00:00Z
425
+ kind: postgres
426
+ status: bound
427
+ binds:
428
+ host: "db.internal.net"
429
+ port: 5432
430
+ database: "app_prod"
431
+ ---
432
+
433
+ Production PostgreSQL database connection.
434
+ ```
435
+
436
+ #### `task`
437
+
438
+ A unit of submitted work — the universal work primitive. A `task` MAY be ad-hoc or
439
+ instantiated from a `workflow` template; either way it executes as a `run`.
440
+
441
+ REQUIRED: `type`, `priority` (integer), `category`, `status`
442
+ (`pending|in_progress|done|failed`). A task instantiated from a template carries an
443
+ OPTIONAL `workflow_id` referencing it.
444
+
445
+ Runtime-created tasks SHOULD additionally carry `workflow_path`, `trigger_id`,
446
+ `trigger_type`, `trigger_event_id`, `scheduled_for`, and `dedupe_key`. These fields
447
+ make the task reconstructible from the workflow definition plus the trigger event
448
+ and prevent duplicate daemon ticks from creating duplicate work (§11.8).
449
+
450
+ ```markdown
451
+ ---
452
+ type: task
453
+ title: "Research the payments API"
454
+ description: "Research the payments API and write a reference skill."
455
+ timestamp: 2026-05-16T08:00:00Z
456
+ priority: 85
457
+ category: skill-engineering
458
+ status: pending
459
+ workflow_id: "research-skill"
460
+ trigger_id: "manual"
461
+ scheduled_for: 2026-05-16T08:00:00Z
462
+ dedupe_key: "runtime:abc123"
463
+ ---
464
+
465
+ ## Objective
466
+ Research the payments API and write a reference skill.
467
+ ```
468
+
469
+ #### `assistant`
470
+
471
+ The definition of an AI assistant.
472
+
473
+ REQUIRED: `type`, `name`.
474
+
475
+ ```markdown
476
+ ---
477
+ type: assistant
478
+ name: "Support Bot"
479
+ title: "Support Bot"
480
+ description: "Front-line customer support assistant."
481
+ timestamp: 2026-05-16T14:00:00Z
482
+ model: "example/large-model"
483
+ ---
484
+
485
+ ## Instructions
486
+ You are a helpful support assistant.
487
+ ```
488
+
489
+ #### `workflow`
490
+
491
+ A reusable **task template** — a defined multi-step procedure plus triggers. A
492
+ workflow is not executed directly: when a trigger fires (or it is invoked), the host
493
+ **submits a `task`** from the template, and that task executes as a `run`. Workflow
494
+ and task are one work model — the workflow is the reusable definition, the task is
495
+ the submitted instance.
496
+
497
+ REQUIRED: `type`, `name`. `triggers` (array) is OPTIONAL — a workflow with no
498
+ triggers is valid and may be invoked manually or by another workflow.
499
+
500
+ When present, `triggers[]` is the canonical schedule source. OS cron, hosted
501
+ schedulers, queues, and daemon timers are wake-up mechanisms only; they MUST NOT
502
+ become the record of what the workflow schedule means. A trigger entry SHOULD
503
+ include:
504
+
505
+ | Field | Description |
506
+ |-------|-------------|
507
+ | `type` | `manual`, `cron`, `interval`, `event`, `webhook`, `file_change`, or `condition`. |
508
+ | `id` / `trigger_id` | Stable trigger identity within the workflow. |
509
+ | `cron` / `interval` / `event_type` | Type-specific selector. |
510
+ | `timezone` | Required for wall-clock schedules; UTC is implied if omitted. |
511
+ | `misfire_policy` | `skip`, `run_once`, or `catch_up`; default `run_once`. |
512
+ | `concurrency` | `allow_parallel`, `skip_if_running`, `enqueue`, or `replace`; default `skip_if_running`. |
513
+
514
+ ```markdown
515
+ ---
516
+ type: workflow
517
+ name: "Daily Digest"
518
+ title: "Daily Digest"
519
+ description: "Sends a daily summary email."
520
+ timestamp: 2026-05-16T14:00:00Z
521
+ triggers:
522
+ - type: cron
523
+ id: daily-0800
524
+ cron: "0 8 * * *"
525
+ timezone: "America/Denver"
526
+ misfire_policy: run_once
527
+ concurrency: skip_if_running
528
+ isActive: true
529
+ ---
530
+
531
+ ## Steps
532
+ 1. Gather unread messages.
533
+ 2. Summarize.
534
+ 3. Send digest.
535
+ ```
536
+
537
+ #### `trigger`
538
+
539
+ A standalone schedule or event-driven trigger that fires a task from a workflow template.
540
+
541
+ REQUIRED: `type`, `name`, `source` (`cron|interval|webhook|event|file_change|condition|manual`), `status` (`active|paused|disabled`).
542
+
543
+ ```markdown
544
+ ---
545
+ type: trigger
546
+ name: "Daily Sync"
547
+ title: "Daily Sync Trigger"
548
+ description: "Fires the daily synchronization workflow at 08:00 UTC."
549
+ timestamp: 2026-05-16T14:00:00Z
550
+ source: cron
551
+ status: active
552
+ cron: "0 8 * * *"
553
+ target_workflow: "workflows/sync.md"
554
+ ---
555
+
556
+ Triggers daily synchronization.
557
+ ```
558
+
559
+ #### `rule`
560
+
561
+ A workspace-scoped behavior rule that constrains how assistants/agents act.
562
+ Distinct from `memory` (which is agent-private knowledge): a `rule` is workspace
563
+ governance, authored deliberately.
564
+
565
+ REQUIRED: `type`, `name`. OPTIONAL: `description`, `scope`.
566
+
567
+ ```markdown
568
+ ---
569
+ type: rule
570
+ name: "No external links in replies"
571
+ title: "No external links in replies"
572
+ description: "Customer-facing replies must not contain outbound URLs."
573
+ timestamp: 2026-05-16T14:00:00Z
574
+ scope: support
575
+ ---
576
+
577
+ Outbound links are stripped from any assistant reply on a support thread.
578
+ ```
579
+
580
+ #### `security_role`
581
+
582
+ A named set of capabilities used for role-based access control (RBAC). It maps
583
+ a role name to the capabilities an agent or user holding that role is granted
584
+ within the workspace.
585
+
586
+ REQUIRED: `type`, `name`, `permissions` (array). OPTIONAL: `description`.
587
+
588
+ ```markdown
589
+ ---
590
+ type: security_role
591
+ name: "support-agent"
592
+ title: "Support agent"
593
+ description: "Can write assistants and events, nothing else."
594
+ timestamp: 2026-05-16T14:00:00Z
595
+ permissions:
596
+ - "ssss:assistant:*"
597
+ - "write:event"
598
+ ---
599
+
600
+ Maintains support assistants and records support events.
601
+ ```
602
+
603
+ `permissions` holds capability strings (§6.6). A capability names a scope and an
604
+ action; `*` in the action position grants every action on that scope, and `*:*`
605
+ grants everything. A `security_role` is one way for a host to derive a
606
+ principal's capabilities. The kernel only ever sees the resulting capability
607
+ list, never the role name.
608
+
609
+ #### `role`
610
+
611
+ A named set of capabilities used for role-based access control (RBAC). Canonical form of `security_role`.
612
+
613
+ REQUIRED: `type`, `name`, `permissions` (array). OPTIONAL: `description`.
614
+
615
+ ```markdown
616
+ ---
617
+ type: role
618
+ name: "support-agent"
619
+ title: "Support agent"
620
+ description: "Can write assistants and events, nothing else."
621
+ timestamp: 2026-05-16T14:00:00Z
622
+ permissions:
623
+ - "ssss:assistant:*"
624
+ - "write:event"
625
+ ---
626
+
627
+ Maintains support assistants and records support events.
628
+ ```
629
+
630
+ #### `model`
631
+
632
+ The definition of an inference model.
633
+
634
+ REQUIRED: `type`, `model_id`, `provider`.
635
+
636
+ ```markdown
637
+ ---
638
+ type: model
639
+ title: "Example Large Model"
640
+ description: "A general-purpose long-context model."
641
+ timestamp: 2026-05-16T14:00:00Z
642
+ model_id: "example/large-model"
643
+ provider: example
644
+ display_name: "Example Large Model"
645
+ ---
646
+
647
+ ## Capabilities
648
+ Long-context reasoning, tool use, vision.
649
+ ```
650
+
651
+ #### `conversation`
652
+
653
+ An append-only chat transcript. Append-type.
654
+
655
+ REQUIRED: `type`, `thread_id`. Typical fields: `workspace_id`, `user_id`, `status`,
656
+ `turn_count`, `created_at`.
657
+
658
+ ```markdown
659
+ ---
660
+ type: conversation
661
+ title: "Greeting"
662
+ description: "A two-turn support conversation."
663
+ timestamp: 2026-05-16T14:00:05Z
664
+ thread_id: "7f3a2b1c-5d6e-4f70-8a91-b2c3d4e5f607"
665
+ workspace_id: "ws-acme"
666
+ user_id: "user-42"
667
+ status: active
668
+ created_at: 2026-05-16T14:00:00Z
669
+ ---
670
+
671
+ ### turn 1 — user — 2026-05-16T14:00:00Z
672
+ Hello.
673
+
674
+ ### turn 2 — assistant — 2026-05-16T14:00:05Z
675
+ Hi — how can I help?
676
+ ```
677
+
678
+ #### `thread`
679
+
680
+ An append-only chat transcript. Append-type. Canonical form of `conversation`.
681
+
682
+ REQUIRED: `type`, `thread_id`. Typical fields: `workspace_id`, `user_id`, `status`,
683
+ `turn_count`, `created_at`.
684
+
685
+ ```markdown
686
+ ---
687
+ type: thread
688
+ title: "Support Thread"
689
+ description: "A two-turn customer support thread."
690
+ timestamp: 2026-05-16T14:00:05Z
691
+ thread_id: "7f3a2b1c-5d6e-4f70-8a91-b2c3d4e5f607"
692
+ workspace_id: "ws-acme"
693
+ user_id: "user-42"
694
+ status: active
695
+ created_at: 2026-05-16T14:00:00Z
696
+ ---
697
+
698
+ ### turn 1 — user — 2026-05-16T14:00:00Z
699
+ Hello.
700
+
701
+ ### turn 2 — assistant — 2026-05-16T14:00:05Z
702
+ Hi — how can I help?
703
+ ```
704
+
705
+ #### `run`
706
+
707
+ An append-only workflow execution record. Append-type.
708
+
709
+ REQUIRED: `type`, `run_id`, `workflow_id`. Typical fields: `workspace_id`, `status`,
710
+ `task_id`, `task_path`, `step_count`, `started_at`.
711
+
712
+ `status` SHOULD be one of: `queued`, `claimed`, `running`, `waiting_for_human`,
713
+ `succeeded`, `failed`, `canceled`, `retrying`, `dead_letter`.
714
+
715
+ ```markdown
716
+ ---
717
+ type: run
718
+ title: "Daily Digest run 2026-05-16"
719
+ description: "Execution record for the 08:00 daily digest."
720
+ timestamp: 2026-05-16T08:00:01Z
721
+ run_id: "run-001"
722
+ workflow_id: "daily-digest"
723
+ task_path: "tasks/daily-digest/daily-0800-20260516T080000Z.md"
724
+ status: queued
725
+ started_at: 2026-05-16T08:00:00Z
726
+ ---
727
+
728
+ ### step 1 — gather — 2026-05-16T08:00:01Z — ok
729
+ Collected 12 messages.
730
+ ```
731
+
732
+ #### `conflict`
733
+
734
+ A record of two contradicting primitives. Blocks promotion until resolved.
735
+
736
+ REQUIRED: `type`, `conflict_id`, `status` (`pending|resolved`), `new_slug`,
737
+ `existing_slug`, `detected_at`.
738
+
739
+ ```markdown
740
+ ---
741
+ type: conflict
742
+ title: "HTML vs plaintext email"
743
+ description: "A new memory contradicts an existing one about email format."
744
+ timestamp: 2026-05-16T18:30:00Z
745
+ conflict_id: conflict-2026-05-16-001
746
+ status: pending
747
+ new_slug: use-html-email
748
+ existing_slug: use-plaintext-email
749
+ detected_at: 2026-05-16T18:30:00Z
750
+ ---
751
+ ```
752
+
753
+ #### `page`
754
+
755
+ A VFS-native sandboxed custom workspace page.
756
+
757
+ REQUIRED: `type`, `slug`, `name`, `sandbox_entry`.
758
+
759
+ ```markdown
760
+ ---
761
+ type: page
762
+ title: "Leads Dashboard"
763
+ description: "A sandboxed dashboard of inbound leads."
764
+ timestamp: 2026-05-16T14:00:00Z
765
+ slug: "leads-portal"
766
+ name: "Leads Dashboard"
767
+ icon: "users"
768
+ layout: "split-chat"
769
+ sandbox_entry: "index.html"
770
+ ---
771
+ ```
772
+
773
+ #### `migration`
774
+
775
+ An SSSS schema migration record.
776
+
777
+ REQUIRED: `type`, `migration_id`, `from_version`, `to_version`, `status`, `description`.
778
+
779
+ ```markdown
780
+ ---
781
+ type: migration
782
+ title: "Add vector_embedding field"
783
+ timestamp: 2026-05-16T14:00:00Z
784
+ migration_id: "mig-v2-to-v3"
785
+ from_version: 2
786
+ to_version: 3
787
+ status: pending
788
+ description: "Add vector_embedding field"
789
+ ---
790
+ ```
791
+
792
+ #### `release`
793
+
794
+ An SSSS system schema version release.
795
+
796
+ REQUIRED: `type`, `release_id`, `version`, `schema_version`, `summary`, `released_at`.
797
+
798
+ ```markdown
799
+ ---
800
+ type: release
801
+ title: "Release 3.1.0"
802
+ description: "Adds proposal and migration file types."
803
+ timestamp: 2026-05-16T12:00:00Z
804
+ release_id: "rel-3.1.0"
805
+ version: "3.1.0"
806
+ schema_version: 3
807
+ summary: "Added proposal and migration file types"
808
+ released_at: 2026-05-16T12:00:00Z
809
+ ---
810
+ ```
811
+
812
+ #### `primitive`
813
+
814
+ A governed definition for a namespaced primitive that can be authored in any human
815
+ language without changing the core registry. REQUIRED: `type`, `primitive_id`,
816
+ `namespace`, `version`, `name`, `mutation`, `portability`, `scopes`, and `fields`.
817
+ Stable primitive, field, enum, capability, and action identifiers are symbolic and
818
+ language-independent. Labels and descriptions are multilingual presentation data.
819
+
820
+ The definition is validated against a meta-schema on write:
821
+
822
+ | Field | Rule |
823
+ |-------|------|
824
+ | `primitive_id` | Qualified (`<namespace>:<id>`), prefix equal to `namespace`. A host MAY derive it from `namespace` + `name` so an author never types one. |
825
+ | `namespace` | Lowercase, `[a-z][a-z0-9_-]{0,63}`. |
826
+ | `version` | Positive integer. `revision`, if present, is a positive integer. |
827
+ | `mutation` | `replace` or `append` (§5.3). |
828
+ | `portability` | A §5.5 class. |
829
+ | `scopes` | Non-empty unique subset of `system`, `account`, `workspace`, `user`. |
830
+ | `fields[]` | Each has a unique symbolic `id`, a non-empty `name` in any language, and a `kind`: `string`, `text`, `number`, `integer`, `boolean`, `datetime`, `date`, `enum` (with unique `values`), `object`, `array`, `reference`, `secret_reference`, or `resource_reference`. |
831
+ | `capabilities` | Optional map of action → list of capability strings. |
832
+ | `aliases` | Optional list of unique safe identifiers that resolve to this primitive. |
833
+
834
+ ```markdown
835
+ ---
836
+ type: primitive
837
+ title: "Booking"
838
+ description: "A customer booking, authored in Japanese."
839
+ timestamp: 2026-05-16T14:00:00Z
840
+ primitive_id: "acme:booking"
841
+ namespace: acme
842
+ version: 1
843
+ name: "顧客予約"
844
+ language: ja
845
+ mutation: replace
846
+ portability: tenant_private
847
+ scopes: [workspace]
848
+ fields:
849
+ - id: reservation_date
850
+ name: "予約日"
851
+ kind: datetime
852
+ required: true
853
+ - id: status
854
+ name: "状態"
855
+ kind: enum
856
+ values: [pending, confirmed]
857
+ capabilities:
858
+ create: ["acme.booking:create"]
859
+ ---
860
+ ```
861
+
862
+ ### 5.5 Portability Classification
863
+
864
+ A workspace is not one undifferentiated blob. Some of it is the **reusable business
865
+ model** (the workflows, assistants, pages, and rules that make the business run); some is
866
+ the operator's **private operational data** (customer transcripts, runtime work); and some
867
+ is **bound to a real external resource** (a domain, a phone number, a mailbox). Selling,
868
+ templating, and backing up a workspace each need a different slice. SSSS makes that slice
869
+ declarable instead of ad-hoc.
870
+
871
+ Every **document** primitive declares one **portability class** in its registry entry.
872
+ (Contract primitives — `operation`/`patch`/`event`/`lease` — are protocol envelopes, not
873
+ stored documents, and have no portability class.)
874
+
875
+ | Class | Meaning | May appear in template/sale? |
876
+ |-------|---------|------------------------------|
877
+ | `structural` | The reusable business model — carries no operator- or customer-specific data. | ✅ verbatim |
878
+ | `tenant_private` | The operator's private operational data (customers, transcripts, runtime work). | ❌ never — backup only, encrypted at rest |
879
+ | `resource_bound` | Requires a real external resource bound at provision time. | ⚠️ as a **requirement declaration** only — the seller's resource value is stripped |
880
+
881
+ A file MAY override its type's default with an `x_portability` frontmatter field. A host
882
+ MUST honor the **most restrictive** of (type default, instance override), ordered
883
+ `structural` < `resource_bound` < `tenant_private`. A file may make itself more private
884
+ than its type, never less. An unrecognized override value is ignored.
885
+
886
+ An **export profile** is simply a filter over portability classes:
887
+
888
+ - **`backup`** — all three classes. `tenant_private` MUST be encrypted at rest.
889
+ - **`template`** / **`sale`** — `structural` verbatim; `resource_bound` reduced to a
890
+ requirement declaration; `tenant_private` **dropped entirely**.
891
+
892
+ A requirement declaration is produced mechanically. The type's registry entry MUST
893
+ declare `resource.binds`, the list of fields that hold the bound value. Each of
894
+ those fields is replaced with the literal string `REQUIREMENT`, and the file is
895
+ marked `x_portability: resource_bound`. An exporter MUST fail rather than emit a
896
+ `resource_bound` file whose type declares no `resource.binds`, because it cannot
897
+ know which fields to strip.
898
+
899
+ A host MUST reject a `template`/`sale` export that would emit a `tenant_private` primitive.
900
+ This single rule is what lets an operator sell a proven business model without ever
901
+ shipping a customer's data — the data is `tenant_private` by classification, so it
902
+ physically cannot enter a sale bundle.
903
+
904
+ ### 5.6 Registries, Qualified Identities & Extensions
905
+
906
+ The type registry is data: `registry/core.json` defines the core primitives, and an
907
+ **extension registry** adds a namespace of its own. Every primitive has a
908
+ **qualified identity**: `ssss:<type>` for core types and `<registry>:<type>` for an
909
+ extension's. A document MAY declare either the bare or the qualified name in
910
+ `type`. Hosts resolve both, and canonical events always record the qualified one
911
+ (§8.2).
912
+
913
+ A registry entry declares the rules that validation (§9) enforces:
914
+
915
+ | Key | Effect |
916
+ |-----|--------|
917
+ | `required_fields` | Fields that MUST be present and non-empty. |
918
+ | `required_when` | `{ "<field>==<value>": [fields] }`: fields required only when the condition holds. |
919
+ | `enums` | Allowed values per field. Array values are checked element by element. |
920
+ | `patterns` | A Unicode regular expression each value of the field MUST match. |
921
+ | `immutable_fields` | Fields a `patch` MUST NOT change. |
922
+ | `references` | Fields holding vault paths, with `allowed_types`, `disallowed_types`, `allowed_portability`, `must_exist`, and an optional `hash_field` pinning the target's content hash. |
923
+ | `append_only` | `true` makes the type append-type (§5.3). |
924
+ | `portability` | The default class (§5.5). |
925
+ | `capabilities` | Per-action capability requirements (§6.6). |
926
+ | `lease_required` | `true` makes every write to the type require a lease (§7). |
927
+ | `resource.binds` | Fields stripped to a requirement declaration on sale export (§5.5). |
928
+
929
+ Composition rules:
930
+
931
+ - An extension MUST NOT redefine or shadow a core type, a sibling extension's type,
932
+ or an existing alias. A collision is a load-time error, not a runtime preference.
933
+ - An extension MAY declare `requires: { "<extension>": "<semver range>" }`. A host
934
+ MUST refuse to load an extension whose dependencies are missing or out of range.
935
+ - A host MAY pin a composed registry set with an **integrity lock**: a SHA-256 over
936
+ the canonical composition. A lock that no longer matches is drift, and a host
937
+ SHOULD refuse to start on it.
938
+ - Extension registry files MUST be regular files. A host MUST refuse symlinked
939
+ registry files.
940
+
941
+ ---
942
+
943
+ ## 6. The Operation Contract
944
+
945
+ All agent-generated mutations to a vault MUST flow through the Operation Contract.
946
+ An agent MUST NOT write vault files directly.
947
+
948
+ ### 6.1 The Envelope
949
+
950
+ An envelope is a JSON object:
951
+
952
+ ```jsonc
953
+ {
954
+ "type": "operation", // "operation" | "patch" | "event" | "delete" (§6.2)
955
+ "workspace_id": "ws-acme", // the vault/workspace scope
956
+ "idempotency_key": "b3c1…", // §6.4
957
+ "path": "assistants/bot/ASSISTANT.md", // vault-relative, no leading "/", no "." or ".." segments
958
+ "content": "---\ntype: …", // operation: full document; event: JSON payload string
959
+ "patches": { }, // patch only
960
+ "primitive_type": "assistant", // OPTIONAL — asserts the target's type
961
+ "operation_id": "uuid", // OPTIONAL — client-chosen; generated if absent
962
+ "lease_id": "uuid", // OPTIONAL — §7
963
+ "dry_run": false, // OPTIONAL — validate and authorize without committing
964
+ "intent": "human description" // OPTIONAL — audit annotation, not interpreted
965
+ }
966
+ ```
967
+
968
+ The envelope carries **no identity**. Who is acting is supplied by the host as a
969
+ verified principal, next to the envelope and never inside it (§6.6). A kernel
970
+ MUST ignore any identity-bearing field a client places in the envelope, including
971
+ the pre-0.9 `actor` object.
972
+
973
+ A `path` MUST be rejected with `invalid_request` if it is empty, absolute, contains
974
+ a backslash or NUL, or has an empty, `.`, or `..` segment. A host MUST also refuse
975
+ to follow a symbolic link out of the vault.
976
+
977
+ ### 6.2 Envelope Types
978
+
979
+ | `type` | Semantics | Required fields beyond `type`, `workspace_id`, `idempotency_key`, `path` |
980
+ |--------|-----------|------------|
981
+ | `operation` | Create a document, or fully replace an existing one. | `content` (string) |
982
+ | `patch` | Merge into an existing document's frontmatter and/or body. | `patches` (object) |
983
+ | `event` | Append an immutable entry to the event log (§8). Never touches a document. | none; `content`, if present, MUST be a JSON string |
984
+ | `delete` | Remove a replace-type document. | none |
985
+
986
+ **`operation`** — `content` is the complete document. An `operation` MUST NOT
987
+ change the `type` of an existing document; changing type is a migration
988
+ (§5.4 `migration`). Writing a directory `index.md` (§4.3) is permitted and is
989
+ not validated as a primitive.
990
+
991
+ **`patch`** — keys of `patches` are merged shallowly into the frontmatter: a
992
+ supplied key replaces that key's whole value, and absent keys are untouched. The
993
+ reserved key `__body__` replaces the Markdown body of a replace-type document, or
994
+ is appended to the body of an append-type document (§5.3). A `patch` MUST NOT
995
+ change `type` or any of the type's `immutable_fields`. The merged document is
996
+ validated as a whole before commit.
997
+
998
+ **`event`** — the parsed `content` becomes the event's `payload` (§8.2). The target
999
+ `path` is recorded as the event's `subject` and need not exist.
1000
+
1001
+ **`delete`** — the host removes the document and records the deletion as an event,
1002
+ so history is never lost. A `delete` targeting an append-type document MUST be
1003
+ rejected with `validation_failed`. A `delete` of a path that does not exist MUST be
1004
+ rejected with `not_found`, unless it is an idempotent replay of an earlier delete
1005
+ with the same key, in which case the original result is returned (§6.4). `delete`
1006
+ is the only envelope that removes vault state. Export and provision (§16, §17)
1007
+ never delete.
1008
+
1009
+ ### 6.3 The Processing Pipeline
1010
+
1011
+ A host MUST process every envelope through these stages, in this order. A failure
1012
+ at any stage before the commit point aborts the envelope with nothing committed.
1013
+ Kernels MUST NOT reorder or skip stages. Adapters (§6.7) implement mechanics only.
1014
+
1015
+ | # | Stage | On failure |
1016
+ |---|-------|------------|
1017
+ | 1 | **Envelope & identity** — known `type`, required fields present and well-typed (§6.2); a principal with an `id` and `kind` is attached. Nothing is read before this passes, so an anonymous caller learns nothing about the vault. | `invalid_request`, `unauthorized` |
1018
+ | 2 | **Idempotency** — look up (`workspace_id`, `idempotency_key`). Same request hash: return the stored response with `replay: true` and stop. Different hash: stop (§6.4). | `idempotency_conflict` |
1019
+ | 3 | **Read current state** — load the target, if any, and its version. An unsafe path fails here. | `invalid_request`, or `internal_error` for unreadable stored state |
1020
+ | 4 | **Content validation** — resolve the primitive and validate the resulting document (§9). Enforce type immutability, `immutable_fields`, patch/delete target existence, and append-only rules. | `not_found`, `validation_failed` |
1021
+ | 5 | **Authorization** — the verified principal must be complete (§6.6), scoped to `workspace_id`, and hold every capability the primitive and action require. | `unauthorized`, `forbidden` |
1022
+ | 6 | **Lease** — if the primitive is `lease_required` or the host requires a lease for this path, verify it (§7). | `lease_conflict` |
1023
+ | 7 | **Resource prepare** — if the host coordinates an external resource (a domain, a phone number), reserve it. | `internal_error` |
1024
+ | 8 | **Dry-run exit** — if `dry_run`, release anything prepared in stage 7 and return success with `committed_at: null`. | — |
1025
+ | 9 | **Commit** — under the path's commit intent (below), write the document with a compare-and-swap on the version read in stage 3 (create-if-absent for a new document), or remove it for `delete`. `event` envelopes write nothing here. | `version_conflict`, `internal_error` |
1026
+ | 10 | **Event append — the commit point.** Append the canonical event (§8.2). If the append fails, undo stage 9 and release stage 7. | `internal_error` |
1027
+ | 11 | **Resource finalize** — complete the external effect. A failure here MUST NOT undo the commit. The host reconciles and the response carries a warning. | warning only |
1028
+ | 12 | **Projections** — dispatch the event to projections (§10). A failure is a warning, never a rollback. | warning only |
1029
+ | 13 | **Record idempotency** — store the response under the key (§6.4). | warning only |
1030
+
1031
+ **The commit point.** A mutation is committed exactly when its canonical event is
1032
+ durably appended. Before that, every failure leaves no trace in the vault. After
1033
+ it, nothing may undo the mutation, because the append-only log (§8) already says it
1034
+ happened. Work after the commit point is compensated forward, never rolled back.
1035
+
1036
+ **Commit intents.** A process can die between stage 9 and stage 10, leaving the
1037
+ vault ahead of the log. A host whose vault outlives the process MUST therefore,
1038
+ before stage 9, durably record a *commit intent* for the path and hold the path's
1039
+ commit lock until stage 10 ends. The intent names the `event_id` the commit will
1040
+ append, the prior content (or its absence), and a digest of the intended content.
1041
+ Durably means the intent, then the stage-9 write, then the stage-10 append each
1042
+ reach stable storage before the next begins.
1043
+
1044
+ An intent whose lock is free belongs to a writer that died. Before the next commit
1045
+ on that path, and before a kernel's first operation, the host resolves it:
1046
+
1047
+ | The log holds the intent's `event_id` | The document now | Outcome |
1048
+ |---|---|---|
1049
+ | yes | anything | `committed` — the commit stands |
1050
+ | no | has the intended digest (absent, for `delete`) | `rolled_back` — the prior content is restored |
1051
+ | no | has the prior digest (absent, if it had none) | `discarded` — stage 9 never landed |
1052
+ | no | anything else | `conflict` — written outside the kernel; the intent is kept aside and reported |
1053
+
1054
+ An intent whose writer is alive is never resolved. A writer that read uncommitted
1055
+ state fails its stage-9 compare-and-swap after the rollback and retries on the real
1056
+ state, so nothing is ever committed on top of a write that did not commit. The
1057
+ reference `FileSystemVfs` supplies a journal under the reserved `.ssss-intents/`
1058
+ directory; `kernel.recover()` runs resolution on demand.
1059
+
1060
+ **Resource lifecycle.** If a host coordinates external resources, every successful
1061
+ `prepare` MUST be followed by exactly one `finalize` or `reconcile`. `reconcile`
1062
+ receives the phase it runs in (`dry_run`, `commit`, or `finalize`), so the host
1063
+ can tell a released reservation from a compensation after a committed intent.
1064
+
1065
+ **Concurrency.** Two envelopes racing on one path are serialized by the stage-9
1066
+ compare-and-swap. The loser either finds a winner with the same key and returns
1067
+ that winner's result as a replay, or fails with `version_conflict`. Two `event`
1068
+ envelopes with the same key are serialized by the event store's uniqueness on
1069
+ `event_id` (§8.1).
1070
+
1071
+ ### 6.4 Idempotency
1072
+
1073
+ Every envelope carries an `idempotency_key`, scoped to its `workspace_id`.
1074
+
1075
+ - The **request hash** is SHA-256 over the canonical JSON (keys sorted
1076
+ recursively, no insignificant whitespace) of `type`, `workspace_id`,
1077
+ `idempotency_key`, `path`, `primitive_type`, `content`, `patches`, and the
1078
+ verified principal's `id`. `dry_run`, `lease_id`, `operation_id`, and `intent`
1079
+ are excluded, so retrying with a fresh lease is still the same request.
1080
+ - Only **successful commits** are recorded. A failed or dry-run envelope records
1081
+ nothing, so it may be retried under the same key after the cause is fixed.
1082
+ - A recorded key replays: the same request hash returns the original response with
1083
+ `replay: true` and changes nothing. A different request hash under the same key
1084
+ fails with `idempotency_conflict`.
1085
+ - Because the principal is part of the hash, a key replayed by a *different*
1086
+ principal is a conflict, never a disclosure of another principal's result.
1087
+ - **The event log is the durable record.** Every committed envelope's event
1088
+ carries its `idempotency_key` and `request_hash` (§8.2), written at the commit
1089
+ point, so it survives anything the commit survives. The idempotency store is a
1090
+ cache of full responses in front of it. When the store has no record, a kernel
1091
+ MUST look the key up in the log if its event store supports that lookup
1092
+ (§6.7): the first event under the key decides. A matching hash replays a
1093
+ response rebuilt from the event, identical to the original except that
1094
+ post-commit warnings (stages 11–13) are absent; any other hash, including a
1095
+ missing one, is `idempotency_conflict`.
1096
+ - **Retention.** A host whose event store answers key lookups MAY expire store
1097
+ records; the reference `FileIdempotencyStore` keeps them 24 hours by default.
1098
+ A host whose event store cannot answer them MUST retain records indefinitely.
1099
+ - An `unchanged` response (an `operation` identical to the stored document)
1100
+ commits nothing and appends no event, so only the store holds it.
1101
+
1102
+ Keys are opaque strings. Use a random UUID for ad-hoc requests. Use a
1103
+ deterministic derivation where retries must converge, as with runtime-created work
1104
+ (§11.8) and bundle import (§17). A committed key is never reusable for a different
1105
+ request, so a derivation MUST cover everything that distinguishes one intended
1106
+ request from another: the reference bundle import derives its key from the
1107
+ workspace, the target path, and the file's content digest.
1108
+
1109
+ ### 6.5 The Response & Error Codes
1110
+
1111
+ ```jsonc
1112
+ {
1113
+ "success": true,
1114
+ "type": "operation",
1115
+ "operation_id": "uuid",
1116
+ "path": "assistants/bot/ASSISTANT.md",
1117
+ "committed_at": "2026-05-16T14:00:00Z", // null for dry_run and failures
1118
+ "dry_run": false,
1119
+ "event_id": "uuid", // the canonical event (§8.2); absent unless committed
1120
+ "replay": true, // present only on an idempotent replay
1121
+ "validation": {
1122
+ "valid": true,
1123
+ "type": "ssss:assistant", // resolved qualified type (§5.6)
1124
+ "errors": [],
1125
+ "warnings": [] // e.g. a projection or finalize failure
1126
+ }
1127
+ }
1128
+ ```
1129
+
1130
+ A failed response has `success: false`, `committed_at: null`, `validation.valid:
1131
+ false`, the `repair` block of §9, and an `error` object:
1132
+
1133
+ ```jsonc
1134
+ { "success": false, "error": { "code": "validation_failed", "message": "name: Missing required field 'name'." }, "…": "…" }
1135
+ ```
1136
+
1137
+ `error.code` is exactly one of the symbolic codes below. Clients MUST branch on
1138
+ `error.code`, never on message text. A host MAY use any transport. If it uses HTTP,
1139
+ it MUST use these statuses, `201` for a commit, and `200` for a replay or dry run:
1140
+
1141
+ | Code | HTTP | Meaning |
1142
+ |------|------|---------|
1143
+ | `invalid_request` | 400 | Malformed envelope, non-JSON event content, or an unsafe path. |
1144
+ | `unauthorized` | 401 | No valid verified principal reached the kernel. |
1145
+ | `forbidden` | 403 | The principal is not scoped to the workspace or lacks a required capability. |
1146
+ | `not_found` | 404 | The `patch` or `delete` target does not exist. |
1147
+ | `lease_conflict` | 409 | A required lease is missing, mismatched, or expired. |
1148
+ | `version_conflict` | 409 | The document changed between read and commit, and no same-key winner exists. |
1149
+ | `idempotency_conflict` | 409 | The key was already used for a different request. |
1150
+ | `validation_failed` | 422 | The document fails §9, or the envelope would change a type, an immutable field, or an append-only document. |
1151
+ | `internal_error` | 500 | Unreadable stored state, a failed resource prepare, or a failed commit. Nothing was committed. |
1152
+
1153
+ ### 6.6 Identity & Authorization
1154
+
1155
+ Authorization acts on a **verified principal** that the host attaches *outside* the
1156
+ envelope, after authenticating the caller:
1157
+
1158
+ ```jsonc
1159
+ {
1160
+ "id": "user-42", // stable, recorded on every event
1161
+ "kind": "human", // "human" | "agent" | "service" | "system"
1162
+ "workspaceIds": ["ws-acme"], // workspaces this principal may act in
1163
+ "capabilities": ["ssss:assistant:*"], // §6.6 capability strings
1164
+ "authentication": { "provider": "oidc", "assurance": "verified" }
1165
+ }
1166
+ ```
1167
+
1168
+ - A host that exposes the Operation Contract to untrusted callers MUST derive the
1169
+ principal from its own authentication, never from the request body. This is why
1170
+ the envelope carries no identity (§6.1).
1171
+ - A missing or malformed principal MUST be denied as `unauthorized`. There is no
1172
+ default principal and no anonymous write.
1173
+ - A non-`system` principal MUST list the envelope's `workspace_id` in
1174
+ `workspaceIds`.
1175
+ - The required capabilities are the primitive's registry `capabilities[<action>]`,
1176
+ or `<qualified_type>:<action>` if none are declared. The action is one of
1177
+ `create`, `replace`, `patch`, `append`, `event`, or `delete`. It is derived from
1178
+ the envelope and the target's existence, never supplied by the client. `event`
1179
+ envelopes require `write:event`.
1180
+ - A granted capability covers a required one if it is equal, if it is `*:*`, or if
1181
+ it ends in `:*` and the required capability starts with everything before that
1182
+ `*`. So `ssss:*` covers every core primitive and `ssss:assistant:*` covers every
1183
+ action on assistants.
1184
+ - A `system` principal bypasses capability checks. It exists for trusted internal
1185
+ callers such as import (§17). A host MUST NOT grant `system` to anything a remote
1186
+ caller controls.
1187
+ - A host MAY layer **policy floors** (extra capabilities per primitive and action),
1188
+ **step-up** (a minimum `authentication.assurance`), and **human confirmation**
1189
+ (a `human` principal plus an explicit confirmation) on top of this. These only
1190
+ ever add requirements.
1191
+
1192
+ **Pre-0.9 role compatibility.** Hosts that still accept the pre-0.9 envelope field
1193
+ `actor.role` MUST convert it to a principal before stage 5. `system` becomes a
1194
+ `system` principal, `admin` receives `*:*`, and any other role receives the
1195
+ `permissions` of its `security_role` document at `roles/<role>/ROLE.md`, with
1196
+ `write:<type>` and `*:<type>` expanded to `<qualified_type>:*`, and `write:*`
1197
+ expanded to `*:*`. A missing role still MUST be denied, never promoted.
1198
+
1199
+ ### 6.7 Adapter Contracts
1200
+
1201
+ A kernel owns the stages above. A host supplies the mechanics through adapters,
1202
+ each with a shared contract test in the conformance suite (§12):
1203
+
1204
+ | Adapter | Contract |
1205
+ |---------|----------|
1206
+ | **VFS** | `read(path) → {bytes, version, hash} \| null`; `writeAtomic(path, bytes, {version \| ifAbsent})` and `remove(path, {version})`, both compare-and-swap, failing with a version conflict and never a partial write. Rejects unsafe paths and symlink traversal. A VFS whose state outlives the process SHOULD provide `intentJournal()`, its co-located intent journal. |
1207
+ | **Event store** | `append(event)` durably and in order, rejecting a duplicate `event_id` across every writer; `replay({cursor, workspaceId})` in append order. SHOULD provide `findByIdempotencyKey(workspaceId, key) → event \| null`, the first event recorded under the key, across every writer and every rotated segment (§6.4). |
1208
+ | **Intent journal** | `run(path, intent, commit, {resolve})` holds the path's commit lock across `commit`, first passing any leftover intent for the path to `resolve`, and removes the intent afterward unless `commit` asks to keep it; `recover(resolve)` resolves every intent whose writer is gone and reports live ones as `in_flight` (§6.3). |
1209
+ | **Idempotency store** | `get(workspace, key)`; `put(workspace, key, record)`, which rejects a second `put` for the same key across every writer. |
1210
+ | **Lease store** | `acquire`, `verify`, `renew`, `release` per §7, with at most one live lease per target across every writer. |
1211
+ | **Authorizer** | `authorize({principal, workspaceId, definition, action}) → {allowed, reason}`, per §6.6. Fails closed. |
1212
+ | **Projection coordinator** | `dispatch(event)`, `replay(id, {rebuild})`, `detectDrift(id, hash)` per §10. |
1213
+ | **Resource coordinator** | Optional `prepare`, `finalize`, `reconcile`, per the §6.3 resource lifecycle. |
1214
+
1215
+ "Across every writer" means across threads, processes, and hosts sharing the same
1216
+ storage, not just within one instance.
1217
+
1218
+ ---
1219
+
1220
+ ## 7. Leases — Concurrency Control
1221
+
1222
+ A **lease** is a time-bound write claim on one `(workspace_id, target)` pair. It
1223
+ lets an agent do long work (such as a workflow run, §11.8) without another agent
1224
+ writing the same path underneath it.
1225
+
1226
+ A lease record carries `lease_id`, `workspace_id`, `target`, `principal_id`,
1227
+ `operation_id`, `issued_at`, and `expires_at`.
1228
+
1229
+ - **acquire** — grants a lease if no live lease exists on the target; otherwise it
1230
+ fails. At most one live lease MAY exist per target, across every writer.
1231
+ - **verify** — succeeds only if a live lease exists and its `lease_id`,
1232
+ `principal_id`, and `operation_id` all match the caller. A lease is bound to the
1233
+ principal and the unit of work that took it. Presenting someone else's
1234
+ `lease_id` is not enough. An envelope that writes under a lease therefore
1235
+ carries both `lease_id` and the `operation_id` the lease was acquired with.
1236
+ - **renew** — extends `expires_at` for the verified holder.
1237
+ - **release** — deletes the lease for the verified holder.
1238
+ - An expired lease is treated as absent. A host SHOULD reclaim expired leases.
1239
+
1240
+ Whether a write *requires* a lease is decided by the primitive's `lease_required`
1241
+ flag or by host policy. Unleased writes are otherwise protected by the stage-9
1242
+ compare-and-swap (§6.3). Leases are coordination, not security. Authorization
1243
+ (§6.6) is the security boundary.
1244
+
1245
+ ---
1246
+
1247
+ ## 8. The Event Log
1248
+
1249
+ The event log is an **append-only, immutable** record. It is two things at once: a
1250
+ flat physical *log*, and a relational *event graph* layered on top of it.
1251
+
1252
+ ### 8.1 The Log
1253
+
1254
+ - Every committed envelope appends exactly one canonical event (§6.3 stage 10). The
1255
+ event *is* the audit record. There is no separate audit write.
1256
+ - An entry, once written, MUST NOT be updated or deleted.
1257
+ - `event_id` is unique within the log, across every writer. For `event` envelopes,
1258
+ a kernel SHOULD derive `event_id` deterministically from (`workspace_id`,
1259
+ `idempotency_key`). The reference uses UUIDv5 over their JSON array. That way,
1260
+ concurrent duplicates of one event collide on the uniqueness check instead of
1261
+ both landing. Other envelopes get their `event_id` before stage 9, so a commit
1262
+ intent (§6.3) can name the event that decides it.
1263
+ - The log is also the durable idempotency record (§6.4): the first event recorded
1264
+ under an `idempotency_key` decides every later request with that key.
1265
+ - Order is append order within a log.
1266
+ - The event log is the canonical history of *what happened*; the vault is the
1267
+ canonical state of *what is true now*. Both are source-of-truth; projections are
1268
+ not.
1269
+
1270
+ ### 8.2 The Event Record
1271
+
1272
+ An event is a typed record, **not** a document primitive. There is no `EVENT.md`;
1273
+ events exist only in the log.
1274
+
1275
+ | Field | Description |
1276
+ |-------|-------------|
1277
+ | `event_id` | Unique identity (§8.1). |
1278
+ | `event_type` | The kind of event. Kernel mutations use `ssss.mutation`. |
1279
+ | `schema_version` | Version of this record shape; currently `1`. |
1280
+ | `timestamp` | ISO 8601 commit time. |
1281
+ | `workspace_id` | The workspace. |
1282
+ | `primitive_id`, `primitive_version` | The qualified type (§5.6) and its version. `ssss:event` for `event` envelopes. |
1283
+ | `action` | `create`, `replace`, `patch`, `append`, `event`, or `delete`. |
1284
+ | `subject` | The vault path the event is about. |
1285
+ | `principal` | The verified principal (§6.6) that caused it. |
1286
+ | `operation_id`, `idempotency_key`, `request_hash` | Ties the event to its envelope (§6.4). |
1287
+ | `correlation_id` | Groups every event of one logical flow ("saga"). Defaults to `operation_id`. |
1288
+ | `causation_id` | The `event_id` that directly caused this one, or `null`. |
1289
+ | `before_hash`, `after_hash` | Content hashes of the target before and after, so the log alone can detect vault drift. |
1290
+ | `changed_fields` | For `patch`, the sorted keys that were patched. |
1291
+ | `resource_status` | `prepared` if a resource coordinator took part (§6.3), else `null`. |
1292
+ | `payload` | The event-type-specific body (for `event` envelopes, the parsed `content`). |
1293
+
1294
+ ### 8.3 The Event Graph
1295
+
1296
+ Events relate to **non-adjacent** events: a feedback event refers to the completion
1297
+ it rated, an investigation to the feedback that triggered it, a fix to the
1298
+ investigation. These references form a causal **graph** over the flat log.
1299
+
1300
+ The graph is preserved without violating append-only because **edges point backward
1301
+ only**: a new event records its `causation_id` parent; an existing event is never
1302
+ mutated to record a child. The forward view (an event's children, a full saga tree)
1303
+ is reconstructed by scanning — so the **event graph is a derived artifact** (§10),
1304
+ disposable and rebuildable. Relationships are canonical (backward `event_id`
1305
+ references stored in the log); the graph index is only a cache.
1306
+
1307
+ A **session** is not a separate primitive — it is a named, `correlation_id`-scoped
1308
+ slice of the event graph: the saga tree of one coherent unit of work.
1309
+
1310
+ ---
1311
+
1312
+ ## 9. Validation & Repair
1313
+
1314
+ Validation is **deterministic**: identical input always yields an identical verdict.
1315
+ It is a pure function of the document and the composed registry (§5.6).
1316
+
1317
+ A document is valid if and only if:
1318
+
1319
+ 1. Its frontmatter parses (§4.5) to an object.
1320
+ 2. `type` resolves, bare or qualified, to a primitive in the registry.
1321
+ 3. Every universal field (§4.2) and every `required_fields` entry is present and
1322
+ non-empty. `null`, `""`, and `[]` count as empty.
1323
+ 4. Every `required_when` condition that holds has its fields present and non-empty.
1324
+ 5. Every present field with an `enums` entry takes allowed values only.
1325
+ 6. Every present field with a `patterns` entry matches it.
1326
+ 7. Every `references` field names a safe vault path to an existing document (unless
1327
+ `must_exist: false`) of an allowed type and portability. If a `hash_field` is
1328
+ declared, it equals the target's current content hash.
1329
+ 8. A `primitive` document also satisfies the §5.4 `primitive` meta-schema.
1330
+
1331
+ On top of the document rules, stage 4 (§6.3) rejects an envelope that would change
1332
+ a document's `type`, change an `immutable_fields` value, rewrite an append-type
1333
+ document, or delete one.
1334
+
1335
+ Hosts MUST NOT reject a document because of unknown frontmatter keys. Unknown keys
1336
+ MUST be preserved to support agent scratchpads and forward compatibility with OKF
1337
+ extensions.
1338
+
1339
+ On failure, the host MUST return structured **repair feedback** so an agent can
1340
+ self-correct without guesswork:
1341
+
1342
+ ```jsonc
1343
+ {
1344
+ "repair": {
1345
+ "field_errors": [
1346
+ { "field": "name", "issue": "Missing required field 'name'." }
1347
+ ]
1348
+ }
1349
+ }
1350
+ ```
1351
+
1352
+ A host MAY also emit non-blocking `warnings` (deprecated fields, low-confidence
1353
+ content, a failed projection). Warnings MUST NOT block a commit.
1354
+
1355
+ ---
1356
+
1357
+ ## 10. Derived Artifacts
1358
+
1359
+ Hosts MAY maintain derived artifacts for performance: search indexes, embedding
1360
+ indexes, graph indexes, the **event-graph index** (the forward/causal view of the
1361
+ event log — see §8.3), routing logs, and relational **projections** of vault data.
1362
+
1363
+ All derived artifacts are **disposable**:
1364
+
1365
+ - They MUST be fully rebuildable from the vault alone.
1366
+ - They MUST NOT be treated as source-of-truth for product meaning.
1367
+ - Deleting them MUST NOT lose information — only force a rebuild.
1368
+
1369
+ A host that maintains projections MUST provide a means to (a) rebuild a projection
1370
+ from a vault scan, and (b) detect and repair drift between a projection and the
1371
+ vault.
1372
+
1373
+ ### 10.1 Projection Manifest
1374
+
1375
+ A host SHOULD maintain a `MANIFEST.json` (or equivalent) in the derived-artifacts
1376
+ directory declaring each projection as disposable and recording provenance:
1377
+
1378
+ ```jsonc
1379
+ {
1380
+ "type": "projection-manifest",
1381
+ "generated_at": "2026-05-30T06:35:00Z",
1382
+ "vault_hash": "sha256:abc123...", // content hash of the vault at build time
1383
+ "projections": [
1384
+ { "file": "graph-index.jsonl", "disposable": true },
1385
+ { "file": "memory-layers.jsonl", "disposable": true },
1386
+ { "file": "embeddings.json", "disposable": true }
1387
+ ],
1388
+ "rebuild_command": "<host-defined rebuild command>"
1389
+ }
1390
+ ```
1391
+
1392
+ The `vault_hash` field enables **staleness detection**: if the current vault hash
1393
+ differs from the manifest's hash, the projections are stale and SHOULD be rebuilt.
1394
+ This supports **incremental compilation** — a host MAY skip recompilation when the
1395
+ hash matches, avoiding redundant I/O on unchanged vaults.
1396
+
1397
+ ---
1398
+
1399
+ ## 11. The Semantic Layer
1400
+
1401
+ SSSS operates as two layers with deliberately opposite requirements. A conformant
1402
+ host MUST keep them separate.
1403
+
1404
+ ### 11.1 The Two Layers
1405
+
1406
+ **The deterministic layer** — the file format (§4), type registry (§5), Operation
1407
+ Contract (§6), leases (§7), event log (§8), and validation (§9). It is exact and
1408
+ reproducible: identical input yields an identical verdict. It is language-independent
1409
+ *by construction*: its control vocabulary — every frontmatter **key** and every
1410
+ enumerated **value** (`type`, `modality`, `status`, the primitive type names, …) —
1411
+ consists of **stable symbolic identifiers**, never localized words. They are never
1412
+ translated, exactly as a JSON key or an HTTP method is never translated. Only
1413
+ natural-language *content* (§11.2) carries language. A host MUST NOT make this layer
1414
+ fuzzy.
1415
+
1416
+ **The semantic layer** — retrieval, routing, deduplication, conflict detection, and
1417
+ memory surfacing. It operates on **meaning**, not on shared surface tokens. This is
1418
+ where natural-language content lives, and where SSSS becomes genuinely
1419
+ language-independent. A host MUST NOT make this layer depend on lexical token overlap
1420
+ alone.
1421
+
1422
+ ### 11.2 Language Independence
1423
+
1424
+ Natural-language fields — `title`, `description`, document bodies, feedback comments —
1425
+ MAY be authored in ANY language. The semantic layer MUST treat documents by meaning,
1426
+ so a node authored in one language remains retrievable, routable, and
1427
+ conflict-checkable against a query or node in any other. Implementations SHOULD use a
1428
+ multilingual embedding model so that all languages share a single vector space.
1429
+
1430
+ ### 11.3 The Embedding Index
1431
+
1432
+ The semantic layer is backed by an **embedding index** — a derived artifact (§10):
1433
+ disposable, never source-of-truth, fully rebuildable from the vault.
1434
+
1435
+ - It MUST record the `embedding_model` and vector `dim` that produced it. Embeddings
1436
+ are not comparable across models; a model change REQUIRES a full reindex.
1437
+ - A host MUST maintain exactly **one canonical embedding implementation**. Parallel
1438
+ or duplicate embedding systems (e.g. one in JSON format and another in JSONL)
1439
+ create consistency risks where a node is indexed in one but not the other.
1440
+ - Retrieval SHOULD be **hybrid**: an exact/lexical pass (strong for slugs,
1441
+ identifiers, and code) fused with a dense semantic pass (strong for meaning and
1442
+ cross-lingual matches).
1443
+
1444
+ ### 11.4 Provenance
1445
+
1446
+ So that outcomes can be attributed to their causes, append-type records (conversation
1447
+ turns, run steps) SHOULD capture **provenance**: the set of primitives that produced
1448
+ the record — e.g. the assistant, model, skills, and memory nodes in play. Provenance
1449
+ is what lets a quality signal on an outcome propagate back to the primitives
1450
+ responsible for it.
1451
+
1452
+ ### 11.5 The `feedback` Block
1453
+
1454
+ Any document primitive MAY carry an OPTIONAL `feedback` frontmatter block — a
1455
+ derived, language-neutral rollup of feedback signal:
1456
+
1457
+ ```yaml
1458
+ feedback:
1459
+ score: 0.82 # 0..1, normalized
1460
+ positive: 14
1461
+ negative: 3
1462
+ samples: 17
1463
+ last_feedback: 2026-05-16T09:00:00Z
1464
+ ```
1465
+
1466
+ - Raw feedback MUST be recorded as `type: event` entries in the append-only event
1467
+ log (§8) — never written as raw events directly into a document's frontmatter.
1468
+ - The `feedback` block is a **rollup** of those events, recomputed periodically — the
1469
+ same derived-cache pattern as `confidence`. It lives in the canonical file but is a
1470
+ deliberately-lagged projection of the log.
1471
+ - The block MUST be language-neutral structured signal (scores, counts, polarity),
1472
+ never prose. Free-text feedback lives in the event payload and the embedding index.
1473
+
1474
+ ### 11.6 Feedback as an Enhancement Layer
1475
+
1476
+ A host MAY use feedback to adjust `confidence`, routing weight, and to trigger
1477
+ investigation of low-scored outcomes. Feedback is strictly an **enhancement** layer:
1478
+ a host MUST remain fully functional with feedback collection disabled, and the
1479
+ semantic layer MUST degrade gracefully to its other signals (access frequency, decay,
1480
+ embedding similarity).
1481
+
1482
+ ### 11.7 The `language_convention` Primitive
1483
+
1484
+ Because the control vocabulary is symbolic and never translated (§11.1), a workspace
1485
+ that wishes to *present* itself in a given human language does so with data, not by
1486
+ translating keys. The `language_convention` primitive (a `structural`, extension-owned
1487
+ type) records a workspace's presentation conventions: its default
1488
+ language/locale, formality, date and currency formatting, and terminology preferences.
1489
+
1490
+ It is `structural` and therefore travels in `template`/`sale` bundles (§5.5): a sold
1491
+ business carries its voice and locale conventions, but never the operator's private
1492
+ content. A host applies a `language_convention` as a **presentation overlay** at the
1493
+ semantic/rendering layer; it MUST NOT alter the deterministic layer's symbolic keys or
1494
+ enumerated values.
1495
+
1496
+ ### 11.8 Workflow Runtime & Daemon Contract
1497
+
1498
+ SSSS defines the source of truth for workflow runtime behavior, but it does not
1499
+ mandate one resident process manager. A host MAY use OS cron, systemd timers,
1500
+ serverless schedules, webhooks, message queues, browser alarms, or an always-on
1501
+ daemon to wake the runtime. Those systems are **wake-up mechanisms** only. They MUST
1502
+ NOT become the canonical schedule, queue, or task history.
1503
+
1504
+ The canonical runtime sources are:
1505
+
1506
+ | Concern | Source of truth |
1507
+ |---------|-----------------|
1508
+ | Schedule and trigger meaning | `workflow` frontmatter `triggers[]`. |
1509
+ | Submitted work | `task` documents. |
1510
+ | Execution transcript | append-only `run` documents. |
1511
+ | What happened | append-only event log (§8). |
1512
+ | Claim/concurrency safety | leases (§7) plus deterministic idempotency keys (§6.4). |
1513
+ | Dashboards, task queues, cursors | projections (§10), rebuildable from the vault and event log. |
1514
+
1515
+ A conformant daemon loop is:
1516
+
1517
+ 1. **Scan** active `workflow` primitives whose `triggers[]` might fire.
1518
+ 2. **Evaluate** the trigger against wall-clock time, incoming event, webhook, file
1519
+ change, condition, or explicit manual invocation.
1520
+ 3. **Append** a `workflow_triggered` event via an `event` envelope.
1521
+ 4. **Instantiate** one `task` via an `operation` envelope.
1522
+ 5. **Claim** the task using a time-bound lease before execution.
1523
+ 6. **Create or append** a `run` record for execution steps.
1524
+ 7. **Patch** task status to `done` or `failed`, or to `pending` with retry metadata.
1525
+ 8. **Rebuild** derived task queues, run timelines, graph indexes, or UI projections
1526
+ as needed.
1527
+
1528
+ Every step that mutates vault state MUST use the Operation Contract (§6). A daemon
1529
+ MUST NOT write task, run, cursor, or workflow files directly.
1530
+
1531
+ #### Trigger Types
1532
+
1533
+ Core trigger types are:
1534
+
1535
+ | Type | Fires when |
1536
+ |------|------------|
1537
+ | `manual` | A human, agent, or another workflow invokes it. |
1538
+ | `cron` | A wall-clock cron expression reaches a scheduled instant. |
1539
+ | `interval` | A fixed duration elapses after the previous scheduled instant. |
1540
+ | `event` | A matching event-log entry appears. |
1541
+ | `webhook` | A verified external request arrives. |
1542
+ | `file_change` | A matching vault path is created, patched, or deleted. |
1543
+ | `condition` | A host-defined predicate over vault/projection state becomes true. |
1544
+
1545
+ An `event` trigger selects canonical events (§8) with two optional fields on the
1546
+ `trigger` primitive, evaluated as a pure function of the trigger and the event:
1547
+
1548
+ - `event_subject` is a glob over the event `subject`. `*` matches within one `/`
1549
+ segment and `**` matches across segments.
1550
+ - `event_match` maps dotted event paths (for example `principal.kind`) to a literal
1551
+ or an array of allowed literals. Every entry MUST hold.
1552
+
1553
+ A trigger with neither field matches nothing. An event nobody matches is only
1554
+ recorded. Work an event causes MUST carry the event's `event_id` as `causation_id`,
1555
+ and its idempotency basis uses `event_id` in place of `scheduled_for`, so a replayed
1556
+ event creates no second task and two events at the same instant create two.
1557
+
1558
+ An `assistant` MAY declare `owns`, a list of subject globs it is responsible for.
1559
+ The owner of a subject is the assistant whose claim has the longest literal prefix.
1560
+ Equal best claims are a conflict that a host MUST surface rather than resolve
1561
+ silently. Ownership says who is responsible; a lease (§7) says who is acting now.
1562
+
1563
+ Trigger entries SHOULD use the fields documented in §5.4 `workflow`. Hosts MAY add
1564
+ type-specific `x_` fields, but MUST preserve unknown fields when rewriting the
1565
+ workflow document (§4.2).
1566
+
1567
+ #### Idempotency & Duplicate Daemons
1568
+
1569
+ The idempotency basis for runtime-created work is:
1570
+
1571
+ ```text
1572
+ workspace_id + workflow_id + trigger_id + scheduled_for
1573
+ workspace_id + workflow_id + trigger_id + event_id (event-driven work)
1574
+ ```
1575
+
1576
+ Two daemon ticks evaluating the same trigger for the same scheduled instant MUST
1577
+ produce the same task idempotency key. Replaying the same envelope MUST NOT create a
1578
+ second task. This rule is what lets an SSSS host run multiple scheduler processes
1579
+ without a scheduler database becoming the source of truth.
1580
+
1581
+ For `event`, `webhook`, and `file_change` triggers, `scheduled_for` SHOULD be the
1582
+ canonical event timestamp or the host's normalized receipt timestamp, and the task
1583
+ SHOULD also record `trigger_event_id` when one exists.
1584
+
1585
+ #### Concurrency, Misfires & Retries
1586
+
1587
+ `misfire_policy` determines what happens when a daemon wakes after one or more missed
1588
+ schedule instants:
1589
+
1590
+ | Policy | Meaning |
1591
+ |--------|---------|
1592
+ | `skip` | Do not create work for missed instants. |
1593
+ | `run_once` | Create one task for the most recent missed instant. |
1594
+ | `catch_up` | Create one task per missed instant, each with its own idempotency key. |
1595
+
1596
+ `concurrency` determines what happens when a trigger fires while earlier work from
1597
+ the same workflow/trigger is still active:
1598
+
1599
+ | Policy | Meaning |
1600
+ |--------|---------|
1601
+ | `allow_parallel` | Create the new task regardless of active runs. |
1602
+ | `skip_if_running` | Do not create a new task while a prior run is active. |
1603
+ | `enqueue` | Create a pending task, but allow a worker to claim it only after prior work finishes. |
1604
+ | `replace` | Cancel or fail the previous task/run before creating the replacement. |
1605
+
1606
+ Retries MUST be represented on the `task` and/or `run` (`attempts`,
1607
+ `next_attempt_at`, `status: retrying`) and by events. A dead-letter outcome SHOULD be
1608
+ represented as `status: failed` on the task and `status: dead_letter` on the final
1609
+ run, plus an event explaining the terminal failure.
1610
+
1611
+ #### Runtime Helpers
1612
+
1613
+ The reference package exposes `@gregiteen/ssss-cli/runtime`, including deterministic helpers
1614
+ for planning a workflow trigger into a `workflow_triggered` event envelope and a
1615
+ task `operation` envelope. Hosts MAY implement their own daemon, but SHOULD pass the
1616
+ runtime conformance checks to prove the same source-of-truth and idempotency rules.
1617
+
1618
+ ### 11.9 Multilingual Semantic Runtime Contract
1619
+
1620
+ The semantic layer is a **derived projection** over validated vault documents. It
1621
+ MUST be deterministic for the same vault bytes, registry set, adapter identity, and projection
1622
+ options. It MUST NOT become a second source of truth.
1623
+
1624
+ Each projected record SHOULD expose a stable identity, source path and content hash,
1625
+ primitive type, portability class, surface text, normalized search tokens, and graph
1626
+ edges. Identity is resolved from `semantic_id`, then `resource`, then the source path.
1627
+ Edges are derived from explicit `relations`, wiki links, and Markdown links. Hosts MAY
1628
+ add embeddings or richer ranking, but the exact lexical/graph projection MUST remain
1629
+ available as a dependency-free interoperability baseline.
1630
+
1631
+ The safe default projection contains only `structural` documents. It MUST exclude
1632
+ `tenant_private` and `resource_bound` documents unless the caller explicitly enables
1633
+ private indexing in an authorized context. Language selection MUST NOT widen scope or
1634
+ implicitly disclose conversations, runs, tasks, credentials, customer data, or bound
1635
+ resource values.
1636
+
1637
+ A host MAY inject a multilingual embedding adapter. Every enriched record MUST carry
1638
+ the embedding model identity and vector dimension. Search SHOULD report lexical and
1639
+ semantic evidence separately before computing a hybrid score.
1640
+
1641
+ A host MAY inject an LLM render adapter at presentation time. The render request MUST
1642
+ carry an invariant-control block. Rendering MAY change natural-language title,
1643
+ description, body, formatting, dates, and units, but MUST NOT change primitive IDs,
1644
+ field IDs, enum codes, actions, permissions, paths, versions, hashes, or relations.
1645
+ Canonical documents are authored once in any language; SSSS 0.9 neither requires nor
1646
+ materializes translation documents or localized vault trees.
1647
+
1648
+ ---
1649
+
1650
+ ## 12. Conformance
1651
+
1652
+ Conformance is defined by a shared set of **fixtures** — canonical
1653
+ request/response pairs for the Operation Contract. A host is conformant if, for
1654
+ every fixture, it produces the expected response and status code.
1655
+
1656
+ Fixtures are distributed as a JSON document carrying:
1657
+
1658
+ - `operation_types` — the envelope-type schemas.
1659
+ - `idempotency` — TTL and replay behavior.
1660
+ - `validation_rules` — envelope and content rules.
1661
+ - `runtime_contract` — trigger vocabulary and daemon idempotency rules (§11.8).
1662
+ - registry-extension checks — schema shape, regex validity, symlink rejection, and
1663
+ core/sibling collision rejection.
1664
+ - multilingual semantic checks — deterministic indexing, privacy defaults, graph
1665
+ edges, embedding provenance, cross-language retrieval, and invariant rendering
1666
+ (§11.9).
1667
+ - `fixtures[]` — each with a `request`, an `expected_response`, and an
1668
+ OPTIONAL `expected_http_status`.
1669
+ - `error_codes` — the canonical code table.
1670
+
1671
+ The conformance fixture set is the shared test contract between all SSSS
1672
+ implementations. A host MUST NOT claim SSSS conformance without passing the current
1673
+ fixture set, including each fixture's `expected_http_status` if it speaks HTTP
1674
+ (§6.5). Beyond the fixtures:
1675
+
1676
+ - Hosts implementing workflow daemons SHOULD run the runtime checks exposed by
1677
+ `@gregiteen/ssss-cli/runtime` (§11.8).
1678
+ - Hosts exposing semantic search or runtime rendering MUST pass the §11.9 checks.
1679
+ - Hosts supplying their own adapters (§6.7) MUST pass the shared adapter
1680
+ contracts: VFS, event store, idempotency store, and lease store, including
1681
+ their multi-process races.
1682
+ - Kernel implementations MUST pass the resource-lifecycle, error-code,
1683
+ append-only, capability, and frontmatter-subset checks.
1684
+
1685
+ The reference suite also checks **this document**: every example document in it
1686
+ must validate, §5.1 must list every core primitive with its registry portability,
1687
+ and the §6.5 table must match the reference error codes. A spec edit that breaks
1688
+ an example fails the build, just like a code change would.
1689
+
1690
+ ---
1691
+
1692
+ ## 13. Naming Conventions
1693
+
1694
+ | Thing | Convention | Example |
1695
+ |-------|-----------|---------|
1696
+ | Memory / task slug | `kebab-case`, unique, matches filename | `prefer-atomic-writes` |
1697
+ | Memory category | lowercase, matches directory | `patterns` |
1698
+ | Skill name | `kebab-case`, matches directory | `deploy` |
1699
+ | Canonical filename | `UPPERCASE.md` | `ASSISTANT.md` |
1700
+ | VFS path | relative, no leading `/`, `/`-separated | `assistants/bot/ASSISTANT.md` |
1701
+ | Conflict ID | `conflict-YYYY-MM-DD-NNN` | `conflict-2026-05-16-001` |
1702
+ | Idempotency key | Opaque string; random UUID for ad-hoc requests, deterministic derivation for runtime work (§6.4, §11.8) | `runtime-run-3f9a…` |
1703
+ | Timestamp | ISO 8601, `Z` suffix (UTC) | `2026-05-16T14:03:00Z` |
1704
+
1705
+ Slugs and names MAY contain non-ASCII Unicode letters so that non-Latin scripts are
1706
+ first-class; they remain lowercase and hyphen-separated. A host MAY instead use an
1707
+ opaque ID as the slug and keep the human-readable label in `title` / `name`.
1708
+
1709
+ ---
1710
+
1711
+ ## 14. Spec Versioning
1712
+
1713
+ This document is versioned independently of any host and of the conformance
1714
+ fixture set.
1715
+
1716
+ - The spec version is stated in the document header (currently **v0.9**).
1717
+ - Breaking changes to the file format, the type registry, or the Operation
1718
+ Contract increment the spec version.
1719
+ - Until **v1.0**, any version MAY introduce breaking changes.
1720
+ - A host SHOULD declare which spec version it targets.
1721
+
1722
+ ---
1723
+
1724
+ ## 15. Schema Evolution
1725
+
1726
+ SSSS is **self-describing and self-mutable**. The type registry (§5), the field
1727
+ schemas, and the contract rules are themselves SSSS-governed data — not a frozen
1728
+ external artifact. The protocol can evolve. But evolution is **governed**, never
1729
+ ad-hoc, so the deterministic layer (§11.1) stays exact at every moment.
1730
+
1731
+ ### 15.1 Plain-Language Proposals
1732
+
1733
+ A change to SSSS is proposed in **plain natural language**, in any language — e.g.
1734
+ *"add an optional `priority` field to the task primitive."* A proposal is an ordinary
1735
+ SSSS work item (a `task`); authoring one does NOT require writing formal schema
1736
+ syntax by hand.
1737
+
1738
+ The host interprets the proposal **semantically** (§11), so a proposal written in any
1739
+ language is understood identically. The plain-language text is the *authoring
1740
+ interface* — it is not itself the schema.
1741
+
1742
+ ### 15.2 The Governed Path
1743
+
1744
+ A proposal becomes part of SSSS only through a fixed pipeline:
1745
+
1746
+ 1. **Interpret** — the plain-language proposal is resolved into a formal schema delta.
1747
+ 2. **Validate** — the delta is checked against the current spec for consistency
1748
+ (no contradiction; no existing REQUIRED field removed without a migration).
1749
+ 3. **Review** — acceptance is gated by human/admin approval and/or eval gates.
1750
+ 4. **Version** — on acceptance the spec version (§14) is incremented.
1751
+ 5. **Migrate** — a migration is recorded so existing vault data conforms to the new
1752
+ version.
1753
+
1754
+ ### 15.3 Mutability Without Fuzziness
1755
+
1756
+ At any instant the *active* schema is a single, fixed, exact, versioned artifact —
1757
+ validation never becomes fuzzy. Mutability happens **between** versions, through the
1758
+ gate of §15.2. SSSS is therefore a *sequence of exact schemas*, not a fluid one. The
1759
+ plain-language interface lowers the authoring barrier; the governed path preserves
1760
+ the determinism the contract layer depends on.
1761
+
1762
+ ---
1763
+
1764
+ ## 16. The `.ucw` Bundle Format
1765
+
1766
+ A **bundle** is a single transportable file that packages a portion of a vault — its
1767
+ files plus a manifest describing what they are and what they need to run. A bundle is
1768
+ how an SSSS business or template is **backed up, shared, sold, and re-provisioned**. The
1769
+ canonical container is `package.ucw.json` (a "universal containerized workspace"); a host
1770
+ MAY additionally wrap it in a `.ucw` archive (the JSON plus any binary branding assets),
1771
+ but the JSON document is the normative artifact and is self-contained.
1772
+
1773
+ A bundle is produced by an **export** (§17) under one of the export profiles of §5.5
1774
+ (`backup | template | sale`). The profile a bundle was built under is recorded in its
1775
+ manifest and governs which portability classes (§5.5) its files may contain. A conformant
1776
+ exporter MUST NOT emit a `tenant_private` file into a `template` or `sale` bundle.
1777
+
1778
+ ### 16.1 Structure
1779
+
1780
+ A bundle is a JSON object with three top-level members:
1781
+
1782
+ ```jsonc
1783
+ {
1784
+ "manifest": { /* §16.2 — what this bundle is and needs */ },
1785
+ "branding": { /* OPTIONAL — binary assets, base64 (logo, favicon, colors, fonts) */ },
1786
+ "files": [ /* §16.4 — the SSSS files, in deterministic path order */ ]
1787
+ }
1788
+ ```
1789
+
1790
+ `files` MUST be sorted by `path` (§16.3 order) so that two exports of the same vault state
1791
+ are identical and content-hashable (§16.3, `provenance.content_hash`).
1792
+
1793
+ ### 16.2 The Manifest
1794
+
1795
+ The manifest is the bundle's contract. It declares the bundle's identity, the SSSS version
1796
+ and extensions a host needs to consume it, the export profile, an inventory of what is
1797
+ inside, the resources it must bind at provision time, and provenance.
1798
+
1799
+ | Field | Required | Meaning |
1800
+ |-------|----------|---------|
1801
+ | `name` | yes | Human name of the bundle. |
1802
+ | `description` | yes | One-line summary. |
1803
+ | `version` | yes | The bundle's own semver, independent of the spec. |
1804
+ | `exported_at` | yes | ISO-8601 timestamp of export. |
1805
+ | `ssss_core_version` | yes | The `registry/core.json` `spec_version` the bundle targets (e.g. `"0.9"`). A host MUST refuse a bundle whose core version it does not support. |
1806
+ | `required_extensions` | yes | Array of extension registry ids the files rely on (e.g. `["acme"]`). Empty array if the bundle uses only core primitives. A host MUST refuse a bundle naming an extension it has not loaded. |
1807
+ | `export_profile` | yes | `backup` \| `template` \| `sale` — the §5.5 profile this bundle was built under. Determines the allowed portability classes. |
1808
+ | `primitive_inventory` | yes | Map of primitive `type` → count, over every file in the bundle (replaces the legacy hard-coded `categories`; it is registry-driven, so extension types appear automatically). |
1809
+ | `provisioning` | yes | Array of provisioning steps (§17.2) — the ordered, declarative plan for binding this bundle into a live workspace. Empty for a pure `backup` that is restored in place. |
1810
+ | `parameters` | no | Array of parameter definitions (§16.5) the importer must resolve (e.g. business name, domain). |
1811
+ | `source_workspace_id` | no | Origin workspace; OMITTED or nulled in `template`/`sale` profiles (it is operator-identifying). |
1812
+ | `dependencies` | no | `{ primitives, extensions, migrations, integrity }`: the sorted primitive types and extension ids the files use, the `migration` ids they carry, and `integrity: { content_hash, ssss_core_version }`. If present, `integrity.content_hash` MUST equal `provenance.content_hash`. |
1813
+ | `file_count` | yes | Length of `files`; a cheap integrity check. |
1814
+ | `provenance` | yes | `{ content_hash, exporter, signature? }` (§16.3). |
1815
+
1816
+ `primitive_inventory` supersedes the legacy fixed `categories` object and `provisioning`
1817
+ supersedes its `capabilities` booleans: both are now open and registry-driven rather than a
1818
+ closed enum, so a bundle full of extension primitives inventories and provisions them
1819
+ without a spec change.
1820
+
1821
+ ### 16.3 Provenance & Integrity
1822
+
1823
+ `provenance` makes a bundle verifiable and attributable:
1824
+
1825
+ - `content_hash` — `sha256:` followed by the lowercase hex SHA-256 of the UTF-8 bytes of
1826
+ the **canonical file serialization**, defined as:
1827
+ 1. Take each file as `{ "path": …, "content": … }`, in that key order, dropping any
1828
+ other member (such as a cached `frontmatter`).
1829
+ 2. Sort by `path`, comparing strings by UTF-16 code units. This equals byte order
1830
+ for ASCII paths.
1831
+ 3. Serialize the array as JSON with no insignificant whitespace, escaping strings
1832
+ exactly as ECMAScript `JSON.stringify` does: `"`, `\`, and control characters
1833
+ are escaped, and all other characters, including non-ASCII, are emitted
1834
+ literally.
1835
+
1836
+ An importer MUST recompute it and reject a bundle whose files do not match. This is
1837
+ what makes a bundle tamper-evident and what a marketplace lists against.
1838
+ - `exporter` — an identifier for the tool/host that produced the bundle (`"@gregiteen/ssss-cli@0.9.3"`).
1839
+ - `signature` — OPTIONAL detached signature over `content_hash` for a sold bundle, so a
1840
+ buyer can verify authorship. Unsigned bundles are valid; signing is a marketplace concern.
1841
+
1842
+ ### 16.4 Files
1843
+
1844
+ Each entry of `files` is `{ path, content }`, where `content` is the full SSSS file text
1845
+ (frontmatter + body, §4). A host MAY also carry a parsed `frontmatter` object for
1846
+ convenience, but `content` is normative — on import the host re-parses `content`, so a
1847
+ divergent cached `frontmatter` is ignored. Every file's resolved portability class (§5.5,
1848
+ honoring `x_portability`) MUST be permitted by `export_profile`.
1849
+
1850
+ ### 16.5 Parameters
1851
+
1852
+ `parameters` are the values an importer must supply to turn a template into a running
1853
+ instance — the difference between "a festival in a box" and "*this* festival." The schema is
1854
+ adopted verbatim from the legacy `WorkspaceTemplateVariableDefinition`:
1855
+
1856
+ | Field | Meaning |
1857
+ |-------|---------|
1858
+ | `key` | Stable identifier, referenced by provisioning steps and link rewriting. |
1859
+ | `label` | Human prompt. |
1860
+ | `type` | Value type (`string`, `boolean`, `surfaces`, …). |
1861
+ | `scope` | Where the value applies (`workspace`, `automation`, `data`, …). |
1862
+ | `source` | Who supplies it: `user` \| `llm` \| `graph` \| `system`. |
1863
+ | `required` | Whether provisioning may proceed without it. |
1864
+ | `defaultValue`, `options`, `dependsOn` | Optional default, enumerated choices, and dependency keys. |
1865
+
1866
+ A `sale`/`template` bundle declares its `resource_bound` requirements (§5.5) as `parameters`
1867
+ of `source: user` or `source: system` — e.g. the phone number, domain, and mailbox a buyer
1868
+ must bind. This is how the standard guarantees a sold business says exactly what real-world
1869
+ resources it needs without shipping the seller's own.
1870
+
1871
+ ---
1872
+
1873
+ ## 17. The Provisioning Contract
1874
+
1875
+ Export, provision, and import are the three verbs that move a bundle (§16) between vaults.
1876
+ They are specified to be **deterministic** and **idempotent** so that selling, cloning, and
1877
+ restoring an SSSS business are reliable operations rather than bespoke migrations.
1878
+
1879
+ ### 17.1 The Three Verbs
1880
+
1881
+ - **export(vault, profile) → bundle** — Walk the vault, filter by the §5.5 portability rules
1882
+ for `profile`, sort files by path, compute `provenance.content_hash`, and emit a §16
1883
+ bundle. Export is **pure**: the same vault state and profile yield a byte-identical bundle.
1884
+ - **provision(bundle, parameters, target) → plan** — Resolve `parameters` (§16.5), bind the
1885
+ bundle's `resource_bound` requirements to real resources in `target`, and produce an
1886
+ ordered, replayable plan of Operation Contract envelopes (§6) plus resource bindings. A
1887
+ `dry_run` provision (mirroring §6 `dry_run`) validates and plans without committing.
1888
+ - **import(plan, target)** — Replay the plan's envelopes through the target's engine (§6.3).
1889
+ Because each envelope carries an `idempotency_key`, a re-run is a safe no-op: import is
1890
+ idempotent.
1891
+
1892
+ ### 17.2 Provisioning Steps & Binding Vocabulary
1893
+
1894
+ A manifest's `provisioning` array is an ordered list of steps. The step schema and its
1895
+ controlled vocabularies are adopted from the legacy `WorkspaceProvisioningStep` and
1896
+ `WorkspaceGraphEdge`:
1897
+
1898
+ A **step** is `{ id, label, system, mode, required, notes? }`:
1899
+
1900
+ - `system` — the subsystem the step acts on: `workspace | branding | email | phone |
1901
+ domains | accounts | deployments | marketplace | tabs | automation`.
1902
+ - `mode` — the canonical **binding verb**: `existing` (bind to a resource the target
1903
+ already has), `provision` (allocate a new real resource — a domain, a phone number),
1904
+ `install` (add a dependency bundle), `generate` (synthesize content), `configure` (set
1905
+ values). `mode` is how a bundle distinguishes "needs a *new* phone number" from "route to
1906
+ the operator's existing line."
1907
+
1908
+ Dependency and resource relationships between primitives are expressed with the canonical
1909
+ **edge relations**: `uses_brand | owns_domain | routes_calls_to | deploys_to | has_surface
1910
+ | contains_page | installs_pack | authenticates_account | runs_workflow`. The
1911
+ `resource_bound` primitives of §5.5 each declare which relation binds them (for example,
1912
+ an extension's `domain` → `owns_domain`, `phone_number` → `routes_calls_to`, and
1913
+ `integration_connection` → `connects_to`), so an importer knows exactly what real-world
1914
+ binding each requires.
1915
+
1916
+ ### 17.3 Determinism, Id-Remap & Link Integrity
1917
+
1918
+ When a bundle is provisioned into a target vault, identifiers (slugs, workspace ids,
1919
+ cross-file links) are **remapped** so the imported business is a fresh, self-consistent
1920
+ instance rather than a clone aliasing the seller's ids. Remapping MUST preserve link
1921
+ integrity: every internal `[[link]]` / relative reference that resolved in the source bundle
1922
+ MUST resolve to the remapped target after import. This is the same rewrite engine the
1923
+ semantic layer's autolink (§11) uses, run with a bundle-relative id map. An importer that
1924
+ cannot resolve a link MUST fail the provision rather than emit a dangling reference.
1925
+
1926
+ ### 17.4 Composition & Upgrade
1927
+
1928
+ - **Composition** — a bundle MAY depend on other bundles. A dependency carries an
1929
+ `installMode` of `optional | recommended | required` (adopted from the legacy
1930
+ `WorkspaceMarketplaceRecommendation`). `provision` installs `required` dependencies before
1931
+ the bundle itself; `optional`/`recommended` are surfaced to the operator.
1932
+ - **Upgrade** — moving an installed bundle from one version to the next is performed
1933
+ through a `migration` primitive (§5.4) plus **structural-only** `patch` envelopes (§6.2). An upgrade MUST NOT touch `tenant_private` data: it rewrites the
1934
+ structural model, never the operator's private records. This is what lets a sold business
1935
+ receive standard updates without the vendor reaching into customer data.
1936
+
1937
+ ---
1938
+
1939
+ ## Appendix A — Reserved Frontmatter Keys
1940
+
1941
+ The following frontmatter keys are reserved by this spec across all primitives and
1942
+ MUST NOT be repurposed by hosts:
1943
+
1944
+ - Universal (§4.2): `type`, `title`, `description`, `timestamp`.
1945
+ - Semantic (§4.2, §11): `semantic_id`, `relations`, `language`, `resource`, `tags`,
1946
+ `aliases`, `feedback`, `confidence`.
1947
+ - Lifecycle: `slug`, `schema_version`, `status`.
1948
+ - Portability (§5.5): `x_portability`.
1949
+
1950
+ The patch key `__body__` (§6.2) is reserved and can never be a frontmatter key.
1951
+
1952
+ Hosts adding their own frontmatter fields SHOULD prefix them `x_` to remain
1953
+ forward-compatible with future spec revisions.
1954
+
1955
+ ---
1956
+
1957
+ *SSSS is a portable standard. This specification is the ground truth; every SSSS
1958
+ implementation is a conformant consumer of it. To learn how a specific product
1959
+ implements SSSS, read that product's `SKILL.md`, not this file.*