@fias/arche-sdk 2.26.0 → 2.27.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.
@@ -9,7 +9,7 @@
9
9
  * `tests/architecture/sdk-permissions-match-db-types.test.ts` ensures
10
10
  * this file stays in lockstep with the canonical source.
11
11
  */
12
- export type PluginPermission = 'ai:actions' | 'assets:community:publish' | 'assets:community:read' | 'assets:read' | 'data:search' | 'data:store' | 'data:workspace' | 'docsign:envelopes:read' | 'email:company:send' | 'entities:audio_generate' | 'entities:client_invoke' | 'entities:image_edit' | 'entities:image_generate' | 'entities:invoke' | 'entities:web_search' | 'navigation:open_arche' | 'sandbox:vendored-libraries' | 'storage:sandbox' | 'store:purchase' | 'theme:read' | 'user:profile:read' | 'vault:arche-saves:write' | 'vault:documents:read' | 'vault:documents:write' | 'vault:user-documents:edit' | 'vault:user-documents:read' | 'vault:user-documents:write' | 'vault:workspace-documents:read';
12
+ export type PluginPermission = 'ai:actions' | 'assets:community:publish' | 'assets:community:read' | 'assets:read' | 'data:agents' | 'data:search' | 'data:store' | 'data:workspace' | 'docsign:envelopes:read' | 'email:company:send' | 'entities:audio_generate' | 'entities:client_invoke' | 'entities:image_edit' | 'entities:image_generate' | 'entities:invoke' | 'entities:web_search' | 'navigation:open_arche' | 'sandbox:vendored-libraries' | 'storage:sandbox' | 'store:purchase' | 'theme:read' | 'user:profile:read' | 'vault:arche-saves:write' | 'vault:documents:read' | 'vault:documents:write' | 'vault:user-documents:edit' | 'vault:user-documents:read' | 'vault:user-documents:write' | 'vault:workspace-documents:read';
13
13
  export declare const VALID_PLUGIN_PERMISSIONS: readonly PluginPermission[];
14
14
  export declare function isValidPluginPermission(perm: string): perm is PluginPermission;
