Existing-app integration
A complete workflow for agents working in an existing codebase.
Before the first implementation, follow the Domino skill's existing-app campaign confirmation procedure. Ask for missing campaign basics, prepare the campaign and integration proposal, and obtain the owner's confirmation. Preserve the app's current design and components; brand discovery and visual approval are not prerequisites. Reuse an already confirmed brief in later sessions.
Inspect the app's framework, package manager, workspace boundaries, authentication, and deployment scripts. Identify where the requested participant experience belongs. Keep its repository, UI conventions, login, and hosting.
Use the Domino project selected by the user. If no remote project exists, create it in Console. domino create provisions a hosted repository and is not the existing-app integration path.
Use the project ID returned by Console. Domino assigns it when the project is created; the project name is a separate display label. Do not invent a project ID or derive it from the name.
From the intended package or project root, run domino init --project <id> to create relay.json and RELAY.md. Init verifies access and does not install packages or generate sample quests. If these files already exist, inspect the existing connection and continue from it. Init deliberately refuses to overwrite them.
Run domino agents install to register package-backed skill loaders for both Codex and Claude, or select one with --agent codex or --agent claude. It adds a marked guidance section to AGENTS.md and, for Claude, a pointer in CLAUDE.md while preserving existing project instructions. The loaders read node_modules/@domino-sdk/relay-cli/cli/skills/domino/SKILL.md; install the project-local CLI and dependencies first. Shared guidance follows the installed CLI version, so upgrades only require the agent to re-read the bundled skill.
For a project with copied skills, run the upgraded CLI's domino agents install once. Known unmodified copies become loaders, and existing reference links receive redirects to the package. If the installer names a customized skill or reference, move its project-specific rules into AGENTS.md, then replace that reported file with the corresponding file from the project-local CLI's cli/skills/domino directory and rerun installation. Preserve the custom rules before replacing anything. If a marked Domino section in AGENTS.md or CLAUDE.md was edited, move custom rules outside that section, remove only the marked section, and rerun installation. The installer checks all selected destinations before writing and supports retries. It does not fetch guidance from the network or change dependencies.
Add the SDK to the package that owns the authored modules using the app's package manager and an available Domino package distribution. Resolve SDK imports there before adding quest entries to relay.json. Quest files can follow the existing source layout.
For participant UI, inspect the installed @domino-sdk/relay and @domino-sdk/relay/browser exports. Use the supplied quest controllers for submissions, recovery, and changed rules. Keep authored quest keys and collection slots stable. Participants explicitly review changed rules before resubmitting.
Keep the application's existing login using createParticipantBackend on its server. Read participant authentication and routing for the complete route example. Implement authenticate(request) using the app's existing server session verifier and return its stable user ID. Never accept a user ID from browser input as proof of identity.
An organization administrator creates an identity integration in Console under Settings → App login keys, for the selected project and environment. For a Domino-hosted app, Console's "Also save it as an app secret" box (checked by default, needs publish) stores the new key as the app secret APP_IDENTITY_KEY in the key's environment, and Add secret on a connected app replaces it the same way; the app reads it from its next build. Otherwise the user saves the shown key directly in the application's server secret settings as APP_IDENTITY_KEY. A shown key is shown once; keep it out of agent chat, source control and browser bundles. CLI and personal management credentials cannot create, rotate or revoke these keys, or substitute for them. An organization administrator's CLI session can list them: domino identity-integrations list --json gives each key's origin, identity kind and secrets' expiry and last use, never a secret. Hand off this way: (1) the owner creates the key in Console, which for a Domino-hosted app also stores it; (2) otherwise the owner stores it without pasting it into chat, with printf %s "$KEY" | domino secrets set APP_IDENTITY_KEY for a Domino-hosted app (--environment live for the live app) or the app's own secret settings; (3) the agent confirms with domino identity-integrations list and domino secrets list. domino secrets set checks a di_ key before storing it and names its key in identityIntegration; it stores nothing and exits 2 with INVALID_ARGUMENT when the key is unknown, expired or revoked or belongs to another project or environment, and warns (storing it) when the key's origin is not the app's own address for that environment or the check cannot run. A key signs members in only in its own environment: a staged app runs in Test and needs a Test key registered for https://<project-slug>--staging.domino.page; the live app needs a Live key for its live address or custom domain. Creating a key for a domino.page staging or preview address in Live, or a live <project-slug>.domino.page address in Test, is refused with 400 invalid-request naming the right environment; other origins can use either. The origin must be exact (no path, query or trailing slash; the refusal names the origin it accepts). Pass onExchangeError(error, request) to createParticipantBackend to log each refused exchange on the server (ParticipantExchangeError: status, code, Domino's message, retryAfter); the browser still gets the general message for anything but a 409 or ACCOUNT_VOUCHING_OFF. inspectIntegrationKey({ baseUrl, integrationKey }) from @domino-sdk/relay/portal-proxy answers the same check from a server. Readiness requires the deployed API and SDK versions supporting identity-exchange; a legacy 404 is an upgrade issue.
Mount the adapter at /relay/* and use createBrowserRelayClient({ baseUrl: "/relay" }). Verify a signed-in session, one participant action, and that logging out of the application removes access. The adapter checks application authentication on every request and derives project scope from the integration key. No custom fetch wrapper or browser project headers are needed. When the app signs in or out without a full page load, call await useSession().refresh() after its own sign-in succeeds and before rendering member pages, since RelayProvider keeps the signed-out session it read on load, and again after the app's own logout clears its session, which drops the member's data. Sign out through the app only, not useSignOut(): while the app session lasts, the provider's next read signs the member back in. See existing application login for the snippet, and verify both without reloading.
Read authoring when adding quests or collection slots. Run the app's normal checks and development server. Use its existing preview deployment process when available. domino deploy publishes Domino behavior; it does not deploy the app. Register participant offers in relay.json's offers list; build, check and deployment summaries include the number of offers in the authored bundle. Register ongoing content rewards under engagement in relay.json. Their tracker, qualifying quest, and points balance can publish in the same transaction. Preview reports new, unchanged, and changed formulas, and each quest as created, updated or unchanged (questChanges); an unchanged quest keeps its release. Before publishing, check that only the quests you meant to change are updated. Resume the saved deployment ID to publish or recover its receipt. Publishing resends a request whose answer was lost, at most three times in all within 30 seconds, so resume only after domino deploy exits 3 with OUTCOME_UNCERTAIN. When other worktrees or agents deploy the same project, publish only the quests you changed with domino deploy --only <quest-key> (repeatable); the rest stays as published. domino stage builds a commit of a Domino-hosted repository whose relay.json app is a static or worker app, so it is not a general deployment command for existing apps.
When upgrading an existing integration, run domino migrate to inspect authoring changes, apply them with domino migrate --write, and run domino check --json. Keep each existing authoring identity value while renaming id to key; do not recreate projects or replace stored IDs. See authoring upgrades for diagnostics and manual cases.
Add text and URL controls
For text or URL quests, upgrade the Relay SDK and render the corresponding interaction before adding text and url to supportedInteractions in relay.json. Text uses a textarea; URLs use a URL field. Read required, length and allowed-host constraints from the manual trigger, and send values through relay.quests.open(view). Keep interrupted submissions resumable after reload. See submission controls. The new campaign starter includes these controls; existing apps keep their current declared interactions until upgraded.