total-recall-brain 3.9.0 → 3.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/antigravity.mjs +62 -183
- package/package.json +6 -5
- package/scaffold/.agent/skills/total-recall/SKILL.md +1 -0
- package/scaffold/.agent/skills/total-recall/skills/{cli-agents → tr-cli-agents}/SKILL.md +3 -2
- package/scaffold/.agent/skills/total-recall/skills/{research → tr-research}/SKILL.md +2 -1
- package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/SKILL.md +3 -2
- package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/evals/evals.json +3 -3
- package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/hooks/on-skill-add.sh +1 -1
- package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/hooks/on-skill-delete.sh +1 -1
- package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/scripts/create-skill.sh +3 -3
- package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/scripts/find-skills.mjs +25 -1
- package/scaffold/.agent/skills/total-recall/skills/tr-skill/scripts/install-skill.mjs +117 -0
- package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/scripts/scan-skill.mjs +20 -0
- package/scaffold/.agent/skills/total-recall/skills/{ssss → tr-ssss}/SKILL.md +120 -19
- package/scaffold/.agent/skills/total-recall/skills/tr-ssss/references/CHANGELOG.md +124 -0
- package/scaffold/.agent/skills/total-recall/skills/{ssss → tr-ssss}/references/ssss-spec.md +474 -43
- package/src/cli/connect.mjs +6 -59
- package/src/cli/ingest-openwiki.mjs +122 -0
- package/src/cli/ingest.mjs +9 -0
- package/src/cli/init.mjs +42 -2
- package/src/cli/skill-projection.mjs +214 -0
- package/src/cli/skill.mjs +44 -18
- package/src/core/daemon-loop.mjs +13 -2
- package/src/core/operation-validator.mjs +85 -9
- package/src/core/research.mjs +47 -9
- package/src/core/runtime.mjs +14 -7
- package/src/core/schema.mjs +85 -13
- package/src/server/api.mjs +2 -2
- package/src/server/rest.mjs +3 -3
- package/src/server/routes/skills.mjs +25 -4
- package/scaffold/.agent/skills/total-recall/skills/ssss/references/CHANGELOG.md +0 -9
- /package/scaffold/.agent/skills/total-recall/skills/{cli-agents → tr-cli-agents}/agents.yml +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{cli-agents → tr-cli-agents}/evals/.gitkeep +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{cli-agents → tr-cli-agents}/references/antigravity.txt +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{cli-agents → tr-cli-agents}/references/claude.txt +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{cli-agents → tr-cli-agents}/references/codex.txt +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{cli-agents → tr-cli-agents}/references/gemini.txt +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{cli-agents → tr-cli-agents}/scripts/.gitkeep +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{cli-agents → tr-cli-agents}/subagents/.gitkeep +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/assets/skill-template/SKILL.md +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/learnings/.gitkeep +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/references/.gitkeep +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/scripts/.gitkeep +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/scripts/enforce-skill-optimization.mjs +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/scripts/skill-watcher.mjs +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/subagents/audit-all-skills.md +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{ssss → tr-ssss}/evals/evals.json +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{ssss → tr-ssss}/scripts/validate-schema.mjs +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{ssss → tr-ssss}/subagents/audit-ssss-node.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# SSSS — Structured Semantic Syntax System
|
|
2
2
|
|
|
3
|
-
**Specification v0.
|
|
3
|
+
**Specification v0.6 — Draft**
|
|
4
4
|
|
|
5
5
|
> This is the canonical, vendor-neutral specification for SSSS. It is the ground
|
|
6
6
|
> truth on which all SSSS implementations are built. It is intended to be vendored
|
|
@@ -22,19 +22,19 @@ SSSS — the Structured Semantic Syntax System — is a **database-free, Markdow
|
|
|
22
22
|
schema and mutation contract for AI agent state**.
|
|
23
23
|
|
|
24
24
|
Every unit of agent-relevant state — a memory, a skill, a conversation, a workflow
|
|
25
|
-
run, an assistant definition — is a plain Markdown file with YAML
|
|
26
|
-
is no relational database of record, no binary format, and no
|
|
27
|
-
A relational store MAY exist, but only as a *disposable
|
|
28
|
-
the Markdown.
|
|
25
|
+
run, an assistant definition, a runtime task — is a plain Markdown file with YAML
|
|
26
|
+
frontmatter. There is no relational database of record, no binary format, and no
|
|
27
|
+
proprietary container. A relational store MAY exist, but only as a *disposable
|
|
28
|
+
projection* rebuildable from the Markdown.
|
|
29
29
|
|
|
30
30
|
SSSS additionally defines the **Operation Contract**: a single, validated, idempotent
|
|
31
31
|
envelope through which all agent-generated mutations must flow. This makes
|
|
32
32
|
AI-generated state changes deterministic, replayable, conflict-safe, and auditable.
|
|
33
33
|
|
|
34
|
-
Any tool, IDE, agent framework, or CLI that can read Markdown can
|
|
35
|
-
an SSSS vault. The only thing that distinguishes a memory engine,
|
|
36
|
-
a workflow orchestrator is *which primitive types they read and
|
|
37
|
-
underlying file format and mutation contract are identical.
|
|
34
|
+
Any tool, IDE, agent framework, daemon, or CLI that can read Markdown can
|
|
35
|
+
interoperate with an SSSS vault. The only thing that distinguishes a memory engine,
|
|
36
|
+
a chat runtime, and a workflow orchestrator is *which primitive types they read and
|
|
37
|
+
write* — the underlying file format and mutation contract are identical.
|
|
38
38
|
|
|
39
39
|
---
|
|
40
40
|
|
|
@@ -112,13 +112,30 @@ Every SSSS document primitive MUST include:
|
|
|
112
112
|
| Field | Type | Description |
|
|
113
113
|
|-------|------|-------------|
|
|
114
114
|
| `type` | string | The primitive type. MUST match an entry in the Type Registry (§5). |
|
|
115
|
+
| `title` | string | Human-readable title of the document. |
|
|
116
|
+
| `description` | string | One-sentence summary of the document's purpose. |
|
|
117
|
+
| `timestamp` | string | ISO 8601 timestamp of last modification. |
|
|
118
|
+
|
|
119
|
+
For OKF-compatible discovery, SSSS document primitives SHOULD also include:
|
|
120
|
+
|
|
121
|
+
| Field | Type | Description |
|
|
122
|
+
|-------|------|-------------|
|
|
123
|
+
| `resource` | string | Canonical URI for the underlying asset, when the primitive describes one. |
|
|
124
|
+
| `tags` | array | Array of string tags for categorization and routing. |
|
|
125
|
+
| `aliases` | array | Array of alternative names for this concept, used for wiki autolinking. |
|
|
115
126
|
|
|
116
127
|
Every primitive type defines its own additional REQUIRED and OPTIONAL fields
|
|
117
|
-
(§5.4).
|
|
118
|
-
fields are permitted only as OPTIONAL fields and SHOULD be namespaced (e.g.
|
|
119
|
-
`x_host_*`) to avoid collision with future spec fields.
|
|
128
|
+
(§5.4). To maintain forward compatibility and allow agents scratchpad space, hosts MUST NOT reject documents containing unknown frontmatter keys. Unknown fields MUST be preserved.
|
|
120
129
|
|
|
121
|
-
### 4.3
|
|
130
|
+
### 4.3 Linking & Progressive Disclosure
|
|
131
|
+
|
|
132
|
+
SSSS adopts the OKF standards for hyperlinking and directory indices:
|
|
133
|
+
|
|
134
|
+
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)`).
|
|
135
|
+
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.
|
|
136
|
+
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.
|
|
137
|
+
|
|
138
|
+
### 4.4 Canonical Filenames
|
|
122
139
|
|
|
123
140
|
Document primitives that have a fixed role in a directory use an **uppercase
|
|
124
141
|
canonical filename** that signals the primitive at a glance:
|
|
@@ -147,21 +164,26 @@ primitive — it implements the subset its product requires — but any primitiv
|
|
|
147
164
|
|
|
148
165
|
### 5.1 Document Primitives
|
|
149
166
|
|
|
150
|
-
| `type` | Family | Purpose |
|
|
151
|
-
|
|
152
|
-
| `memory` | knowledge | A single unit of agent knowledge (rule, pattern, fact, preference). |
|
|
153
|
-
| `skill` | capability | A skill package manifest. |
|
|
154
|
-
| `rule` | governance | A workspace-scoped behavior rule applied to assistants/agents. |
|
|
155
|
-
| `
|
|
156
|
-
| `
|
|
157
|
-
| `
|
|
158
|
-
| `
|
|
159
|
-
| `
|
|
160
|
-
| `
|
|
161
|
-
| `
|
|
162
|
-
| `
|
|
163
|
-
| `
|
|
164
|
-
| `
|
|
167
|
+
| `type` | Family | Portability | Purpose |
|
|
168
|
+
|--------|--------|-------------|---------|
|
|
169
|
+
| `memory` | knowledge | structural | A single unit of agent knowledge (rule, pattern, fact, preference). |
|
|
170
|
+
| `skill` | capability | structural | A skill package manifest. |
|
|
171
|
+
| `rule` | governance | structural | A workspace-scoped behavior rule applied to assistants/agents. |
|
|
172
|
+
| `security_role` | governance | structural | A security role definition for role-based access control (RBAC). |
|
|
173
|
+
| `task` | work | tenant_private | A unit of submitted work — one step or many. The universal work primitive. |
|
|
174
|
+
| `assistant` | actor | structural | The definition of an AI assistant/persona. |
|
|
175
|
+
| `workflow` | work | structural | A reusable **task template**: a defined procedure plus triggers. Firing a workflow submits a `task`. |
|
|
176
|
+
| `model` | catalog | structural | The definition of an inference model. |
|
|
177
|
+
| `conversation` | transcript | tenant_private | An append-only chat transcript. |
|
|
178
|
+
| `run` | transcript | tenant_private | An append-only workflow execution record. |
|
|
179
|
+
| `conflict` | meta | tenant_private | A record of two contradicting primitives, blocking promotion. |
|
|
180
|
+
| `page` | capability | structural | A VFS-native sandboxed custom workspace page. |
|
|
181
|
+
| `migration` | meta | structural | An SSSS schema migration state record. |
|
|
182
|
+
| `release` | meta | structural | An SSSS system schema version release record. |
|
|
183
|
+
|
|
184
|
+
The **Portability** column is the primitive's default portability class (§5.5); a host
|
|
185
|
+
resolves it from `registry/core.json`. Extension registries assign their own primitives a
|
|
186
|
+
class — notably `resource_bound` for things like domains and phone numbers.
|
|
165
187
|
|
|
166
188
|
### 5.2 Contract Primitives
|
|
167
189
|
|
|
@@ -170,6 +192,7 @@ primitive — it implements the subset its product requires — but any primitiv
|
|
|
170
192
|
| `operation` | A full atomic file write (create or full replace) — see §6. |
|
|
171
193
|
| `patch` | A partial merge into an existing file — see §6. |
|
|
172
194
|
| `event` | An append-only immutable log entry — see §6, §8. |
|
|
195
|
+
| `delete` | A tombstoning removal of a replace-type file — see §6. |
|
|
173
196
|
| `lease` | A file-level write lock — see §7. |
|
|
174
197
|
|
|
175
198
|
### 5.3 Append-Type vs. Replace-Type Documents
|
|
@@ -262,12 +285,21 @@ REQUIRED: `type`, `priority` (integer), `category`, `status`
|
|
|
262
285
|
(`pending|in_progress|done|failed`). A task instantiated from a template carries an
|
|
263
286
|
OPTIONAL `workflow_id` referencing it.
|
|
264
287
|
|
|
288
|
+
Runtime-created tasks SHOULD additionally carry `workflow_path`, `trigger_id`,
|
|
289
|
+
`trigger_type`, `trigger_event_id`, `scheduled_for`, and `dedupe_key`. These fields
|
|
290
|
+
make the task reconstructible from the workflow definition plus the trigger event
|
|
291
|
+
and prevent duplicate daemon ticks from creating duplicate work (§11.8).
|
|
292
|
+
|
|
265
293
|
```markdown
|
|
266
294
|
---
|
|
267
295
|
type: task
|
|
268
296
|
priority: 85
|
|
269
297
|
category: skill-engineering
|
|
270
298
|
status: pending
|
|
299
|
+
workflow_id: "research-skill"
|
|
300
|
+
trigger_id: "manual"
|
|
301
|
+
scheduled_for: 2026-05-16T08:00:00Z
|
|
302
|
+
dedupe_key: "runtime:abc123"
|
|
271
303
|
---
|
|
272
304
|
|
|
273
305
|
## Objective
|
|
@@ -303,6 +335,20 @@ the submitted instance.
|
|
|
303
335
|
REQUIRED: `type`, `name`. `triggers` (array) is OPTIONAL — a workflow with no
|
|
304
336
|
triggers is valid and may be invoked manually or by another workflow.
|
|
305
337
|
|
|
338
|
+
When present, `triggers[]` is the canonical schedule source. OS cron, hosted
|
|
339
|
+
schedulers, queues, and daemon timers are wake-up mechanisms only; they MUST NOT
|
|
340
|
+
become the record of what the workflow schedule means. A trigger entry SHOULD
|
|
341
|
+
include:
|
|
342
|
+
|
|
343
|
+
| Field | Description |
|
|
344
|
+
|-------|-------------|
|
|
345
|
+
| `type` | `manual`, `cron`, `interval`, `event`, `webhook`, `file_change`, or `condition`. |
|
|
346
|
+
| `id` / `trigger_id` | Stable trigger identity within the workflow. |
|
|
347
|
+
| `cron` / `interval` / `event_type` | Type-specific selector. |
|
|
348
|
+
| `timezone` | Required for wall-clock schedules; UTC is implied if omitted. |
|
|
349
|
+
| `misfire_policy` | `skip`, `run_once`, or `catch_up`; default `run_once`. |
|
|
350
|
+
| `concurrency` | `allow_parallel`, `skip_if_running`, `enqueue`, or `replace`; default `skip_if_running`. |
|
|
351
|
+
|
|
306
352
|
```markdown
|
|
307
353
|
---
|
|
308
354
|
type: workflow
|
|
@@ -310,7 +356,11 @@ name: "Daily Digest"
|
|
|
310
356
|
description: "Sends a daily summary email."
|
|
311
357
|
triggers:
|
|
312
358
|
- type: cron
|
|
359
|
+
id: daily-0800
|
|
313
360
|
cron: "0 8 * * *"
|
|
361
|
+
timezone: "America/Denver"
|
|
362
|
+
misfire_policy: run_once
|
|
363
|
+
concurrency: skip_if_running
|
|
314
364
|
isActive: true
|
|
315
365
|
---
|
|
316
366
|
|
|
@@ -339,6 +389,27 @@ scope: support
|
|
|
339
389
|
Outbound links are stripped from any assistant reply on a support thread.
|
|
340
390
|
```
|
|
341
391
|
|
|
392
|
+
#### `security_role`
|
|
393
|
+
|
|
394
|
+
A definition of a security role used for role-based access control (RBAC).
|
|
395
|
+
It maps a role name to a set of permissions that dictate what an agent or user
|
|
396
|
+
can do within the workspace.
|
|
397
|
+
|
|
398
|
+
REQUIRED: `type`, `name`, `permissions` (array). OPTIONAL: `description`.
|
|
399
|
+
|
|
400
|
+
```markdown
|
|
401
|
+
---
|
|
402
|
+
type: security_role
|
|
403
|
+
name: "admin"
|
|
404
|
+
description: "Administrator with full access to all workspace primitives."
|
|
405
|
+
permissions:
|
|
406
|
+
- "read:*"
|
|
407
|
+
- "write:*"
|
|
408
|
+
---
|
|
409
|
+
|
|
410
|
+
Full administrative access to the workspace.
|
|
411
|
+
```
|
|
412
|
+
|
|
342
413
|
#### `model`
|
|
343
414
|
|
|
344
415
|
The definition of an inference model.
|
|
@@ -386,14 +457,18 @@ Hi — how can I help?
|
|
|
386
457
|
An append-only workflow execution record. Append-type.
|
|
387
458
|
|
|
388
459
|
REQUIRED: `type`, `run_id`, `workflow_id`. Typical fields: `workspace_id`, `status`,
|
|
389
|
-
`step_count`, `started_at`.
|
|
460
|
+
`task_id`, `task_path`, `step_count`, `started_at`.
|
|
461
|
+
|
|
462
|
+
`status` SHOULD be one of: `queued`, `claimed`, `running`, `waiting_for_human`,
|
|
463
|
+
`succeeded`, `failed`, `canceled`, `retrying`, `dead_letter`.
|
|
390
464
|
|
|
391
465
|
```markdown
|
|
392
466
|
---
|
|
393
467
|
type: run
|
|
394
468
|
run_id: "run-001"
|
|
395
469
|
workflow_id: "daily-digest"
|
|
396
|
-
|
|
470
|
+
task_path: "tasks/daily-digest/daily-0800-20260516T080000Z.md"
|
|
471
|
+
status: queued
|
|
397
472
|
started_at: 2026-05-16T08:00:00Z
|
|
398
473
|
---
|
|
399
474
|
|
|
@@ -470,6 +545,41 @@ released_at: 2026-05-16T12:00:00Z
|
|
|
470
545
|
---
|
|
471
546
|
```
|
|
472
547
|
|
|
548
|
+
### 5.5 Portability Classification
|
|
549
|
+
|
|
550
|
+
A workspace is not one undifferentiated blob. Some of it is the **reusable business
|
|
551
|
+
model** (the workflows, assistants, pages, and rules that make the business run); some is
|
|
552
|
+
the operator's **private operational data** (customer transcripts, runtime work); and some
|
|
553
|
+
is **bound to a real external resource** (a domain, a phone number, a mailbox). Selling,
|
|
554
|
+
templating, and backing up a workspace each need a different slice. SSSS makes that slice
|
|
555
|
+
declarable instead of ad-hoc.
|
|
556
|
+
|
|
557
|
+
Every **document** primitive declares one **portability class** in its registry entry.
|
|
558
|
+
(Contract primitives — `operation`/`patch`/`event`/`lease` — are protocol envelopes, not
|
|
559
|
+
stored documents, and have no portability class.)
|
|
560
|
+
|
|
561
|
+
| Class | Meaning | May appear in template/sale? |
|
|
562
|
+
|-------|---------|------------------------------|
|
|
563
|
+
| `structural` | The reusable business model — carries no operator- or customer-specific data. | ✅ verbatim |
|
|
564
|
+
| `tenant_private` | The operator's private operational data (customers, transcripts, runtime work). | ❌ never — backup only, encrypted at rest |
|
|
565
|
+
| `resource_bound` | Requires a real external resource bound at provision time. | ⚠️ as a **requirement declaration** only — the seller's resource value is stripped |
|
|
566
|
+
|
|
567
|
+
A file MAY override its type's default with an `x_portability` frontmatter field. A host
|
|
568
|
+
MUST honor the **most restrictive** of (type default, instance override) — a file may make
|
|
569
|
+
itself more private than its type, never less.
|
|
570
|
+
|
|
571
|
+
An **export profile** is simply a filter over portability classes:
|
|
572
|
+
|
|
573
|
+
- **`backup`** — all three classes. `tenant_private` MUST be encrypted at rest.
|
|
574
|
+
- **`template`** / **`sale`** — `structural` verbatim; `resource_bound` reduced to a
|
|
575
|
+
requirement declaration (seller's bound value stripped); `tenant_private` **dropped
|
|
576
|
+
entirely**.
|
|
577
|
+
|
|
578
|
+
A host MUST reject a `template`/`sale` export that would emit a `tenant_private` primitive.
|
|
579
|
+
This single rule is what lets an operator sell a proven business model without ever
|
|
580
|
+
shipping a customer's data — the data is `tenant_private` by classification, so it
|
|
581
|
+
physically cannot enter a sale bundle.
|
|
582
|
+
|
|
473
583
|
---
|
|
474
584
|
|
|
475
585
|
## 6. The Operation Contract
|
|
@@ -483,7 +593,7 @@ An operation is a JSON envelope:
|
|
|
483
593
|
|
|
484
594
|
```jsonc
|
|
485
595
|
{
|
|
486
|
-
"type": "operation", // "operation" | "patch" | "event"
|
|
596
|
+
"type": "operation", // "operation" | "patch" | "event" | "delete"
|
|
487
597
|
"idempotency_key": "uuid-v4", // see §6.4
|
|
488
598
|
"path": "assistants/bot/ASSISTANT.md", // relative VFS path, no leading "/"
|
|
489
599
|
"workspace_id": "uuid", // the vault/workspace scope
|
|
@@ -491,7 +601,11 @@ An operation is a JSON envelope:
|
|
|
491
601
|
"patches": { }, // partial merge (patch only)
|
|
492
602
|
"lease_id": "uuid", // OPTIONAL — see §7
|
|
493
603
|
"intent": "human description", // OPTIONAL — audit annotation
|
|
494
|
-
"dry_run": false
|
|
604
|
+
"dry_run": false, // OPTIONAL — validate without committing
|
|
605
|
+
"actor": { // OPTIONAL — the cryptographically verified identity.
|
|
606
|
+
"type": "human", // "human" | "ai" | "system"
|
|
607
|
+
"role": "admin" // role-based access control hook for the host
|
|
608
|
+
}
|
|
495
609
|
}
|
|
496
610
|
```
|
|
497
611
|
|
|
@@ -502,29 +616,58 @@ An operation is a JSON envelope:
|
|
|
502
616
|
| `operation` | Full atomic write — creates or fully replaces a file. | `content` | `type`, `idempotency_key`, `path`, `workspace_id`, `content` |
|
|
503
617
|
| `patch` | Partial merge into an existing file's frontmatter and/or body. | `patches` | `type`, `idempotency_key`, `path`, `workspace_id`, `patches` |
|
|
504
618
|
| `event` | Append-only immutable log entry. Never overwrites. | `content` | `type`, `idempotency_key`, `path`, `workspace_id`, `content` |
|
|
619
|
+
| `delete` | Removes a replace-type file from the vault. | — | `type`, `idempotency_key`, `path`, `workspace_id` |
|
|
505
620
|
|
|
506
621
|
For `patch`, the `patches` object merges into frontmatter keys; the reserved key
|
|
507
622
|
`__body__` replaces or (for append-type documents) appends the Markdown body. For
|
|
508
623
|
`event`, `content` MUST be a valid JSON string carrying the event payload.
|
|
509
624
|
|
|
625
|
+
For `delete`, the host removes the file at `path` and appends a deletion event to the log
|
|
626
|
+
(§8) — the removal is itself an auditable, append-only record, so history is never lost. A
|
|
627
|
+
host MUST reject a `delete` targeting an **append-type** document (`conversation`, `run`)
|
|
628
|
+
or a non-existent path. A `delete` of an already-deleted path is an idempotent no-op that
|
|
629
|
+
returns the original result (§6.4). `delete` is the only contract type that removes vault
|
|
630
|
+
state; export and provision (§16) never delete — only a live workspace edit or a migration
|
|
631
|
+
(§5.4 `migration`) does.
|
|
632
|
+
|
|
510
633
|
### 6.3 The Processing Pipeline
|
|
511
634
|
|
|
512
635
|
A host MUST process every operation through these ordered stages. Any stage's
|
|
513
636
|
failure aborts the operation with no commit.
|
|
514
637
|
|
|
515
|
-
1. **Envelope validation** — `type` is one of the
|
|
516
|
-
envelope fields present and
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
638
|
+
1. **Envelope validation** — `type` is one of the four envelope types
|
|
639
|
+
(`operation`/`patch`/`event`/`delete`); required envelope fields present and
|
|
640
|
+
well-formed.
|
|
641
|
+
2. **Idempotency check** — if this `idempotency_key` + `workspace_id` +
|
|
642
|
+
request hash was already committed within the TTL, return the original result
|
|
643
|
+
as a replay (§6.4). If the key and workspace match but the request hash
|
|
644
|
+
differs, reject the request with `idempotency_conflict`. Stop.
|
|
645
|
+
3. **Authorization & Actor Identity** — the agent has write access to `workspace_id`.
|
|
646
|
+
*Security Mandate*: If a host exposes the Operation Contract directly to untrusted clients (e.g., a `POST /api/ssss` REST endpoint), the host **MUST** irreversibly overwrite the `actor` payload with the user's cryptographically verified session identity. Hosts MUST use this `actor` field to enforce Role-Based Access Control (RBAC) over sensitive or `resource_bound` primitives.
|
|
520
647
|
4. **Lease check** — if the target path is leased, the operation MUST carry a
|
|
521
648
|
matching, unexpired `lease_id` (§7).
|
|
522
649
|
5. **Content validation** — for `operation`/`patch`, the resulting file is validated
|
|
523
|
-
against its primitive schema (§9). Append-type rewrite attempts are rejected.
|
|
524
|
-
|
|
650
|
+
against its primitive schema (§9). Append-type rewrite attempts are rejected. For
|
|
651
|
+
`delete`, the host verifies the target exists and is a replace-type document (append-type
|
|
652
|
+
deletes are rejected).
|
|
653
|
+
5.5. **Granular Authorization (RBAC)** — evaluated only if stage 5 passed. Resolve
|
|
654
|
+
`actor.role` from the (by now host-verified, per stage 3) envelope. `role: "system"`
|
|
655
|
+
is an unconditional bypass (used by trusted internal callers such as the provisioning
|
|
656
|
+
pipeline, §17). `role: "admin"` is granted `write:*`/`read:*` unconditionally. Any
|
|
657
|
+
other named role's permissions are read from that role's `security_role` document
|
|
658
|
+
(canonical location `roles/<role>/ROLE.md`) and checked against the required
|
|
659
|
+
permission — `write:<type>` for `operation`/`patch`/`delete` (using the type resolved
|
|
660
|
+
in stage 5), or the fixed `write:event` for `event` envelopes (which have no resolved
|
|
661
|
+
document type). A permission list satisfies the requirement via an exact match,
|
|
662
|
+
`*:<type>`, `write:*`, or `*:*`. **A MISSING `actor.role` MUST be denied, not treated
|
|
663
|
+
as any default role** — this is the fail-closed complement to stage 3's mandate: a
|
|
664
|
+
host that forgets to overwrite `actor` gets every write rejected, not silently
|
|
665
|
+
promoted to admin.
|
|
666
|
+
6. **Commit** — the mutation is applied to the vault atomically. For `delete`, the file is
|
|
667
|
+
removed.
|
|
525
668
|
7. **Audit** — an audit entry is appended to the event log (§8).
|
|
526
669
|
|
|
527
|
-
A `dry_run` operation runs stages 1–5 and then stops: it MUST return the validation
|
|
670
|
+
A `dry_run` operation runs stages 1–5.5 and then stops: it MUST return the validation
|
|
528
671
|
verdict with `success` reflecting validity, and MUST NOT commit (`committed_at` is
|
|
529
672
|
`null`).
|
|
530
673
|
|
|
@@ -553,9 +696,11 @@ verdict with `success` reflecting validity, and MUST NOT commit (`committed_at`
|
|
|
553
696
|
|
|
554
697
|
| Code | Meaning |
|
|
555
698
|
|------|---------|
|
|
699
|
+
| `400` | Invalid request — malformed envelope, or a path that fails the traversal guard. |
|
|
556
700
|
| `401` | Authentication required. |
|
|
557
701
|
| `403` | Agent lacks write access to the workspace. |
|
|
558
|
-
| `
|
|
702
|
+
| `404` | The `patch`/`delete` target does not exist. |
|
|
703
|
+
| `409` | Lease conflict, version conflict, or idempotency conflict — path is locked, the supplied lease is invalid/expired, or the same idempotency key was reused for a different request hash. |
|
|
559
704
|
| `422` | Validation failure — see `validation.errors` and `repair`. |
|
|
560
705
|
| `500` | Internal error — the operation was not committed. |
|
|
561
706
|
|
|
@@ -640,6 +785,8 @@ A file is valid if and only if:
|
|
|
640
785
|
3. Every REQUIRED field for that primitive is present and non-empty.
|
|
641
786
|
4. For append-type documents, the operation does not rewrite existing records.
|
|
642
787
|
|
|
788
|
+
Hosts MUST NOT reject a file due to the presence of unknown or unrecognized frontmatter keys. Unrecognized keys MUST be silently preserved to support agent scratchpads and forward compatibility with OKF extensions.
|
|
789
|
+
|
|
643
790
|
On failure, the host MUST return structured **repair feedback** so an agent can
|
|
644
791
|
self-correct without guesswork:
|
|
645
792
|
|
|
@@ -783,6 +930,123 @@ a host MUST remain fully functional with feedback collection disabled, and the
|
|
|
783
930
|
semantic layer MUST degrade gracefully to its other signals (access frequency, decay,
|
|
784
931
|
embedding similarity).
|
|
785
932
|
|
|
933
|
+
### 11.7 The `language_convention` Primitive
|
|
934
|
+
|
|
935
|
+
Because the control vocabulary is symbolic and never translated (§11.1), a workspace
|
|
936
|
+
that wishes to *present* itself in a given human language does so with data, not by
|
|
937
|
+
translating keys. The `language_convention` primitive (a `structural`, extension-owned
|
|
938
|
+
type — festech ships it) records a workspace's presentation conventions: its default
|
|
939
|
+
language/locale, formality, date and currency formatting, and terminology preferences.
|
|
940
|
+
|
|
941
|
+
It is `structural` and therefore travels in `template`/`sale` bundles (§5.5): a sold
|
|
942
|
+
business carries its voice and locale conventions, but never the operator's private
|
|
943
|
+
content. A host applies a `language_convention` as a **presentation overlay** at the
|
|
944
|
+
semantic/rendering layer; it MUST NOT alter the deterministic layer's symbolic keys or
|
|
945
|
+
enumerated values.
|
|
946
|
+
|
|
947
|
+
### 11.8 Workflow Runtime & Daemon Contract
|
|
948
|
+
|
|
949
|
+
SSSS defines the source of truth for workflow runtime behavior, but it does not
|
|
950
|
+
mandate one resident process manager. A host MAY use OS cron, systemd timers,
|
|
951
|
+
serverless schedules, webhooks, message queues, browser alarms, or an always-on
|
|
952
|
+
daemon to wake the runtime. Those systems are **wake-up mechanisms** only. They MUST
|
|
953
|
+
NOT become the canonical schedule, queue, or task history.
|
|
954
|
+
|
|
955
|
+
The canonical runtime sources are:
|
|
956
|
+
|
|
957
|
+
| Concern | Source of truth |
|
|
958
|
+
|---------|-----------------|
|
|
959
|
+
| Schedule and trigger meaning | `workflow` frontmatter `triggers[]`. |
|
|
960
|
+
| Submitted work | `task` documents. |
|
|
961
|
+
| Execution transcript | append-only `run` documents. |
|
|
962
|
+
| What happened | append-only event log (§8). |
|
|
963
|
+
| Claim/concurrency safety | leases (§7) plus deterministic idempotency keys (§6.4). |
|
|
964
|
+
| Dashboards, task queues, cursors | projections (§10), rebuildable from the vault and event log. |
|
|
965
|
+
|
|
966
|
+
A conformant daemon loop is:
|
|
967
|
+
|
|
968
|
+
1. **Scan** active `workflow` primitives whose `triggers[]` might fire.
|
|
969
|
+
2. **Evaluate** the trigger against wall-clock time, incoming event, webhook, file
|
|
970
|
+
change, condition, or explicit manual invocation.
|
|
971
|
+
3. **Append** a `workflow_triggered` event via an `event` envelope.
|
|
972
|
+
4. **Instantiate** one `task` via an `operation` envelope.
|
|
973
|
+
5. **Claim** the task using a time-bound lease before execution.
|
|
974
|
+
6. **Create or append** a `run` record for execution steps.
|
|
975
|
+
7. **Patch** task status to `done` or `failed`, or to `pending` with retry metadata.
|
|
976
|
+
8. **Rebuild** derived task queues, run timelines, graph indexes, or UI projections
|
|
977
|
+
as needed.
|
|
978
|
+
|
|
979
|
+
Every step that mutates vault state MUST use the Operation Contract (§6). A daemon
|
|
980
|
+
MUST NOT write task, run, cursor, or workflow files directly.
|
|
981
|
+
|
|
982
|
+
#### Trigger Types
|
|
983
|
+
|
|
984
|
+
Core trigger types are:
|
|
985
|
+
|
|
986
|
+
| Type | Fires when |
|
|
987
|
+
|------|------------|
|
|
988
|
+
| `manual` | A human, agent, or another workflow invokes it. |
|
|
989
|
+
| `cron` | A wall-clock cron expression reaches a scheduled instant. |
|
|
990
|
+
| `interval` | A fixed duration elapses after the previous scheduled instant. |
|
|
991
|
+
| `event` | A matching event-log entry appears. |
|
|
992
|
+
| `webhook` | A verified external request arrives. |
|
|
993
|
+
| `file_change` | A matching vault path is created, patched, or deleted. |
|
|
994
|
+
| `condition` | A host-defined predicate over vault/projection state becomes true. |
|
|
995
|
+
|
|
996
|
+
Trigger entries SHOULD use the fields documented in §5.4 `workflow`. Hosts MAY add
|
|
997
|
+
type-specific `x_` fields, but MUST preserve unknown fields when rewriting the
|
|
998
|
+
workflow document (§4.2).
|
|
999
|
+
|
|
1000
|
+
#### Idempotency & Duplicate Daemons
|
|
1001
|
+
|
|
1002
|
+
The idempotency basis for runtime-created work is:
|
|
1003
|
+
|
|
1004
|
+
```text
|
|
1005
|
+
workspace_id + workflow_id + trigger_id + scheduled_for
|
|
1006
|
+
```
|
|
1007
|
+
|
|
1008
|
+
Two daemon ticks evaluating the same trigger for the same scheduled instant MUST
|
|
1009
|
+
produce the same task idempotency key. Replaying the same envelope MUST NOT create a
|
|
1010
|
+
second task. This rule is what lets an SSSS host run multiple scheduler processes
|
|
1011
|
+
without a scheduler database becoming the source of truth.
|
|
1012
|
+
|
|
1013
|
+
For `event`, `webhook`, and `file_change` triggers, `scheduled_for` SHOULD be the
|
|
1014
|
+
canonical event timestamp or the host's normalized receipt timestamp, and the task
|
|
1015
|
+
SHOULD also record `trigger_event_id` when one exists.
|
|
1016
|
+
|
|
1017
|
+
#### Concurrency, Misfires & Retries
|
|
1018
|
+
|
|
1019
|
+
`misfire_policy` determines what happens when a daemon wakes after one or more missed
|
|
1020
|
+
schedule instants:
|
|
1021
|
+
|
|
1022
|
+
| Policy | Meaning |
|
|
1023
|
+
|--------|---------|
|
|
1024
|
+
| `skip` | Do not create work for missed instants. |
|
|
1025
|
+
| `run_once` | Create one task for the most recent missed instant. |
|
|
1026
|
+
| `catch_up` | Create one task per missed instant, each with its own idempotency key. |
|
|
1027
|
+
|
|
1028
|
+
`concurrency` determines what happens when a trigger fires while earlier work from
|
|
1029
|
+
the same workflow/trigger is still active:
|
|
1030
|
+
|
|
1031
|
+
| Policy | Meaning |
|
|
1032
|
+
|--------|---------|
|
|
1033
|
+
| `allow_parallel` | Create the new task regardless of active runs. |
|
|
1034
|
+
| `skip_if_running` | Do not create a new task while a prior run is active. |
|
|
1035
|
+
| `enqueue` | Create a pending task, but allow a worker to claim it only after prior work finishes. |
|
|
1036
|
+
| `replace` | Cancel or fail the previous task/run before creating the replacement. |
|
|
1037
|
+
|
|
1038
|
+
Retries MUST be represented on the `task` and/or `run` (`attempts`,
|
|
1039
|
+
`next_attempt_at`, `status: retrying`) and by events. A dead-letter outcome SHOULD be
|
|
1040
|
+
represented as `status: failed` on the task and `status: dead_letter` on the final
|
|
1041
|
+
run, plus an event explaining the terminal failure.
|
|
1042
|
+
|
|
1043
|
+
#### Runtime Helpers
|
|
1044
|
+
|
|
1045
|
+
The reference package exposes `@ssss/cli/runtime`, including deterministic helpers
|
|
1046
|
+
for planning a workflow trigger into a `workflow_triggered` event envelope and a
|
|
1047
|
+
task `operation` envelope. Hosts MAY implement their own daemon, but SHOULD pass the
|
|
1048
|
+
runtime conformance checks to prove the same source-of-truth and idempotency rules.
|
|
1049
|
+
|
|
786
1050
|
---
|
|
787
1051
|
|
|
788
1052
|
## 12. Conformance
|
|
@@ -796,13 +1060,15 @@ Fixtures are distributed as a JSON document carrying:
|
|
|
796
1060
|
- `operation_types` — the envelope-type schemas.
|
|
797
1061
|
- `idempotency` — TTL and replay behavior.
|
|
798
1062
|
- `validation_rules` — envelope and content rules.
|
|
1063
|
+
- `runtime_contract` — trigger vocabulary and daemon idempotency rules (§11.8).
|
|
799
1064
|
- `fixtures[]` — each with a `request`, an `expected_response`, and an
|
|
800
1065
|
OPTIONAL `expected_http_status`.
|
|
801
1066
|
- `error_codes` — the canonical code table.
|
|
802
1067
|
|
|
803
1068
|
The conformance fixture set is the shared test contract between all SSSS
|
|
804
1069
|
implementations. A host MUST NOT claim SSSS conformance without passing the current
|
|
805
|
-
fixture set.
|
|
1070
|
+
fixture set. Hosts implementing workflow daemons SHOULD also run the reference
|
|
1071
|
+
runtime checks exposed by `@ssss/cli/runtime`.
|
|
806
1072
|
|
|
807
1073
|
---
|
|
808
1074
|
|
|
@@ -830,7 +1096,7 @@ opaque ID as the slug and keep the human-readable label in `title` / `name`.
|
|
|
830
1096
|
This document is versioned independently of any host and of the conformance
|
|
831
1097
|
fixture set.
|
|
832
1098
|
|
|
833
|
-
- The spec version is stated in the document header (currently **v0.
|
|
1099
|
+
- The spec version is stated in the document header (currently **v0.6 — Draft**).
|
|
834
1100
|
- Breaking changes to the file format, the type registry, or the Operation
|
|
835
1101
|
Contract increment the spec version.
|
|
836
1102
|
- Until **v1.0**, any version MAY introduce breaking changes.
|
|
@@ -878,6 +1144,171 @@ the determinism the contract layer depends on.
|
|
|
878
1144
|
|
|
879
1145
|
---
|
|
880
1146
|
|
|
1147
|
+
## 16. The `.ucw` Bundle Format
|
|
1148
|
+
|
|
1149
|
+
A **bundle** is a single transportable file that packages a portion of a vault — its
|
|
1150
|
+
files plus a manifest describing what they are and what they need to run. A bundle is
|
|
1151
|
+
how an SSSS business or template is **backed up, shared, sold, and re-provisioned**. The
|
|
1152
|
+
canonical container is `package.ucw.json` (a "universal containerized workspace"); a host
|
|
1153
|
+
MAY additionally wrap it in a `.ucw` archive (the JSON plus any binary branding assets),
|
|
1154
|
+
but the JSON document is the normative artifact and is self-contained.
|
|
1155
|
+
|
|
1156
|
+
A bundle is produced by an **export** (§17) under one of the export profiles of §5.5
|
|
1157
|
+
(`backup | template | sale`). The profile a bundle was built under is recorded in its
|
|
1158
|
+
manifest and governs which portability classes (§5.5) its files may contain. A conformant
|
|
1159
|
+
exporter MUST NOT emit a `tenant_private` file into a `template` or `sale` bundle.
|
|
1160
|
+
|
|
1161
|
+
### 16.1 Structure
|
|
1162
|
+
|
|
1163
|
+
A bundle is a JSON object with three top-level members:
|
|
1164
|
+
|
|
1165
|
+
```jsonc
|
|
1166
|
+
{
|
|
1167
|
+
"manifest": { /* §16.2 — what this bundle is and needs */ },
|
|
1168
|
+
"branding": { /* OPTIONAL — binary assets, base64 (logo, favicon, colors, fonts) */ },
|
|
1169
|
+
"files": [ /* §16.4 — the SSSS files, in deterministic path order */ ]
|
|
1170
|
+
}
|
|
1171
|
+
```
|
|
1172
|
+
|
|
1173
|
+
`files` MUST be sorted by `path` (byte order) so that two exports of the same vault state
|
|
1174
|
+
are identical and content-hashable (§16.3, `provenance.content_hash`).
|
|
1175
|
+
|
|
1176
|
+
### 16.2 The Manifest
|
|
1177
|
+
|
|
1178
|
+
The manifest is the bundle's contract. It declares the bundle's identity, the SSSS version
|
|
1179
|
+
and extensions a host needs to consume it, the export profile, an inventory of what is
|
|
1180
|
+
inside, the resources it must bind at provision time, and provenance.
|
|
1181
|
+
|
|
1182
|
+
| Field | Required | Meaning |
|
|
1183
|
+
|-------|----------|---------|
|
|
1184
|
+
| `name` | yes | Human name of the bundle. |
|
|
1185
|
+
| `description` | yes | One-line summary. |
|
|
1186
|
+
| `version` | yes | The bundle's own semver, independent of the spec. |
|
|
1187
|
+
| `exported_at` | yes | ISO-8601 timestamp of export. |
|
|
1188
|
+
| `ssss_core_version` | yes | The `registry/core.json` `spec_version` the bundle targets (e.g. `"0.3"`). A host MUST refuse a bundle whose core version it does not support. |
|
|
1189
|
+
| `required_extensions` | yes | Array of extension registry ids the files rely on (e.g. `["festech"]`). Empty array if the bundle uses only core primitives. A host MUST refuse a bundle naming an extension it has not loaded. |
|
|
1190
|
+
| `export_profile` | yes | `backup` \| `template` \| `sale` — the §5.5 profile this bundle was built under. Determines the allowed portability classes. |
|
|
1191
|
+
| `primitive_inventory` | yes | Map of primitive `type` → count, over every file in the bundle (replaces ultrachat's hard-coded `categories`; it is registry-driven, so extension types appear automatically). |
|
|
1192
|
+
| `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. |
|
|
1193
|
+
| `parameters` | no | Array of parameter definitions (§16.5) the importer must resolve (e.g. business name, domain). |
|
|
1194
|
+
| `source_workspace_id` | no | Origin workspace; OMITTED or nulled in `template`/`sale` profiles (it is operator-identifying). |
|
|
1195
|
+
| `file_count` | yes | Length of `files`; a cheap integrity check. |
|
|
1196
|
+
| `provenance` | yes | `{ content_hash, exporter, signature? }` (§16.3). |
|
|
1197
|
+
|
|
1198
|
+
`primitive_inventory` supersedes ultrachat's fixed `categories` object and `provisioning`
|
|
1199
|
+
supersedes its `capabilities` booleans: both are now open and registry-driven rather than a
|
|
1200
|
+
closed enum, so a bundle full of `festech` extension primitives inventories and provisions
|
|
1201
|
+
them without a spec change.
|
|
1202
|
+
|
|
1203
|
+
### 16.3 Provenance & Integrity
|
|
1204
|
+
|
|
1205
|
+
`provenance` makes a bundle verifiable and attributable:
|
|
1206
|
+
|
|
1207
|
+
- `content_hash` — a hash (SHA-256, hex, prefixed `sha256:`) over the canonical
|
|
1208
|
+
serialization of `files` (path-sorted, §16.1). An importer MUST recompute it and reject
|
|
1209
|
+
a bundle whose files do not match. This is what makes a bundle tamper-evident and what a
|
|
1210
|
+
marketplace lists against.
|
|
1211
|
+
- `exporter` — an identifier for the tool/host that produced the bundle (`"@ssss/cli@0.3.0"`).
|
|
1212
|
+
- `signature` — OPTIONAL detached signature over `content_hash` for a sold bundle, so a
|
|
1213
|
+
buyer can verify authorship. Unsigned bundles are valid; signing is a marketplace concern.
|
|
1214
|
+
|
|
1215
|
+
### 16.4 Files
|
|
1216
|
+
|
|
1217
|
+
Each entry of `files` is `{ path, content }`, where `content` is the full SSSS file text
|
|
1218
|
+
(frontmatter + body, §4). A host MAY also carry a parsed `frontmatter` object for
|
|
1219
|
+
convenience, but `content` is normative — on import the host re-parses `content`, so a
|
|
1220
|
+
divergent cached `frontmatter` is ignored. Every file's resolved portability class (§5.5,
|
|
1221
|
+
honoring `x_portability`) MUST be permitted by `export_profile`.
|
|
1222
|
+
|
|
1223
|
+
### 16.5 Parameters
|
|
1224
|
+
|
|
1225
|
+
`parameters` are the values an importer must supply to turn a template into a running
|
|
1226
|
+
instance — the difference between "a festival in a box" and "*this* festival." The schema is
|
|
1227
|
+
adopted verbatim from ultrachat's `WorkspaceTemplateVariableDefinition`:
|
|
1228
|
+
|
|
1229
|
+
| Field | Meaning |
|
|
1230
|
+
|-------|---------|
|
|
1231
|
+
| `key` | Stable identifier, referenced by provisioning steps and link rewriting. |
|
|
1232
|
+
| `label` | Human prompt. |
|
|
1233
|
+
| `type` | Value type (`string`, `boolean`, `surfaces`, …). |
|
|
1234
|
+
| `scope` | Where the value applies (`workspace`, `automation`, `data`, …). |
|
|
1235
|
+
| `source` | Who supplies it: `user` \| `llm` \| `graph` \| `system`. |
|
|
1236
|
+
| `required` | Whether provisioning may proceed without it. |
|
|
1237
|
+
| `defaultValue`, `options`, `dependsOn` | Optional default, enumerated choices, and dependency keys. |
|
|
1238
|
+
|
|
1239
|
+
A `sale`/`template` bundle declares its `resource_bound` requirements (§5.5) as `parameters`
|
|
1240
|
+
of `source: user` or `source: system` — e.g. the phone number, domain, and mailbox a buyer
|
|
1241
|
+
must bind. This is how the standard guarantees a sold business says exactly what real-world
|
|
1242
|
+
resources it needs without shipping the seller's own.
|
|
1243
|
+
|
|
1244
|
+
---
|
|
1245
|
+
|
|
1246
|
+
## 17. The Provisioning Contract
|
|
1247
|
+
|
|
1248
|
+
Export, provision, and import are the three verbs that move a bundle (§16) between vaults.
|
|
1249
|
+
They are specified to be **deterministic** and **idempotent** so that selling, cloning, and
|
|
1250
|
+
restoring an SSSS business are reliable operations rather than bespoke migrations.
|
|
1251
|
+
|
|
1252
|
+
### 17.1 The Three Verbs
|
|
1253
|
+
|
|
1254
|
+
- **export(vault, profile) → bundle** — Walk the vault, filter by the §5.5 portability rules
|
|
1255
|
+
for `profile`, sort files by path, compute `provenance.content_hash`, and emit a §16
|
|
1256
|
+
bundle. Export is **pure**: the same vault state and profile yield a byte-identical bundle.
|
|
1257
|
+
- **provision(bundle, parameters, target) → plan** — Resolve `parameters` (§16.5), bind the
|
|
1258
|
+
bundle's `resource_bound` requirements to real resources in `target`, and produce an
|
|
1259
|
+
ordered, replayable plan of Operation Contract envelopes (§6) plus resource bindings. A
|
|
1260
|
+
`dry_run` provision (mirroring §6 `dry_run`) validates and plans without committing.
|
|
1261
|
+
- **import(plan, target)** — Replay the plan's envelopes through the target's engine (§6.3).
|
|
1262
|
+
Because each envelope carries an `idempotency_key`, a re-run is a safe no-op: import is
|
|
1263
|
+
idempotent.
|
|
1264
|
+
|
|
1265
|
+
### 17.2 Provisioning Steps & Binding Vocabulary
|
|
1266
|
+
|
|
1267
|
+
A manifest's `provisioning` array is an ordered list of steps. The step schema and its
|
|
1268
|
+
controlled vocabularies are adopted from ultrachat's `WorkspaceProvisioningStep` and
|
|
1269
|
+
`WorkspaceGraphEdge`:
|
|
1270
|
+
|
|
1271
|
+
A **step** is `{ id, label, system, mode, required, notes? }`:
|
|
1272
|
+
|
|
1273
|
+
- `system` — the subsystem the step acts on: `workspace | branding | email | phone |
|
|
1274
|
+
domains | accounts | deployments | marketplace | tabs | automation`.
|
|
1275
|
+
- `mode` — the canonical **binding verb**: `existing` (bind to a resource the target
|
|
1276
|
+
already has), `provision` (allocate a new real resource — a domain, a phone number),
|
|
1277
|
+
`install` (add a dependency bundle), `generate` (synthesize content), `configure` (set
|
|
1278
|
+
values). `mode` is how a bundle distinguishes "needs a *new* phone number" from "route to
|
|
1279
|
+
the operator's existing line."
|
|
1280
|
+
|
|
1281
|
+
Dependency and resource relationships between primitives are expressed with the canonical
|
|
1282
|
+
**edge relations**: `uses_brand | owns_domain | routes_calls_to | deploys_to | has_surface
|
|
1283
|
+
| contains_page | installs_pack | authenticates_account | runs_workflow`. The
|
|
1284
|
+
`resource_bound` primitives of §5.5 each declare which relation binds them (festech's
|
|
1285
|
+
`domain` → `owns_domain`, `phone_number` → `routes_calls_to`, `integration_connection` →
|
|
1286
|
+
`connects_to`), so an importer knows exactly what real-world binding each requires.
|
|
1287
|
+
|
|
1288
|
+
### 17.3 Determinism, Id-Remap & Link Integrity
|
|
1289
|
+
|
|
1290
|
+
When a bundle is provisioned into a target vault, identifiers (slugs, workspace ids,
|
|
1291
|
+
cross-file links) are **remapped** so the imported business is a fresh, self-consistent
|
|
1292
|
+
instance rather than a clone aliasing the seller's ids. Remapping MUST preserve link
|
|
1293
|
+
integrity: every internal `[[link]]` / relative reference that resolved in the source bundle
|
|
1294
|
+
MUST resolve to the remapped target after import. This is the same rewrite engine the
|
|
1295
|
+
semantic layer's autolink (§11) uses, run with a bundle-relative id map. An importer that
|
|
1296
|
+
cannot resolve a link MUST fail the provision rather than emit a dangling reference.
|
|
1297
|
+
|
|
1298
|
+
### 17.4 Composition & Upgrade
|
|
1299
|
+
|
|
1300
|
+
- **Composition** — a bundle MAY depend on other bundles. A dependency carries an
|
|
1301
|
+
`installMode` of `optional | recommended | required` (adopted from ultrachat's
|
|
1302
|
+
`WorkspaceMarketplaceRecommendation`). `provision` installs `required` dependencies before
|
|
1303
|
+
the bundle itself; `optional`/`recommended` are surfaced to the operator.
|
|
1304
|
+
- **Upgrade** — moving an installed bundle from `v2` to a `v1`-conformant shape (or any
|
|
1305
|
+
version step) is performed through a `migration` primitive (§5) plus **structural-only**
|
|
1306
|
+
`patch` envelopes (§6.2). An upgrade MUST NOT touch `tenant_private` data: it rewrites the
|
|
1307
|
+
structural model, never the operator's private records. This is what lets a sold business
|
|
1308
|
+
receive standard updates without the vendor reaching into customer data.
|
|
1309
|
+
|
|
1310
|
+
---
|
|
1311
|
+
|
|
881
1312
|
## Appendix A — Reserved Frontmatter Keys
|
|
882
1313
|
|
|
883
1314
|
The following frontmatter keys are reserved by this spec across all primitives and
|