--- name: uru-gems description: Build, revise, publish, or operate an interactive or hosted Uru Gem. --- # Uru Gems A Gem is shipped work. It can be a small interactive view, a static experience, or a hosted application with server code. Use file-specific Skills for a normal deck, document, sheet, image, or PDF. Use a Gem when the output needs an interactive or hosted runtime. ## Core model Keep these states separate: - **Current** is the editable source tree. - An **Edit** records one coherent source change. - A **Version** freezes a selected source revision, saved `preparing` before its Build runs. - A **Build** compiles and checks that revision; the Version becomes `ready` only after its Build succeeds. - A hosted **Release** deploys one ready Version. - A **Share** decides who may open the Gem and which ready Version it serves. It can stay on one Version or follow later ready Versions. "Link" names only the URL a person opens. - Each **schedule or event rule** selects its own Release for future jobs. It keeps that target when a Share changes. Changing Current does not change a Share. Saving a Version does not publish it. Move a Share only after checks pass. ## Tools and source Use `gem_query` for reads and validation, and `gem_control_plane` for source, build, Version, Release, and runtime changes. Read [operation fields](references/operations.md) for the operation you need. Shares use the share ops every Library item uses: `library_collab` for writes and `sharing_query` for reads. Call `api_describe` before `call_query`, `call_action`, or `job_start`; use declared names and returned input shapes without inventing either. Use `library_fs` only to organize or trash the Gem root, not for child files. Every Gem has one root `uru.json` that declares source intent. Uru selects its runtime resources. Before authoring or changing framework, serving, library, or server intent, read [source authoring](references/authoring.md). Use the linked `uru.json` reference there for exact fields. ## Git-backed Gems A Git-backed Gem has a workspace-authorized source binding. The provider's repository and exact commit are the source of truth for that Gem. Use the Git source operations in the platform operation reference so the tool and CLI paths reach the same authority checks and durable state. Use `gem_query` for Git source reads: - inspect a repository before import; review the exact commit SHA, candidate Gem roots, resolved `uru.json`, source bounds, diagnostics, and resource needs; - read source status, current and ready commit identity, policy, import stages, preview state, operation IDs, and refusal reasons; - inspect an exact branch or fork preview head before approval, then open it only after its detached build is ready. Use `gem_control_plane` for Git source changes: - begin and complete the opaque GitHub setup continuation, list authorized repositories, poll setup, and import only the inspected commit; - refresh the bound ref, retry or cancel one exact import operation, change the source policy, disconnect the binding, or make a private editable copy; - inspect a branch head before creating its private branch preview, and inspect a fork preview's exact head and resource policy before approving it. The Git source operation names are `git_source_connections_list`, `git_source_connection_poll`, `git_source_inspect`, `git_source_status`, `git_source_preview_inspect`, and `git_source_preview_open` in `gem_query`; `git_source_setup`, `git_source_connection_callback`, `git_source_import`, `git_source_command`, and `git_source_copy` in `gem_control_plane`. `git_source_copy` is its own operation, not a `git_source_command` action, because it answers with a different Gem rather than with this Gem's state. It takes no version argument: the server copies the latest Version the importer saved. A linked Gem with no saved Version yet is refused with `git_source_no_admitted_version`. For an already connected source, the CLI uses the same source authority with `uru gems source status`, `refresh`, `retry`, `cancel`, `policy`, `change-source`, `disconnect`, and `copy`. Pass the Gem path or ID where the command accepts it. `retry` and `cancel` both require `--import-id`; `retry` also takes the optional `--idempotency-key`. `cancel` and `disconnect` also require `--yes`. The import response is an operation result, not proof that a Gem is ready. Keep the returned operation and artifact identities, then read status until the actual stage is `ready`, `needs_access`, `needs_configuration`, `needs_resource_grant`, `failed`, `canceled`, or `superseded`. A `ready` import can also carry `resourceReviewRequired: true`. That commit changed the resources the Gem needs, so Uru does not prepare or publish commits with those needs by itself. Tell the user, and let the owner decide. `change-source` records every request in the head's `uru.json` as reviewed, closes open previews, and builds that head again. The owner reviews the needs in the Source tab's Settings and grants the access in Connections. A retry names the original import or attempt and carries a fresh idempotency key for that user intent. The CLI accepts `--idempotency-key`; when it is omitted, it creates a UUID. A ref can move after an import, so retry uses the recorded exact commit rather than silently following the ref. Branch previews use the existing repository inspection first, then create a detached preview for the reviewed branch and commit. Fork previews require a new exact-head review when the fork moves. Approval includes the reviewed resource-policy hash. Preview builds cannot write the Gem's Current source, production source binding, production secrets or data, Releases, or Shares. Preview URLs are private, short-lived, and revoked or expired with the preview. Git source files are read-only through the regular Gem editor and source operations. `uru push`, editor writes, agent edits, source restores, patches, syncs, and other in-place writes return the shared refusal for a bound Gem. Use the Git provider to change the source. Use `git_source_copy` (CLI: `uru gems source copy`) when you need an unbound private Gem to edit. The copy is made from the latest saved Version, never from a live GitHub read, so it still works after the branch is deleted or access is lost. It does not inherit credentials, resource grants, schedules, live Shares, or the Git binding; it records only which Gem, commit and Version it came from. The lifecycle remains explicit: admitting a Git commit atomically creates an Edit and saves its normal Version; an asynchronous Build then builds that Version; a hosted Release prepares it under the source and resource gates; a Share advances only after the Release and publishing policy allow it. Failed preparation keeps the last valid served Version available. A pinned Share stays on its selected Version, while a Share that follows the Gem advances only when a later Version passes the same gates. Use the normal Version, Release, and Share operations for promotion, rollback, and verification. ## Build workflow 1. Search the Library before you create a Gem. 2. Inspect an existing Gem before a change. 3. Create the Gem with `gem_control_plane` and `op="init"`, passing the whole starting source tree in `files`. `init` takes the smallest complete tree in one call; it does not need a separate write pass. If `files` carries no `uru.json`, `init` writes one for you from the entrypoint you named — so supply your own root only when you need intent the default cannot express, such as a non-default `framework` or `servingMode`. 4. Add later source with `op="fs_write"`, `op="fs_batch_write"`, or `op="fs_sync"`. Each successful call is one Edit. New paths need `create=true` on `fs_write`; without it the tool refuses a missing file rather than creating one. Use `fs_batch_write` for source and `uru.json` changes that belong together. Use the inspected revision and hash for `base_source_revision_id` and `base_source_hash`. If either changed, read Current again and preserve the newer edits. 5. Validate with `gem_query` and `op="validate"`. The call returns `hosted_job_id` immediately and never creates a durable Build. Poll `gem_query` `op="build_job"` with that id until `status` is `succeeded`, `failed`, or `expired`. Then inspect. Validation does not accept `force`. 6. Build with `gem_control_plane` and `op="build"` the same way: enqueue, poll `build_job`, then inspect. Pass `force=true` only to rebuild. A ready Build may return `status="succeeded"` with `build_id` and no new job. 7. Fix diagnostics until the intended behavior works. 8. Run a meaningful browser or output check. Use [browser checks](references/browser-checks.md); an HTTP success alone does not prove that a JavaScript Gem renders. 9. Save a Version with `op="version_save"`. The call queues the Version's Build; it does not wait for it. Poll `gem_query` `op="version_get"` until `lifecycle_state="ready"` and `build_id` is set. If it fails, read the diagnostics. Use `op="version_retry"` to retry that saved source after correcting a temporary build or resource failure. If the fix changes source, edit Current and save a new Version. Repeating `version_save` for unchanged Current returns the same failed Version. `version_retry` always uses that Version's saved source, for both Uru and GitHub Gems. 10. For publishing, read [publishing and rollback](references/publishing.md). Create a Release with `op="release_create"` when the runtime needs one. 11. Share the Gem with `library_collab` and `op="share_create"`, naming the Gem by its Library `path`. A viewer Share (the default `kind`) lets people open it: name `people` to give each person their own URL, or leave it out for one anyone URL. `audience={"organization":true}` or `audience={"workspace_ids":[…]}` lets members sign in to open it instead. A new viewer Share follows the Gem: each later ready Version serves automatically, so step 11 happens once, not after every edit. Pass `version={"mode":"pinned","version_id":""}` to pin it instead, and use `op="share_update"` only to move a pinned Share or to roll back. An editor Share (`kind="editor"`, `people` required) lets each person sign in and change the Gem from their Library. It has no URL. It lends the editors only the connections, Datasets and secrets named in `consents`; change them later with `op="share_set_consents"`. Read [Shares](references/publishing.md#shares) first. Every Share write needs an `idempotency_key`. A write that answers `gem_share_route_pending` is saved; retry it with the same key. 12. Verify the published result. Do not stop after file upload. Leave the Gem in a clear, inspectable state. ## Size rules Source has two ceilings. One file may be 5,000,000 bytes. A whole Gem may be 25,000,000 bytes across 400 files. Where a picture goes depends on the framework: - For `single_file_html`, `static_site`, `vite_react`, `tanstack_start`, or `server_function`, write the picture as a real file under `public/` and send its bytes with `content_base64`. Never paste picture bytes into code. - For a single-file `react` Gem, put the picture in the code as a `data:` URI. That framework compiles one client bundle and serves no `public/` files, so a file written there is never fetched. Count the cost before you write: - Base64 makes a file 1.33x bigger. A 3,000,000-byte photo costs 4,000,000 characters of source. - Keep any one picture under 500,000 bytes. A phone parses a bundle 2 to 5 times slower than a laptop, and the bundler warns at 512,000 bytes. - Never put video or audio in Gem source. Put the file in the Library, or take it at run time with an upload. ## Data, tools, and credentials - Read `uru-datasets` for Dataset data and the Dataset SDK. - Declare each Dataset in `uru.json`. - Keep Dataset writes disabled unless the Gem must write. - Declare tool needs as logical roles and live operation keys. Get the `integration` and `operations` values from the selected action's `gemDeclaration`. Read [tool setup](references/uru-json.md#tool-discovery-to-gem-calls) for the complete search, declaration, account binding, and Gem call example. Do not copy an Executor path, `act_*` name, or service label into source. - Match each role to the provider account and owner the user named. Check the workspace, adoption, and allowed operations. Ask the user to choose if more than one connection fits. Do not select one by list order or provider name. - For `gemDeclaration.binding.kind="connection"`, bind the role to that exact connection before the build. For `kind="platform"`, use the returned `binding.role`; the build resolves it without an account choice. Uru resolves the current enabled capability, access witness, approval policy, and risk at the build and again at execution. No connector family has a coded allowlist. Calls that need different accounts must use separate roles, even when the provider and operation names match. - A Gem has ONE set of tool bindings and ONE set of secret values. Its preview builds and its releases use them alike. Bind a role once, and every build and every deploy of that Gem resolves it. - To bind a role, call `gem_query` `op="inspect"` with `include_binding_choices=true`. Send the returned `tool_role_binding_choices.expected_binding_set_version`, `tool_role_binding_choices.expected_binding_set_hash`, and a selected `tool_role_binding_choices.available_connections[].connection_ref` per connection role back through `gem_control_plane` `op="upsert_binding"`. The `binding_choices` map is a complete replacement: keep every role you still want. Never send a raw connection id. - Keep an existing generic tool target exactly as returned by Gem inspection. New tool roles use the reviewed `binding_choices` map above. A direct action call name is not a binding target. Do not build a target from account labels, descriptions, schema versions, or fingerprints. - Do not send `environment_key` to `upsert_binding`, `inspect`, `store_secret` or `delete_secret`. There is one binding set, so the parameter is refused. - Do not ask the user for an Uru key or hosting-provider key. - Never write secret values into source. - Declare a custom secret only when the application needs a server secret that Uru cannot supply through a resource connection. Before a build, inspect and bind each connection role. Native platform roles resolve at build without an account choice. After the build, inspect unresolved bindings. Use the returned continuation or binding operations. Do not invent connection ids, integration keys, or operation keys. After a reconnect or account change, confirm the provider account and workspace before you replace the binding. Capabilities use Gem-local names. A query, action, or tool job that calls a tool uses `toolRole` and `operation`; the role and operation must already be declared by the selected binding. A job may also carry a `schedule`, but an action or query may not. A job can also run code shipped in the Gem. A program job uses this shape: ```json { "handler": { "module": "src/jobs.ts", "export": "syncOrders" }, "input": { "source": "orders", "batchSize": 100 }, "schedule": { "cron": "0 9 * * *", "timeZone": "America/Chicago" } } ``` The handler module is a root-relative source path. The export is the named program entry point. Uru packages the handler into the published Gem and runs each attempt in an isolated machine. The handler receives its runtime environment, the saved input, the last checkpoint, and an abort signal. Create the server context with `createUruServerContext(env)`. Use `context.jobs.progress(...)` for bounded progress and `context.jobs.checkpoint(...)` for bounded resume data. Do not put secrets or source rows in either value. Each run keeps its selected deployment and Release. A later Release affects future starts only. Keep the `request_id` from an action or job call. The job result may return `deployment_id` and `executionId`. Send these as `deployment_id` and `execution_id` to `job_status`. Use `executionId` as `execution_id` with `job_cancel`. Get a durable `run_id` from `runs_list` before using `run_cancel`. Read [runtime controls](references/runtime-controls.md) for ID use, retries, and recovery. Dataset V2 is the current Dataset contract. Keep Dataset IDs stable and use server-side pages, filters, totals, and aggregates. A declared query in `capabilities.queries` needs an `upsert_binding` with `source_ref_type=query` (and the Dataset or other source ref) before `release_create` will admit that capability. A Dataset bound only as a resource role is not enough for a named query. ### Accepting a file from the user A Gem that declares `storage` can also accept a file. Use it when the Gem needs the user's PDF, image, or recording. Do not send file bytes through a query, an action, or `uru.storage`: those carry JSON only, and the runtime refuses a body above 100 KB. Call `createUruUploadsContext` from `@uru-intelligence/app` and use `uploads.upload(file)`. It asks Uru for a grant, sends the bytes straight to object storage, and returns the platform's own verdict. Handle every verdict: - `verified` — the file is stored, and `sizeBytes` is the size Uru measured. - `pending` — nothing has arrived yet. The grant is still open; ask again. - `rejected` — the object did not match the grant. It has been deleted. - `expired` — the window closed. Ask for a new grant. The limits are 100 MiB for one file, 1 GiB stored per Gem environment, and ten open grants at a time. A grant works once. Uru derives the object key and the link lifetime; the Gem names only a filename, a media type, and a size. Uploads and `uru.storage` share one switch. Turning `storage` off with `capability_set_enabled` closes both. ## Operating an existing Gem For capabilities, program jobs, schedules, runs, domains, runtime state, or Release retries, read [runtime controls](references/runtime-controls.md). For publishing or rollback, read [publishing](references/publishing.md). Keep build, runtime, permission, quota, and Share failures visible. ## Stop rules - Do not use retired Gem authoring tools or metadata blocks. - Do not write internal runtime fields. - Do not put credentials in source or logs. - Do not use old Dataset tools or SDK calls. - Do not add wrapper, sub-tool, connection-id, provider-route, or fixed connector-catalog fields to `uru.json`. - Do not add Draft, Patch, or Version-window state. The root `uru.json` is the only source-intent file. - Do not use `ssr` as a serving mode. It is rejected by the v2 authoring contract. - Do not publish a failed or unverified Version. - Do not hide a failed Build, Release, run, or Share change. - Stop after a conflict. Inspect Current, the target Version, and the Share before retrying. - Retry the same saved source with `op="version_retry"`. Save a new Version after a source fix. Use `op="release_retry"` for a failed Release.