@everfir/az8-cli 0.1.0 → 0.2.0-preview.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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,29 @@
1
+ # Changelog
2
+
3
+ All notable AZ8 CLI changes are recorded here. The CLI package has its own linear version sequence;
4
+ it does not inherit the Web application or monorepo root version.
5
+
6
+ ## 0.2.0-preview.1 - 2026-07-21
7
+
8
+ First installable internal preview.
9
+
10
+ ### Added
11
+
12
+ - Project list, detail, create, and rename commands.
13
+ - Persistent NDJSON stdio Canvas client with lifecycle, awareness, observations, Receipts,
14
+ reconnect, explicit shutdown, backpressure, and authenticated actor identity.
15
+ - One-shot wrappers over the same Canvas Client and semantic Operation Registry.
16
+ - Note lifecycle, non-World hierarchy, History, summary/detail inspection, and Core Node placement.
17
+ - Generation Planning, Draft editing, Visual References, Workflow start, status query, and bounded
18
+ wait semantics with credit-usage information.
19
+ - Public media URL import and safe local image/video/audio upload and download.
20
+
21
+ ### Safety and compatibility
22
+
23
+ - Canvas writes are available only through semantic Operations and Commands.
24
+ - Writes are serialized, never automatically retried, and isolate the Canvas context after an
25
+ indeterminate result. Read retry remains bounded.
26
+ - Tokens are accepted only through environment variables or env files and are redacted from
27
+ program interaction and diagnostics.
28
+ - 3D World, Asset aggregate management, automatic layout, media replacement, and batch upload are
29
+ intentionally not part of this preview.
package/README.md ADDED
@@ -0,0 +1,330 @@
1
+ # AZ8 CLI
2
+
3
+ AZ8 CLI is a semantic Project Canvas client for agents. It does not import Web implementation code
4
+ and does not expose raw backend, Yjs, or document mutation commands.
5
+
6
+ ## Install the internal preview
7
+
8
+ AZ8 CLI requires Node.js 20 or newer. Install the preview channel from the configured npm registry:
9
+
10
+ ```bash
11
+ npm install --global @everfir/az8-cli@preview
12
+ az8 --version
13
+ az8 help
14
+ ```
15
+
16
+ For a supplied release artifact, install the exact immutable tarball instead:
17
+
18
+ ```bash
19
+ npm install --global ./everfir-az8-cli-0.2.0-preview.1.tgz
20
+ az8 --version
21
+ ```
22
+
23
+ `az8 --version` must report the version selected for the agent environment. Preview releases do not
24
+ replace npm's `latest` channel. Pin an exact version or tarball for reproducible agent runs.
25
+
26
+ ## Credentials and environment
27
+
28
+ Use an ignored `.env.local` or process environment:
29
+
30
+ ```dotenv
31
+ AZ8_TOKEN=...
32
+ AZ8_ENVIRONMENT=test
33
+ ```
34
+
35
+ `AZ8_ENVIRONMENT` accepts `test` or `production`. Command-line `--environment` overrides the env
36
+ value. Tokens must not be passed through argv or stdio protocol payloads.
37
+
38
+ ## Project Management
39
+
40
+ ```bash
41
+ az8 projects list --scope owned
42
+ az8 projects get <project-id>
43
+ az8 projects create --name "CLI iteration"
44
+ az8 projects rename <project-id> --name "New name"
45
+ ```
46
+
47
+ List output is compact and paginated with an opaque cursor. Get returns detail including the current
48
+ collaboration route. Project writes never retry automatically; an uncertain response is reported as
49
+ indeterminate.
50
+
51
+ ## First agent loop
52
+
53
+ A new agent needs only the installed package, a token, and this document. Start by creating its own
54
+ Project and retaining the returned `project.id`:
55
+
56
+ ```bash
57
+ az8 projects create --name "Agent preview workspace"
58
+ az8 canvas query <project-id> capabilities.summary
59
+ printf '%s\n' '{"text":"Release smoke note","position":{"x":160,"y":160}}' \
60
+ | az8 canvas operation <project-id> createNote \
61
+ --input-stdin --request-id preview-note-1
62
+ ```
63
+
64
+ For a long-lived collaborative context, start `az8 canvas open <project-id> --write --format ndjson`,
65
+ read its `hello` frame, send the documented `initialize` request, and wait for `ready` before sending
66
+ queries or Operations. Keep the process and stdin/stdout pipes alive to preserve awareness, local
67
+ History, Receipts, observations, and request replay.
68
+
69
+ For generation, create an image target and call `planGeneration` with the returned View Node and a
70
+ prompt. Execute its returned `plan.operations` in order, stopping after the first failure. A
71
+ successful `startGeneration` Receipt contains the Workflow Run identity; call `waitWorkflowRun`
72
+ separately when a terminal output is required. Planning and starting are intentionally not one
73
+ transaction.
74
+
75
+ For media transfer, `canvas upload` places a verified local image/video/audio file through the
76
+ server-owned Core Node path. After detail query resolves the target's `resolvedCoreNodeId`, `canvas
77
+ download` saves that current output to a new local file. Both commands return structured metadata so
78
+ the agent can verify identities, byte count, MIME, and SHA-256.
79
+
80
+ ## One-shot Canvas wrapper
81
+
82
+ One-shot commands open a real Canvas client, complete synchronization and hydration, invoke the same
83
+ query or Operation used by the persistent client, and close after the result is authoritative:
84
+
85
+ ```bash
86
+ az8 canvas query <project-id> canvas.summary
87
+ az8 canvas query <project-id> canvas.detail --view-node-id <view-node-id>
88
+ printf '%s\n' '{"text":"idea","position":{"x":160,"y":160}}' \
89
+ | az8 canvas operation <project-id> createNote --input-stdin --request-id create-1
90
+ az8 canvas operation <project-id> startGeneration \
91
+ --input-json '{"viewNodeId":"<target-id>"}'
92
+ ```
93
+
94
+ Operation input is one JSON object supplied by exactly one of `--input-stdin`, `--input-file`, or
95
+ `--input-json`; omitted input defaults to `{}`. Input is limited to one MiB. `--timeout-ms` controls
96
+ the same Operation acknowledgement or domain observation window as persistent stdio, and
97
+ `--client-name` changes only the ephemeral awareness display name.
98
+
99
+ Success writes one `az8.canvas.one-shot.v1` JSON document to stdout and exits `0`. A definitive
100
+ input, validation, permission, or business failure writes structured JSON to stderr and exits `1`.
101
+ Connection loss, acknowledgement loss, timeout with unknown effects, or another indeterminate
102
+ lifecycle outcome writes its Receipt or structured error to stderr and exits `2`; mutating
103
+ Operations are never automatically retried.
104
+
105
+ The wrapper adds no Canvas protocol or business logic. Its query and Operation paths share
106
+ `CanvasClient`, Canvas Session, Operation Registry, domain validation, Commands, acknowledgement,
107
+ and Receipt construction with persistent stdio. Consequently `startGeneration` returns after the Run
108
+ start and immediate Canvas effects are acknowledged; waiting for generation remains a separate
109
+ `waitWorkflowRun` call.
110
+
111
+ Each one-shot invocation is a fresh runtime. It therefore does not expose `undo`, `redo`,
112
+ `receipts.summary`, or `receipt.detail`: local Canvas History and the Receipt Log belong to one
113
+ persistent process and are not fabricated across processes. `--request-id` labels the single
114
+ attempt's returned Receipt, but initial one-shot commands do not promise cross-process request replay
115
+ or durable idempotency. Use `canvas open` when an interaction requires History, Receipt lookup,
116
+ observations, or a long-lived awareness identity.
117
+
118
+ ## Local media upload
119
+
120
+ Upload one explicit local image, video, or audio file as a new Canvas resource:
121
+
122
+ ```bash
123
+ az8 canvas upload <project-id> \
124
+ --file ./reference.png \
125
+ --idempotency-key reference-image-1 \
126
+ --name "Reference image" \
127
+ --position-x 640 --position-y 160
128
+ ```
129
+
130
+ This is a convenience wrapper over the public `uploadMedia` Operation, not a separate backend
131
+ shortcut. The wrapper resolves `--file` to the Operation's adapter-owned `source` reference; the
132
+ environment-neutral Canvas Runtime never interprets a local path. The file must be a non-empty
133
+ regular non-symlink file whose bytes identify it as image, video, or audio media. Content type,
134
+ extension, MIME, byte count, and SHA-256 come from inspection rather than caller claims.
135
+
136
+ The Operation follows Web's product sequence: create one undoable `pending` View Node, request a
137
+ presigned upload, stream one credential-free PUT, call Project Content upload completion so the
138
+ server creates the Core Node and binding, then silently mark the View Node `ready`. A known failure
139
+ silently marks the same node `failed`. A lost presign, PUT, Project Content, or collaboration write
140
+ response leaves it `pending`, returns an indeterminate Receipt, takes the Canvas context offline,
141
+ and is never automatically retried.
142
+
143
+ `--idempotency-key` is required and identifies the logical upload independently from the Operation
144
+ Receipt's `--request-id`. Explicit replay with the same normalized file and key first reconciles
145
+ Project Content through a deterministic, opaque intent fingerprint in its source identity; an
146
+ existing binding returns without another upload, while conflicting key reuse fails. Results include
147
+ View Node/Core Node identities and reproducible file metadata but never the presigned or permanent
148
+ file URL. The wrapper uses the standard `az8.canvas.one-shot.v1` output and exit codes and defaults
149
+ to a 300-second deadline. Batch upload, replacement, text-file import, and a durable local upload
150
+ cache are outside the initial slice.
151
+
152
+ ## Local media download
153
+
154
+ Download the current image, video, or audio represented by a View Node, or select an explicit Core
155
+ Node within the Project context:
156
+
157
+ ```bash
158
+ az8 canvas download <project-id> --view-node-id <view-node-id> --output ./result.png
159
+ az8 canvas download <project-id> --core-node-id <core-node-id> --output ./result.mp4
160
+ ```
161
+
162
+ Exactly one source selector and one explicit output path are required. A View Node resolves through
163
+ its current Project Content output, including the compatible display-reference fallback; the CLI
164
+ then reads that Core Node through the same public `getCoreNode` Operation. This command does not
165
+ expose arbitrary URLs, mutate Canvas state, or add content to an Asset.
166
+
167
+ The command opens and hydrates one real collaboration context to resolve the source, then closes it
168
+ before transferring the media. The media request carries no AZ8 token or collaboration credential.
169
+ The response streams into a mode-`0600` temporary file beside the destination, verifies byte count
170
+ and image/video/audio type, computes SHA-256, and only then commits to the final path. Existing paths
171
+ are rejected by default. `--overwrite` may atomically replace an existing regular file, but never a
172
+ directory or symbolic link. A failed, interrupted, or timed-out transfer leaves no partial final
173
+ file and preserves an existing destination.
174
+
175
+ Success writes one `az8.canvas.media-download.v1` document with the absolute path, byte count,
176
+ SHA-256, detected MIME/extension, response metadata, resolved Core Node identity, and whether a file
177
+ was replaced. It deliberately omits the media URL. Exit `0` is success; exit `1` is a definitive
178
+ source, HTTP 4xx, or local-path failure; exit `2` is a retryable connection, HTTP 429/5xx, transfer,
179
+ integrity, or timeout failure; exit `130` is caller cancellation. Downloads are never automatically
180
+ retried. After any non-success, the agent must decide whether a new invocation is safe.
181
+
182
+ ## Persistent Canvas client
183
+
184
+ ```bash
185
+ az8 canvas open <project-id> --write --format ndjson
186
+ ```
187
+
188
+ The process writes one `hello` frame, then waits for an `initialize` request on stdin:
189
+
190
+ ```json
191
+ {"protocolVersion":"1.0","requestId":"init-1","type":"initialize","payload":{"projectId":"<project-id>","client":{"name":"my-agent"},"observationPreset":"compact"}}
192
+ ```
193
+
194
+ Before readiness the client hydrates the current authenticated account profile. Canvas Operations use
195
+ that immutable account id and display name for persisted creator data. The `client.name` supplied by
196
+ `initialize` is awareness-only and cannot impersonate or rename the persisted author. Project owner
197
+ metadata is likewise never treated as the current actor on shared Projects.
198
+
199
+ After `ready`, requests use `query`, `configureObservations`, `operation`, `reconnect`, or `shutdown`.
200
+ The public authoring surface includes the note lifecycle, non-World View Node hierarchy operations,
201
+ and the Stage 3 Core Node creative loop. Hierarchy operations are `groupViewNodes`,
202
+ `ungroupViewNode`, `moveViewNodes` with an optional `targetParentId`, and
203
+ `updateViewNodeStacking`. Core Node operations are `getCoreNode`, `placeCoreNode`,
204
+ `createMediaTarget`, `planGeneration`, `importExternalMedia`, `uploadMedia`, `editGenerationDraft`,
205
+ `addVisualReference`, `removeVisualReference`, `startGeneration`, `getWorkflowRun`, and
206
+ `waitWorkflowRun`. Capability detail is discoverable through `capabilities.detail`; callers should
207
+ use it instead of hard-coding input schemas. Workflow Definitions are available through
208
+ `workflowDefinitions.summary` and `workflowDefinition.detail` queries.
209
+
210
+ Before editing a Draft, an agent can call the read-only `planGeneration` Operation for an existing
211
+ media target. It recommends a Definition from the target and resolved Visual Reference modalities,
212
+ constructs configuration defaults, validates required inputs, and returns compact alternatives plus
213
+ an ordered semantic Operation sequence. Use `detail: "detail"` to include slot and configuration
214
+ field metadata, including dynamic enum options. Planning never creates a Core Node or changes the
215
+ Canvas; returned Operations still execute independently and stop at the first failure.
216
+
217
+ ```json
218
+ {"protocolVersion":"1.0","requestId":"plan-1","type":"operation","payload":{"name":"planGeneration","input":{"targetViewNodeId":"<target-id>","prompt":"A quiet observatory","references":[{"viewNodeId":"<reference-id>"}],"detail":"detail"}}}
219
+ ```
220
+
221
+ `editNoteContent`, `renameViewNode`, and `resizeViewNodes` match Web's silent History policy.
222
+ `duplicateViewNodes` and `removeViewNodes` are undoable. Removal atomically cleans Draft references
223
+ from surviving nodes. Duplication supports notes and non-World resource nodes; resource copies retain
224
+ the currently displayed Project Content output without cloning a Core Node or creating Project
225
+ Content. Grouping, ungrouping, reparenting, and stacking are also undoable. Their inputs use absolute
226
+ canvas coordinates even though grouped children are persisted relative to their parent. Reparenting
227
+ preserves absolute placement, expands a destination group when needed without shrinking it, and
228
+ removes a source group only when the move leaves it empty. Group nodes cannot be nested, and stacking
229
+ is scoped to siblings with the same parent. Decoration, Asset, and all World targets remain deferred.
230
+
231
+ Example write:
232
+
233
+ ```json
234
+ {"protocolVersion":"1.0","requestId":"create-1","type":"operation","payload":{"name":"createNote","input":{"text":"idea","position":{"x":160,"y":160}}}}
235
+ ```
236
+
237
+ Example Stage 2 edits:
238
+
239
+ ```json
240
+ {"protocolVersion":"1.0","requestId":"edit-1","type":"operation","payload":{"name":"editNoteContent","input":{"viewNodeId":"view_node_1","text":"revised idea"}}}
241
+ {"protocolVersion":"1.0","requestId":"resize-1","type":"operation","payload":{"name":"resizeViewNodes","input":{"resizes":[{"viewNodeId":"view_node_1","size":{"width":420,"height":360}}]}}}
242
+ {"protocolVersion":"1.0","requestId":"duplicate-1","type":"operation","payload":{"name":"duplicateViewNodes","input":{"viewNodeIds":["view_node_1"]}}}
243
+ ```
244
+
245
+ Example hierarchy sequence (each successful write is one independent undoable interaction):
246
+
247
+ ```json
248
+ {"protocolVersion":"1.0","requestId":"group-1","type":"operation","payload":{"name":"groupViewNodes","input":{"viewNodeIds":["view_node_1","view_node_2"],"name":"References"}}}
249
+ {"protocolVersion":"1.0","requestId":"reparent-1","type":"operation","payload":{"name":"moveViewNodes","input":{"moves":[{"id":"view_node_3","position":{"x":640,"y":360},"targetParentId":"<group-id>"}]}}}
250
+ {"protocolVersion":"1.0","requestId":"front-1","type":"operation","payload":{"name":"updateViewNodeStacking","input":{"viewNodeId":"view_node_3","direction":"front"}}}
251
+ {"protocolVersion":"1.0","requestId":"ungroup-1","type":"operation","payload":{"name":"ungroupViewNode","input":{"groupViewNodeId":"<group-id>"}}}
252
+ ```
253
+
254
+ Example Stage 3 generation sequence (each line is a separate ordered interaction):
255
+
256
+ ```json
257
+ {"protocolVersion":"1.0","requestId":"target-1","type":"operation","payload":{"name":"createMediaTarget","input":{"contentType":"image"}}}
258
+ {"protocolVersion":"1.0","requestId":"draft-1","type":"operation","payload":{"name":"editGenerationDraft","input":{"viewNodeId":"<target-id>","definitionId":"<definition-id>","prompt":"A quiet observatory","config":{"aspect_ratio":"16:9"}}}}
259
+ {"protocolVersion":"1.0","requestId":"start-1","type":"operation","payload":{"name":"startGeneration","input":{"viewNodeId":"<target-id>"}}}
260
+ {"protocolVersion":"1.0","requestId":"wait-1","type":"operation","payload":{"name":"waitWorkflowRun","input":{"workflowRunId":"<run-id>"},"timeoutMs":120000}}
261
+ ```
262
+
263
+ Example public media URL import:
264
+
265
+ ```json
266
+ {"protocolVersion":"1.0","requestId":"import-1","type":"operation","payload":{"name":"importExternalMedia","input":{"contentType":"image","idempotencyKey":"reference-image-1","url":"https://example.com/reference.png","name":"Reference image","position":{"x":640,"y":160}}}}
267
+ ```
268
+
269
+ `idempotencyKey` is required. Repeating the same normalized input returns the existing View Node and
270
+ Core Node without another write; reusing the key for different input fails. Image, video, and audio
271
+ are supported. The URL is referenced directly—this operation neither uploads a file nor adds the
272
+ Core Node to an Asset. Known failures leave one inspectable `failed` View Node that can be resumed by
273
+ explicitly submitting the same input. An uncertain backend or collaboration outcome leaves the node
274
+ `pending`, takes the context offline, and is never retried automatically.
275
+
276
+ `startGeneration` succeeds when the server accepts the Workflow Run and the immediate Canvas facts
277
+ are acknowledged. It first estimates the exact current Draft inputs, then materializes literal Core
278
+ Nodes and starts with the estimate's cost and Definition version. This estimate is internal: there is
279
+ no public estimate Operation, balance query, caller-supplied expected cost, or second confirmation.
280
+ Waiting for a terminal result is deliberately a separate operation. Generation is a non-undoable
281
+ Canvas History barrier. The CLI does not expose Assets, arbitrary Core Node creation, or 3D World
282
+ operations.
283
+
284
+ Initial connection and explicit reconnect recover every Workflow Run referenced by the Canvas
285
+ pending set before reporting `ready`. Pending/running Runs receive one live subscription; Runs that
286
+ completed while the CLI was offline refresh Project Content and clear their pending Canvas fact
287
+ through a semantic Command. Status-stream read recovery is bounded. Exhaustion, or an indeterminate
288
+ pending-fact cleanup acknowledgement, closes the Canvas context and requires explicit reconnect.
289
+ Cleanup writes are not automatically retried.
290
+
291
+ `waitWorkflowRun` uses `timeoutMs` as a caller-selected observation window. If that window expires
292
+ while the Run is still authoritatively pending or running, the request fails ordinarily, the Canvas
293
+ context remains ready, and lifecycle observation continues. This is distinct from a transport,
294
+ backend-execution, or collaboration-acknowledgement deadline whose unknown outcome isolates the
295
+ context as offline.
296
+
297
+ The start Receipt has an extensible `usage.credits` object. `status: "estimated"` means the Workflow
298
+ was accepted and `estimate.amount` is an estimate rather than authoritative charged usage;
299
+ `"not-consumed"` means generation was definitely not started; and `"unknown"` means the start write
300
+ lost its authoritative response and must be reconciled after reconnect. An available estimate also
301
+ records its Definition identity and version. The CLI never converts an estimate into an actual-charge
302
+ claim.
303
+
304
+ Every output frame has `protocolVersion`, monotonic `streamSeq`, `type`, `payload`, and optional
305
+ `requestId`. stdout contains protocol frames only; diagnostics use stderr. A write completes only
306
+ after collaboration-server acknowledgement. A timeout or lost acknowledgement is indeterminate,
307
+ moves the Canvas context offline, and requires explicit reconnect and inspection before any retry.
308
+
309
+ ## Preview acceptance checklist
310
+
311
+ Before distributing a preview tarball, verify all of the following from its clean installation, not
312
+ from TypeScript source:
313
+
314
+ 1. `az8 --version` matches the immutable package version and `az8 help` lists Project, persistent
315
+ Canvas, one-shot, upload, and download entry points.
316
+ 2. With no credential, an authenticated command fails without connecting and without printing a
317
+ token. With the test token, `projects create` returns a new Project owned by the authenticated
318
+ account.
319
+ 3. Persistent stdio reaches `ready`, accepts a summary query, creates a note whose Receipt records
320
+ the authenticated Actor, and completes an ordered shutdown.
321
+ 4. One-shot `createMediaTarget` plus `planGeneration` returns a ready semantic sequence; executing
322
+ that sequence starts one Workflow Run, and `waitWorkflowRun` or later `getWorkflowRun` observes
323
+ its authoritative state.
324
+ 5. Upload one small local media file, confirm immediate detail resolution to its Core Node, replay
325
+ the same idempotency key without another transfer, and download the resolved media to a fresh
326
+ destination whose SHA-256 is reported.
327
+ 6. Run repository `pnpm verify`, retain the tarball SHA-512, and record the tested environment. Never
328
+ perform these acceptance writes against production.
329
+
330
+ Release and rollback commands are in `RELEASE.md`; package changes are in `CHANGELOG.md`.
package/RELEASE.md ADDED
@@ -0,0 +1,59 @@
1
+ # AZ8 CLI preview release
2
+
3
+ This package is an internal preview. `preview` is the release channel; it must not replace npm's
4
+ `latest` tag until a separate stability decision is made.
5
+
6
+ ## Release gate
7
+
8
+ From the repository root:
9
+
10
+ ```bash
11
+ pnpm release:az8-cli
12
+ pnpm release:pack:az8-cli
13
+ ```
14
+
15
+ The first command runs CLI tests, type checking, builds a real npm tarball, installs that tarball in
16
+ a clean temporary directory, and verifies the installed `az8` executable. The second preserves the
17
+ verified tarball and clean installation under `tmp/az8-cli-release/` for live acceptance.
18
+
19
+ Run the live smoke only against the test environment. It creates one Project unless `--project-id`
20
+ reuses an explicit test Project, starts one image generation, and uploads one tiny PNG:
21
+
22
+ ```bash
23
+ node apps/az8-cli/scripts/smoke-test.js \
24
+ --bin ./tmp/az8-cli-release/install/node_modules/.bin/az8 \
25
+ --env-file ./.env.local
26
+ ```
27
+
28
+ The smoke report must show authenticated persistent stdio, ordered shutdown, a completed Workflow
29
+ Run whose target resolves its output Core Node, upload replay without another transfer, and matching
30
+ download SHA-256. `--skip-generation` is only for diagnosing unrelated media or transport checks;
31
+ it cannot satisfy full release acceptance.
32
+
33
+ Before publishing, also run the test-environment acceptance checklist in the packaged README and the
34
+ repository-wide `pnpm verify`. Publishing is an external action and requires explicit operator
35
+ authorization:
36
+
37
+ ```bash
38
+ npm publish ./tmp/az8-cli-release/everfir-az8-cli-0.2.0-preview.1.tgz --tag preview
39
+ npm view @everfir/az8-cli dist-tags versions --json
40
+ ```
41
+
42
+ Do not pass `--tag latest`. Do not publish from an unverified source directory.
43
+
44
+ ## Rollback
45
+
46
+ Published versions are immutable. Rollback moves the `preview` tag to a previously verified version
47
+ instead of unpublishing or overwriting a package:
48
+
49
+ ```bash
50
+ npm dist-tag add @everfir/az8-cli@<previous-version> preview
51
+ npm view @everfir/az8-cli dist-tags --json
52
+ npm install --global @everfir/az8-cli@preview
53
+ az8 --version
54
+ ```
55
+
56
+ For tarball distribution, retain every verified `.tgz`; reinstall the previous tarball and confirm
57
+ `az8 --version`. A rollback changes only the installed client. It never reverses already
58
+ acknowledged Project or Canvas effects; agents must use semantic compensation or Canvas History for
59
+ product data.