|
179 | 179 | "type": "array", |
180 | 180 | "items": { |
181 | 181 | "type": "object", |
182 | | - "required": ["id", "title", "cron", "prompt"], |
| 182 | + "required": ["id", "cron", "prompt"], |
183 | 183 | "additionalProperties": false, |
184 | 184 | "properties": { |
185 | | - "id": { "type": "string", "pattern": "^[a-z0-9_-]+$" }, |
186 | | - "title": { "type": "string" }, |
187 | | - "cron": { "type": "string" }, |
188 | | - "prompt": { "type": "string" }, |
189 | | - "assetIds": { "type": "array", "items": { "type": "string" } }, |
190 | | - "runAs": { "type": "string", "pattern": "^[a-z0-9_-]+$", "description": "Role slug to scope the run's layer permissions. References a `roles[]` slug or built-in (owner|editor|viewer). Defaults to owner-attribution." }, |
191 | | - "enabled": { "type": "boolean", "default": true }, |
192 | | - "checks": { "type": "array", "items": { "$ref": "#/$defs/check" } } |
| 185 | + "id": { "type": "string", "pattern": "^[a-z0-9_-]+$" }, |
| 186 | + "title": { "type": "string", "description": "Optional display name. Defaults to `id` titlecased." }, |
| 187 | + "cron": { "type": "string", "description": "Standard 5-field cron expression with optional `TZ=<IANA>` prefix. Examples: `0 6 * * *` (UTC daily 06:00), `TZ=Europe/Berlin 0 6 * * *` (Berlin local time, DST-aware). The cron string is the recurrence rule — `next_run_at` is derived on the DB row, never duplicated here." }, |
| 188 | + "prompt": { "type": "string", "description": "The user-input prompt that fires on each tick. Lives directly on the schedule template — no separate phantom prompt_user call. The scheduler reads this at fire time and seeds a real prompt_user call on the freshly-minted child run." }, |
| 189 | + "anchors": { |
| 190 | + "type": "array", |
| 191 | + "description": "Optional explicit input attachments. Each entry is an `AnchorRef` (scenecast canonical shape: `{ asset_id, anchor? }`). When omitted/empty, the scheduled run inherits the scene's default context (all visible assets). When present, behaves like a user pre-selecting these elements in the iOS composer before tapping Run — identical wire format. `asset_id` may be a blueprint-local handle (resolved by the applier) or a real db id.", |
| 192 | + "items": { |
| 193 | + "type": "object", |
| 194 | + "required": ["asset_id"], |
| 195 | + "additionalProperties": false, |
| 196 | + "properties": { |
| 197 | + "asset_id": { "type": "string" }, |
| 198 | + "anchor": { "type": "string", "description": "Optional sub-element selector in scenecast anchor grammar: `item[<id>]`, `row[<idx>|<id>]`, `field[<key>]`, `step[<id>]`, `metric[<id>]`, `zone[<name>]`, `object[<id>]`, `surface[<id>]`, `point[<x>,<y>(,<z>)]`. Omit to address the whole asset." } |
| 199 | + } |
| 200 | + } |
| 201 | + }, |
| 202 | + "runAs": { "type": "string", "pattern": "^[a-z0-9_-]+$", "description": "Role slug to scope the run's layer permissions. References a `roles[]` slug or built-in (owner|editor|viewer). Defaults to the scene's owner-attribution." }, |
| 203 | + "tools": { "type": "object", "additionalProperties": false, "properties": { "allow": { "type": "array", "items": { "type": "string" } }, "deny": { "type": "array", "items": { "type": "string" } } }, "description": "Optional override of the scene's tool allow/deny. Omit to inherit scene defaults." }, |
| 204 | + "enabled": { "type": "boolean", "default": true, "description": "Cron only fires when true. Use false to pause without deleting the template." }, |
| 205 | + "checks": { "type": "array", "items": { "$ref": "#/$defs/check" }, "description": "Per-run success criteria evaluated against the completed run." } |
193 | 206 | } |
194 | 207 | } |
195 | 208 | }, |
|
250 | 263 | "required": ["role"], |
251 | 264 | "additionalProperties": false, |
252 | 265 | "oneOf": [ |
| 266 | + { "required": ["principal"] }, |
253 | 267 | { "required": ["email"] }, |
254 | 268 | { "required": ["device"] } |
255 | 269 | ], |
256 | 270 | "properties": { |
257 | | - "email": { "type": "string", "format": "email" }, |
| 271 | + "principal": { |
| 272 | + "type": "string", |
| 273 | + "pattern": "^[a-z0-9_-]+:.+$", |
| 274 | + "description": "Canonical principal in '<provider>:<identity>' form. Examples: 'github:mirkokiefer', 'github:315252' (numeric id, rename-proof), 'email:foo@bar.com', 'google:<sub>', 'apple:<sub>'. The provider prefix is the auth-provider slug; identity is unique within that provider. Use this form for new blueprints — it scales to any auth provider including asset-provider-auth (e.g. 'slack:U07ABC'). `email` and `device` below remain as legacy aliases." |
| 275 | + }, |
| 276 | + "email": { "type": "string", "format": "email", "description": "Legacy alias for principal 'email:<addr>'. Resolves only against email-auth users." }, |
258 | 277 | "device": { "type": "string", "pattern": "^[a-z0-9_-]+$", "description": "Device slot slug. Provisioning binds physical devices to slots out-of-band (e.g. eFuse pubkey registration)." }, |
259 | 278 | "role": { "type": "string", "pattern": "^[a-z0-9_-]+$", "examples": ["owner", "editor", "viewer"], "description": "Built-in (owner|editor|viewer) or a custom role slug declared in `roles[]`. Anonymous public access is declared on the role itself via `roles[i].public: true`, not on a member entry." } |
260 | 279 | } |
|
0 commit comments