15
15
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../src/generated/permissions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,gBAAgB,GACxB,YAAY,GACZ,0BAA0B,GAC1B,uBAAuB,GACvB,aAAa,GACb,aAAa,GACb,YAAY,GACZ,gBAAgB,GAChB,wBAAwB,GACxB,oBAAoB,GACpB,yBAAyB,GACzB,wBAAwB,GACxB,qBAAqB,GACrB,yBAAyB,GACzB,iBAAiB,GACjB,qBAAqB,GACrB,uBAAuB,GACvB,4BAA4B,GAC5B,iBAAiB,GACjB,gBAAgB,GAChB,YAAY,GACZ,mBAAmB,GACnB,yBAAyB,GACzB,sBAAsB,GACtB,uBAAuB,GACvB,2BAA2B,GAC3B,2BAA2B,GAC3B,4BAA4B,GAC5B,gCAAgC,CAAC;AAErC,eAAO,MAAM,wBAAwB,EAAE,SAAS,gBAAgB,EA6BtD,CAAC;AAEX,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,IAAI,gBAAgB,CAE9E;AAED;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,EAAE,QAAQ,CAAC,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAwCrF,CAAC"}
1
+ {"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../src/generated/permissions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,gBAAgB,GACxB,YAAY,GACZ,0BAA0B,GAC1B,uBAAuB,GACvB,aAAa,GACb,aAAa,GACb,aAAa,GACb,YAAY,GACZ,gBAAgB,GAChB,wBAAwB,GACxB,oBAAoB,GACpB,yBAAyB,GACzB,wBAAwB,GACxB,qBAAqB,GACrB,yBAAyB,GACzB,iBAAiB,GACjB,qBAAqB,GACrB,uBAAuB,GACvB,4BAA4B,GAC5B,iBAAiB,GACjB,gBAAgB,GAChB,YAAY,GACZ,mBAAmB,GACnB,yBAAyB,GACzB,sBAAsB,GACtB,uBAAuB,GACvB,2BAA2B,GAC3B,2BAA2B,GAC3B,4BAA4B,GAC5B,gCAAgC,CAAC;AAErC,eAAO,MAAM,wBAAwB,EAAE,SAAS,gBAAgB,EA8BtD,CAAC;AAEX,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,IAAI,gBAAgB,CAE9E;AAED;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,EAAE,QAAQ,CAAC,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC,CA0CrF,CAAC"}
@@ -18,6 +18,7 @@ exports.VALID_PLUGIN_PERMISSIONS = [
18
18
  'assets:community:publish',
19
19
  'assets:community:read',
20
20
  'assets:read',
21
+ 'data:agents',
21
22
  'data:search',
22
23
  'data:store',
23
24
  'data:workspace',
@@ -56,6 +57,7 @@ exports.PLUGIN_PERMISSION_DESCRIPTIONS = {
56
57
  'assets:community:publish': 'Share images you made here so other people using this arche can see them, and manage what you have shared.',
57
58
  'assets:community:read': 'Show you images that other people using this arche have shared. Everything shared is checked before anyone can see it.',
58
59
  'assets:read': "Show images from this arche's published asset library.",
60
+ 'data:agents': "Let Fias AI, and assistants you connect with an API key and allow here, read this arche's data — and change it where it says so — even while it is closed.",
59
61
  'data:search': "Search this arche's own data semantically — costs credits per search.",
60
62
  'data:store': "Save structured data in this arche's own private database.",
61
63
  'data:workspace': 'Create team workspaces and manage their members.',
@@ -1 +1 @@
1
- {"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../src/generated/permissions.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;AA+DH,0DAEC;AAjCY,QAAA,wBAAwB,GAAgC;IACnE,YAAY;IACZ,0BAA0B;IAC1B,uBAAuB;IACvB,aAAa;IACb,aAAa;IACb,YAAY;IACZ,gBAAgB;IAChB,wBAAwB;IACxB,oBAAoB;IACpB,yBAAyB;IACzB,wBAAwB;IACxB,qBAAqB;IACrB,yBAAyB;IACzB,iBAAiB;IACjB,qBAAqB;IACrB,uBAAuB;IACvB,4BAA4B;IAC5B,iBAAiB;IACjB,gBAAgB;IAChB,YAAY;IACZ,mBAAmB;IACnB,yBAAyB;IACzB,sBAAsB;IACtB,uBAAuB;IACvB,2BAA2B;IAC3B,2BAA2B;IAC3B,4BAA4B;IAC5B,gCAAgC;CACxB,CAAC;AAEX,SAAgB,uBAAuB,CAAC,IAAY;IAClD,OAAQ,gCAA8C,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxE,CAAC;AAED;;;;GAIG;AACU,QAAA,8BAA8B,GAA+C;IACxF,YAAY,EACV,6HAA6H;IAC/H,0BAA0B,EACxB,4GAA4G;IAC9G,uBAAuB,EACrB,wHAAwH;IAC1H,aAAa,EAAE,wDAAwD;IACvE,aAAa,EAAE,uEAAuE;IACtF,YAAY,EAAE,4DAA4D;IAC1E,gBAAgB,EAAE,kDAAkD;IACpE,wBAAwB,EACtB,iGAAiG;IACnG,oBAAoB,EAClB,yNAAyN;IAC3N,yBAAyB,EAAE,kDAAkD;IAC7E,wBAAwB,EACtB,wEAAwE;IAC1E,qBAAqB,EAAE,+CAA+C;IACtE,yBAAyB,EAAE,mDAAmD;IAC9E,iBAAiB,EAAE,wDAAwD;IAC3E,qBAAqB,EAAE,qDAAqD;IAC5E,uBAAuB,EAAE,8CAA8C;IACvE,4BAA4B,EAC1B,8EAA8E;IAChF,iBAAiB,EAAE,iDAAiD;IACpE,gBAAgB,EAAE,+DAA+D;IACjF,YAAY,EAAE,4BAA4B;IAC1C,mBAAmB,EAAE,mCAAmC;IACxD,yBAAyB,EAAE,gDAAgD;IAC3E,sBAAsB,EAAE,yEAAyE;IACjG,uBAAuB,EAAE,mEAAmE;IAC5F,2BAA2B,EACzB,0MAA0M;IAC5M,2BAA2B,EACzB,kJAAkJ;IACpJ,4BAA4B,EAC1B,iFAAiF;IACnF,gCAAgC,EAC9B,yJAAyJ;CAC5J,CAAC"}
1
+ {"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../src/generated/permissions.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;AAiEH,0DAEC;AAlCY,QAAA,wBAAwB,GAAgC;IACnE,YAAY;IACZ,0BAA0B;IAC1B,uBAAuB;IACvB,aAAa;IACb,aAAa;IACb,aAAa;IACb,YAAY;IACZ,gBAAgB;IAChB,wBAAwB;IACxB,oBAAoB;IACpB,yBAAyB;IACzB,wBAAwB;IACxB,qBAAqB;IACrB,yBAAyB;IACzB,iBAAiB;IACjB,qBAAqB;IACrB,uBAAuB;IACvB,4BAA4B;IAC5B,iBAAiB;IACjB,gBAAgB;IAChB,YAAY;IACZ,mBAAmB;IACnB,yBAAyB;IACzB,sBAAsB;IACtB,uBAAuB;IACvB,2BAA2B;IAC3B,2BAA2B;IAC3B,4BAA4B;IAC5B,gCAAgC;CACxB,CAAC;AAEX,SAAgB,uBAAuB,CAAC,IAAY;IAClD,OAAQ,gCAA8C,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxE,CAAC;AAED;;;;GAIG;AACU,QAAA,8BAA8B,GAA+C;IACxF,YAAY,EACV,6HAA6H;IAC/H,0BAA0B,EACxB,4GAA4G;IAC9G,uBAAuB,EACrB,wHAAwH;IAC1H,aAAa,EAAE,wDAAwD;IACvE,aAAa,EACX,4JAA4J;IAC9J,aAAa,EAAE,uEAAuE;IACtF,YAAY,EAAE,4DAA4D;IAC1E,gBAAgB,EAAE,kDAAkD;IACpE,wBAAwB,EACtB,iGAAiG;IACnG,oBAAoB,EAClB,yNAAyN;IAC3N,yBAAyB,EAAE,kDAAkD;IAC7E,wBAAwB,EACtB,wEAAwE;IAC1E,qBAAqB,EAAE,+CAA+C;IACtE,yBAAyB,EAAE,mDAAmD;IAC9E,iBAAiB,EAAE,wDAAwD;IAC3E,qBAAqB,EAAE,qDAAqD;IAC5E,uBAAuB,EAAE,8CAA8C;IACvE,4BAA4B,EAC1B,8EAA8E;IAChF,iBAAiB,EAAE,iDAAiD;IACpE,gBAAgB,EAAE,+DAA+D;IACjF,YAAY,EAAE,4BAA4B;IAC1C,mBAAmB,EAAE,mCAAmC;IACxD,yBAAyB,EAAE,gDAAgD;IAC3E,sBAAsB,EAAE,yEAAyE;IACjG,uBAAuB,EAAE,mEAAmE;IAC5F,2BAA2B,EACzB,0MAA0M;IAC5M,2BAA2B,EACzB,kJAAkJ;IACpJ,4BAA4B,EAC1B,iFAAiF;IACnF,gCAAgC,EAC9B,yJAAyJ;CAC5J,CAAC"}
package/dist/index.mjs CHANGED
@@ -2948,6 +2948,7 @@ var VALID_PLUGIN_PERMISSIONS = [
2948
2948
  "assets:community:publish",
2949
2949
  "assets:community:read",
2950
2950
  "assets:read",
2951
+ "data:agents",
2951
2952
  "data:search",
2952
2953
  "data:store",
2953
2954
  "data:workspace",
@@ -2981,6 +2982,7 @@ var PLUGIN_PERMISSION_DESCRIPTIONS = {
2981
2982
  "assets:community:publish": "Share images you made here so other people using this arche can see them, and manage what you have shared.",
2982
2983
  "assets:community:read": "Show you images that other people using this arche have shared. Everything shared is checked before anyone can see it.",
2983
2984
  "assets:read": "Show images from this arche's published asset library.",
2985
+ "data:agents": "Let Fias AI, and assistants you connect with an API key and allow here, read this arche's data \u2014 and change it where it says so \u2014 even while it is closed.",
2984
2986
  "data:search": "Search this arche's own data semantically \u2014 costs credits per search.",
2985
2987
  "data:store": "Save structured data in this arche's own private database.",
2986
2988
  "data:workspace": "Create team workspaces and manage their members.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fias/arche-sdk",
3
- "version": "2.26.0",
3
+ "version": "2.27.0",
4
4
  "description": "SDK for building FIAS platform plugin arches",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,4 +1,4 @@
1
- <!-- fias-sdk-guide-version: 2.26.0 -->
1
+ <!-- fias-sdk-guide-version: 2.27.0 -->
2
2
 
3
3
  # FIAS Plugin Development Guide
4
4
 
@@ -283,6 +283,121 @@ Why this and not `createCollection` at startup: the runtime op is capped at **10
283
283
 
284
284
  Re-publishing is safe: existing collections are left alone, a stricter role floor is applied, a looser one is refused, and a collection you stop declaring is kept (never deleted — it may hold user data). Keep using `createCollection` for collections whose names you only know at runtime.
285
285
 
286
+ ### Letting agents use your data (`agentAccess`)
287
+
288
+ **Permission:** `data:agents` (requires `data:store`)
289
+
290
+ Your plugin can share some of its collections with AI agents — the platform's Fias AI assistant, and agents a user connects over MCP (Claude Code and others) — **while your plugin is closed**. Agents never run your code: they read and change documents through a fixed set of platform tools (`plugin_apps_list`, `plugin_app_describe`, `plugin_data_query`, `plugin_data_get`, `plugin_data_put`, `plugin_data_patch`, `plugin_data_delete`). Declare what you share in `fias-plugin.json`:
291
+
292
+ ```jsonc
293
+ "permissions": ["data:store", "data:agents"],
294
+ "collections": [
295
+ { "name": "scenes", "scope": "user" },
296
+ { "name": "render_requests", "scope": "user" },
297
+ { "name": "previews", "scope": "user" }
298
+ ],
299
+ "agentAccess": {
300
+ "description": "Puppet cut scenes: a cast, scene-frames and spoken lines.",
301
+ "collections": {
302
+ "scenes": {
303
+ "access": "read_write",
304
+ "description": "One cut scene per document, keyed by scene id.",
305
+ "schema": { "type": "object", "properties": { "title": { "type": "string" } }, "required": ["title"] }
306
+ },
307
+ "render_requests": {
308
+ "access": "read_write",
309
+ "description": "Ask the open app for stills of a scene at chosen times.",
310
+ "schema": {
311
+ "type": "object",
312
+ "properties": {
313
+ "scene": { "type": "string", "maxLength": 100 },
314
+ "times": { "type": "array", "items": { "type": "number", "minimum": 0 }, "minItems": 1, "maxItems": 12 },
315
+ "width": { "type": "integer", "minimum": 64, "maximum": 800 },
316
+ "status": { "enum": ["pending", "working", "done", "failed"] },
317
+ "error": { "type": "string", "maxLength": 2000 },
318
+ "previews": { "type": "integer", "minimum": 0, "maximum": 12 }
319
+ },
320
+ "required": ["scene", "times", "status"],
321
+ "additionalProperties": false
322
+ }
323
+ },
324
+ "previews": { "access": "read", "description": "Stills the open app rendered.", "images": ["/image"] }
325
+ }
326
+ }
327
+ ```
328
+
329
+ Rules (checked by `fias-dev validate` and at publish):
330
+
331
+ - `data:agents` and the `agentAccess` block go together: declaring the permission without a block is an error.
332
+ - Only collections you declare in `collections`, with `user` or `shared` scope. `read_write` only on `user` scope (a write to a `shared` collection would land in every user's copy), and it needs a `schema` — every agent write is validated against it. `workspace` collections can't be shared with agents yet.
333
+ - Schemas use a restricted JSON Schema 2020-12: `type`, `properties`, `required`, `additionalProperties`, `items`, `prefixItems`, `enum`, `const`, min/max bounds, `anyOf`/`oneOf`/`allOf`/`not`, `title`, `description`, `default`, `examples`, `format` (annotation only), and `$ref` to your own `#/$defs/…`. **No `pattern`** (regular expressions), no `propertyNames`, and no remote `$ref`. `uniqueItems` only on arrays whose `items` have a scalar `type`. A `$ref` may recurse only through `properties` / `items` / `additionalProperties` (a tree), never straight back to itself. ≤ 16 KB per schema, depth ≤ 12. If you generate schemas with Zod, note that `z.record()` emits `propertyNames` and `z.email()` / `z.uuid()` / `z.regex()` emit `pattern` — neither is accepted.
334
+ - Descriptions describe your data — they are not instructions to an AI. The publish review flags text that tells an agent what to do, links, and mentions of other apps.
335
+ - `images` names fields holding `{ "mimeType": "image/png" | "image/jpeg" | "image/webp", "data": "<base64>" }` (≤ 96 KB, ≤ 2000 px a side; every image is fully decoded before an agent sees it, and one that doesn't decode is replaced by an error). Agents receive them as pictures and can never write them — so in a `read_write` collection an image field must be optional, never `required`.
336
+
337
+ What agents can do: **Fias AI** acts as the signed-in user on what you declare. An **external agent** reaches your app only through an API key the user allowed to use it, collection by collection, read or read and change — and if you later share more, nothing new is reachable until the user allows it again. Every agent write is conditional on the version it read, so it can't silently overwrite a change made in your open UI; deletes always need the user's confirmation in Fias.
338
+
339
+ **Your obligation for `read_write` collections: validate what you load.** An agent — or text an agent was shown — may have written it. Treat those documents like any untrusted input; never evaluate or render a field as code or HTML.
340
+
341
+ **Answering an agent while open (previews).** Agents can't run your code, but your open plugin can do work for them through data. Watch a requests collection, do the work, and write the answer back:
342
+
343
+ ```tsx
344
+ const dataStore = useFiasDataStore();
345
+ const answerPending = useCallback(async () => {
346
+ const { documents } = await dataStore.query<RenderRequest>('render_requests', {
347
+ filters: [{ field: 'status', op: 'eq', value: 'pending' }],
348
+ limit: 5,
349
+ });
350
+ for (const req of documents) {
351
+ // Claim it first, so two open tabs never both do it.
352
+ const claimed = await dataStore
353
+ .batch(
354
+ [
355
+ {
356
+ op: 'put',
357
+ collection: 'render_requests',
358
+ key: req.key,
359
+ data: { ...req.data, status: 'working' },
360
+ },
361
+ ],
362
+ {
363
+ preconditions: [
364
+ { kind: 'version', collection: 'render_requests', key: req.key, version: req.version },
365
+ ],
366
+ },
367
+ )
368
+ .then(
369
+ () => true,
370
+ () => false,
371
+ );
372
+ if (!claimed) continue;
373
+ const stills = await renderStills(req.data); // your own code, bounded by your schema
374
+ for (const [i, image] of stills.entries()) {
375
+ await dataStore.put('previews', `${req.key}-${i}`, {
376
+ request: req.key,
377
+ t: req.data.times[i],
378
+ image,
379
+ });
380
+ }
381
+ await dataStore.put('render_requests', req.key, {
382
+ ...req.data,
383
+ status: 'done',
384
+ previews: stills.length,
385
+ });
386
+ }
387
+ }, [dataStore]);
388
+ useDataSubscription('render_requests', answerPending); // changes arrive at most once —
389
+ useEffect(() => {
390
+ // so also check on open and every ~10 s
391
+ void answerPending();
392
+ const timer = setInterval(answerPending, 10_000);
393
+ return () => clearInterval(timer);
394
+ }, [answerPending]);
395
+ ```
396
+
397
+ The agent writes a request, waits on it with `plugin_data_get` (`afterVersion` + `waitSeconds`), and reads the stills back as images. Keep requests bounded in your schema (e.g. `"times": { "maxItems": 12 }`), prune old previews, and report failures in the request (e.g. `status: "failed"` with errors) so the agent can fix what it wrote. **Give both the requests and the results collections `user` scope** — in a `shared` collection any user of your app could plant a "result" that another user's agent then reads.
398
+
399
+ **Testing:** in the dev harness's Fias AI window, the read tools see your local `agentAccess` block against your dev data — ask "what scenes do I have?" to see what an agent sees before you publish.
400
+
286
401
  **Rate limits (per minute):** `put` 120, `get` 300, `query` 60, `delete` 60, `batch` 30, `createCollection` 10
287
402
 
288
403
  **Error handling:** Data store calls can reject on infrastructure errors or limit violations. Always use `try/catch`. Common error codes: `COLLECTION_NOT_FOUND`, `DOCUMENT_TOO_LARGE`, `STORAGE_LIMIT_REACHED`, `RATE_LIMIT`.
@@ -1,4 +1,4 @@
1
- <!-- fias-sdk-guide-version: 2.26.0 -->
1
+ <!-- fias-sdk-guide-version: 2.27.0 -->
2
2
 
3
3
  # FIAS Plugin Development Guide
4
4
 
@@ -283,6 +283,121 @@ Why this and not `createCollection` at startup: the runtime op is capped at **10
283
283
 
284
284
  Re-publishing is safe: existing collections are left alone, a stricter role floor is applied, a looser one is refused, and a collection you stop declaring is kept (never deleted — it may hold user data). Keep using `createCollection` for collections whose names you only know at runtime.
285
285
 
286
+ ### Letting agents use your data (`agentAccess`)
287
+
288
+ **Permission:** `data:agents` (requires `data:store`)
289
+
290
+ Your plugin can share some of its collections with AI agents — the platform's Fias AI assistant, and agents a user connects over MCP (Claude Code and others) — **while your plugin is closed**. Agents never run your code: they read and change documents through a fixed set of platform tools (`plugin_apps_list`, `plugin_app_describe`, `plugin_data_query`, `plugin_data_get`, `plugin_data_put`, `plugin_data_patch`, `plugin_data_delete`). Declare what you share in `fias-plugin.json`:
291
+
292
+ ```jsonc
293
+ "permissions": ["data:store", "data:agents"],
294
+ "collections": [
295
+ { "name": "scenes", "scope": "user" },
296
+ { "name": "render_requests", "scope": "user" },
297
+ { "name": "previews", "scope": "user" }
298
+ ],
299
+ "agentAccess": {
300
+ "description": "Puppet cut scenes: a cast, scene-frames and spoken lines.",
301
+ "collections": {
302
+ "scenes": {
303
+ "access": "read_write",
304
+ "description": "One cut scene per document, keyed by scene id.",
305
+ "schema": { "type": "object", "properties": { "title": { "type": "string" } }, "required": ["title"] }
306
+ },
307
+ "render_requests": {
308
+ "access": "read_write",
309
+ "description": "Ask the open app for stills of a scene at chosen times.",
310
+ "schema": {
311
+ "type": "object",
312
+ "properties": {
313
+ "scene": { "type": "string", "maxLength": 100 },
314
+ "times": { "type": "array", "items": { "type": "number", "minimum": 0 }, "minItems": 1, "maxItems": 12 },
315
+ "width": { "type": "integer", "minimum": 64, "maximum": 800 },
316
+ "status": { "enum": ["pending", "working", "done", "failed"] },
317
+ "error": { "type": "string", "maxLength": 2000 },
318
+ "previews": { "type": "integer", "minimum": 0, "maximum": 12 }
319
+ },
320
+ "required": ["scene", "times", "status"],
321
+ "additionalProperties": false
322
+ }
323
+ },
324
+ "previews": { "access": "read", "description": "Stills the open app rendered.", "images": ["/image"] }
325
+ }
326
+ }
327
+ ```
328
+
329
+ Rules (checked by `fias-dev validate` and at publish):
330
+
331
+ - `data:agents` and the `agentAccess` block go together: declaring the permission without a block is an error.
332
+ - Only collections you declare in `collections`, with `user` or `shared` scope. `read_write` only on `user` scope (a write to a `shared` collection would land in every user's copy), and it needs a `schema` — every agent write is validated against it. `workspace` collections can't be shared with agents yet.
333
+ - Schemas use a restricted JSON Schema 2020-12: `type`, `properties`, `required`, `additionalProperties`, `items`, `prefixItems`, `enum`, `const`, min/max bounds, `anyOf`/`oneOf`/`allOf`/`not`, `title`, `description`, `default`, `examples`, `format` (annotation only), and `$ref` to your own `#/$defs/…`. **No `pattern`** (regular expressions), no `propertyNames`, and no remote `$ref`. `uniqueItems` only on arrays whose `items` have a scalar `type`. A `$ref` may recurse only through `properties` / `items` / `additionalProperties` (a tree), never straight back to itself. ≤ 16 KB per schema, depth ≤ 12. If you generate schemas with Zod, note that `z.record()` emits `propertyNames` and `z.email()` / `z.uuid()` / `z.regex()` emit `pattern` — neither is accepted.
334
+ - Descriptions describe your data — they are not instructions to an AI. The publish review flags text that tells an agent what to do, links, and mentions of other apps.
335
+ - `images` names fields holding `{ "mimeType": "image/png" | "image/jpeg" | "image/webp", "data": "<base64>" }` (≤ 96 KB, ≤ 2000 px a side; every image is fully decoded before an agent sees it, and one that doesn't decode is replaced by an error). Agents receive them as pictures and can never write them — so in a `read_write` collection an image field must be optional, never `required`.
336
+
337
+ What agents can do: **Fias AI** acts as the signed-in user on what you declare. An **external agent** reaches your app only through an API key the user allowed to use it, collection by collection, read or read and change — and if you later share more, nothing new is reachable until the user allows it again. Every agent write is conditional on the version it read, so it can't silently overwrite a change made in your open UI; deletes always need the user's confirmation in Fias.
338
+
339
+ **Your obligation for `read_write` collections: validate what you load.** An agent — or text an agent was shown — may have written it. Treat those documents like any untrusted input; never evaluate or render a field as code or HTML.
340
+
341
+ **Answering an agent while open (previews).** Agents can't run your code, but your open plugin can do work for them through data. Watch a requests collection, do the work, and write the answer back:
342
+
343
+ ```tsx
344
+ const dataStore = useFiasDataStore();
345
+ const answerPending = useCallback(async () => {
346
+ const { documents } = await dataStore.query<RenderRequest>('render_requests', {
347
+ filters: [{ field: 'status', op: 'eq', value: 'pending' }],
348
+ limit: 5,
349
+ });
350
+ for (const req of documents) {
351
+ // Claim it first, so two open tabs never both do it.
352
+ const claimed = await dataStore
353
+ .batch(
354
+ [
355
+ {
356
+ op: 'put',
357
+ collection: 'render_requests',
358
+ key: req.key,
359
+ data: { ...req.data, status: 'working' },
360
+ },
361
+ ],
362
+ {
363
+ preconditions: [
364
+ { kind: 'version', collection: 'render_requests', key: req.key, version: req.version },
365
+ ],
366
+ },
367
+ )
368
+ .then(
369
+ () => true,
370
+ () => false,
371
+ );
372
+ if (!claimed) continue;
373
+ const stills = await renderStills(req.data); // your own code, bounded by your schema
374
+ for (const [i, image] of stills.entries()) {
375
+ await dataStore.put('previews', `${req.key}-${i}`, {
376
+ request: req.key,
377
+ t: req.data.times[i],
378
+ image,
379
+ });
380
+ }
381
+ await dataStore.put('render_requests', req.key, {
382
+ ...req.data,
383
+ status: 'done',
384
+ previews: stills.length,
385
+ });
386
+ }
387
+ }, [dataStore]);
388
+ useDataSubscription('render_requests', answerPending); // changes arrive at most once —
389
+ useEffect(() => {
390
+ // so also check on open and every ~10 s
391
+ void answerPending();
392
+ const timer = setInterval(answerPending, 10_000);
393
+ return () => clearInterval(timer);
394
+ }, [answerPending]);
395
+ ```
396
+
397
+ The agent writes a request, waits on it with `plugin_data_get` (`afterVersion` + `waitSeconds`), and reads the stills back as images. Keep requests bounded in your schema (e.g. `"times": { "maxItems": 12 }`), prune old previews, and report failures in the request (e.g. `status: "failed"` with errors) so the agent can fix what it wrote. **Give both the requests and the results collections `user` scope** — in a `shared` collection any user of your app could plant a "result" that another user's agent then reads.
398
+
399
+ **Testing:** in the dev harness's Fias AI window, the read tools see your local `agentAccess` block against your dev data — ask "what scenes do I have?" to see what an agent sees before you publish.
400
+
286
401
  **Rate limits (per minute):** `put` 120, `get` 300, `query` 60, `delete` 60, `batch` 30, `createCollection` 10
287
402
 
288
403
  **Error handling:** Data store calls can reject on infrastructure errors or limit violations. Always use `try/catch`. Common error codes: `COLLECTION_NOT_FOUND`, `DOCUMENT_TOO_LARGE`, `STORAGE_LIMIT_REACHED`, `RATE_LIMIT`.