live-demo · v2.0.0 · 2026-08-28 · sha256 734253f93d78fee7
live-demo v2.0.0A
Immutable. This exact content is served forever at /api/v1/blob/734253f93d78fee7.
--- name: live-demo version: 2.0.0 description: > Add safe hosted-session runtime to a working robium app: per-visitor instances, a capability-protected gateway, start/status/stop lifecycle, boot logs, fleet budgets, Cloud Run or RunPod drivers, and a Gradio, Lichtblick, or Foxglove viewer handoff. Use when: 'live demo', 'start a private demo instance', 'demo gateway', 'all robots busy', 'host the sim', 'Cloud Run demo', 'RunPod demo', or 'viewer will not connect'. Load after the app smoke test passes; pair with app-publishing for the public project page and article. This skill starts only after robot behavior already works. Not for: planning or building that behavior (architect), website/article composition (app-publishing), developer visualization (foxglove/rviz2), or generic containers (integration). --- # live-demo Everything between a verified app and a safe, temporary hosted session. This skill owns the orchestrator/gateway boundary, per-visitor isolation, runtime state machine, budget behavior, and viewer transport. Public project identity, catalog cards, overview pages, and articles live in `app-publishing`. The core patterns were verified on robium.ai with Cloud Run Robot Navigation (2026-07-13 onward), local Gradio/FastAPI demos (2026-07-15 onward), and the RunPod Pi0.5 demo lifecycle (2026-08). ## When to use this skill - Adding hosted lifecycle to a finished robotics or physical-AI application. - Debugging allocation, claims, readiness, reconnects, viewer handoff, expiration, or teardown. - Choosing Cloud Run, RunPod, or local Docker as a per-session provider. - Cross-references: use `app-publishing` for project pages, articles, cards, shared identity, and publication state; `cloud-run` for the general build and deploy path; `foxglove` for bridge/layout mechanics during development; `integration` for app containers; `testing` for the smoke-test entry bar. ## Key directives - **Delegation posture: embed + links.** The session gateway, lifecycle split, and demo-specific provider tuning were derived from real deployments and live here. General provider and viewer mechanics delegate to `cloud-run`, `runpod`, `foxglove`, and upstream documentation. - **The demo smoke extends the product surface.** <!-- id: demo-smoke-extends-product-surface --> Gate the hosted scenario with `make demo-smoke`: gateway claim, readiness, foreign-session rejection, one real scripted outcome, and teardown. A process-health probe alone is not a demo test. - **One visitor, one instance, enforced by capability.** <!-- id: one-visitor-one-instance-gateway-enforced --> The orchestrator returns an opaque instance ID/capability. The gateway claims that session and rejects foreign access. Never depend on provider routing or an unguessable hostname as the isolation boundary. - **Lifecycle outlives the instance.** <!-- id: lifecycle-needs-host-level-orchestrator --> A gateway inside a container cannot start or delete its own host. A host-level orchestrator owns allocation, provider selection, fleet caps, expiration, and teardown; after allocation, the browser talks directly to the protected gateway. - **Scale-to-zero and cost are explicit.** <!-- id: scale-to-zero-non-negotiable-explicit-cost --> Cloud Run uses `min-instances=0`; GPU sessions have an absolute lifetime and daily/hourly budget. The UI states cold-boot time, capacity, remaining session time, and busy/budget states honestly. - **No allocation before an explicit visitor action.** <!-- id: never-allocate-on-page-load --> Catalog, overview, and idle live pages use static facts. Start is the cost boundary. ## Quick start 1. Add one app-side demo entrypoint: simulator/policy + viewer service + readiness signal + the session gateway that owns `$PORT`. 2. Declare the existing `demo.orchestrator` contract in `robium-app.yaml`: image, command, gateway port, readiness log, provider, environment, resources, session duration, and fleet/budget limits. The website orchestrator derives its registry file from this source. 3. Implement the host-level driver behind the existing Driver seam. Local Docker is the cheapest lifecycle probe; use the cloud provider only for behavior that cannot be reproduced locally. 4. Connect the browser state machine described in `references/session-ui.md`: allocate, claim, poll, reconnect, render the viewer only when ready, and stop/delete. 5. Run the app's `make demo-smoke`, the orchestrator tests, and the local start-to-delete lifecycle before enabling production capacity. For the verified ROS/WebSocket gateway shape, adapt `examples/demo_gateway.py` (status: verified 2026-07-13). A Gradio app uses the same lifecycle endpoints and mounts Gradio behind its capability-aware gateway. ## Usage patterns **Choose the provider.** | Provider | Use when | Main constraint | | --- | --- | --- | | Local Docker driver | Frontend/lifecycle development and CPU smoke | Not public; one host's resources | | Cloud Run | CPU-heavy or ROS/sim containers that can boot from an immutable image | No UDP multicast; CPU/billing mode matters | | RunPod | Large pinned GPU model and attached model volume | Paid allocation, regional GPU/volume availability, deletion certainty | Provider-specific launch syntax belongs in the matching provider skill. Keep the browser/orchestrator contract provider-neutral. **Choose the viewer adapter.** | Viewer | Runtime handoff | When | | --- | --- | --- | | Gradio | Capability-scoped `/ui` URL in an iframe or supported web component | Model/policy inputs and outputs | | Self-hosted Lichtblick | Capability-scoped websocket URL + bundled layout | Public ROS visualization without login | | Foxglove deep link | `foxglove-websocket` URL opened in a new tab | Zero viewer hosting; login acceptable | | Custom | App-specific capability URL | The interaction cannot fit the common adapters | The live shell is shared; only URL formation and viewer rendering belong in the adapter. Project tabs, overview, guide, and visual identity are owned by `app-publishing`. **Instance lifecycle contract.** <!-- id: instance-lifecycle-gateway-contract --> The proven gateway shape is: `POST /start?session=U` claims; `GET /status?session=U` returns `claimed/ready/remaining_s/log[]` plus app metrics; foreign sessions return 409/403; a protected viewer/websocket route serves only the current capability; orchestrator deletion is the authoritative stop. The gateway may expose `/shutdown` for direct/local mode, but cloud lifecycle stays outside the container. See `references/gateway-pattern.md`. **Orchestrator response.** Return an opaque instance ID, lifecycle phase, message, expiry, and protected host/capability only when allocated. The UI polls the orchestrator through allocation/boot/deletion, then claims and polls the gateway when a host exists. See `references/orchestrator-pattern.md`. ## Platform gotchas - **Gazebo discovery needs help on Cloud Run.** <!-- id: gazebo-discovery-cloud-run-boot-watchdog --> There is no multicast; use loopback relay settings and a boot watchdog that terminates a sticky failed boot so reconnect can land on a fresh instance. - **Hand-written HTTP responses declare `Connection: close`.** <!-- id: connection-close-header-required --> Cloud Run's proxy pools connections; closing without the header can surface as an edge 503 malformed response. - **ROS 2 launch as PID 1 stops on SIGINT, not an assumed SIGTERM.** <!-- id: sigint-not-sigterm-for-ros2-launch-pid1 --> Verify the actual entrypoint signal behavior before using shutdown as a test. - **Cloud Run affinity is same-site.** <!-- id: session-affinity-cookies-samesite-lax --> Map the demo service under the site's registrable domain and use credentialed exact-origin requests; cross-site `run.app` cookies will not preserve the intended affinity. - **Request-based CPU throttling can freeze boot.** <!-- id: request-based-billing-cpu-throttle-needs-no-throttling --> A start-button flow with no held request needs instance-based CPU allocation; a websocket-held flow may use request-based billing. State the cost. - **FastDDS shared memory is unsuitable in Cloud Run.** <!-- id: fastdds-shm-misbehaves-cloud-run --> Restrict the demo container to UDPv4 and solve discovery separately. - **Concurrent instances need distinct ROS domains.** <!-- id: concurrent-instances-domain-id-collision --> The orchestrator assigns an available domain; a manifest's fixed development value must not merge public sessions. - **A single local instance cannot reroute a rejected claim.** <!-- id: single-instance-503-needs-abortable-takeable-claims --> Make claims takeable, runs abortable, and lock acquisition bounded so refresh does not orphan a Gradio job and deadlock the next session. - **Poll through the current host/capability.** A host chosen after allocation must live in a ref or equivalent current-state cell; an interval that closes over the initial empty host will poll the wrong backend forever. ## Customization - Readiness is app-specific: ROS navigation may require the initial pose and a measured real-time factor; a policy demo may require the checkpoint, env, and first frame. Keep the lifecycle fields stable and add app metrics rather than changing the common state machine. - A disabled production demo can keep its overview, guide, recorded proof, and local path. Disable allocation in site-owned publication/config state; do not rewrite the app's hosted capability as false. - CPU-only policy images should install CPU PyTorch wheels; default wheels can pull an unused multi-GB CUDA stack. GPU images pin model/runtime compatibility and use immutable image/model revisions. ## References - `references/gateway-pattern.md`: claim, status, protected transport, readiness, shutdown, and watchdog contract. - `references/orchestrator-pattern.md`: provider-neutral allocation/deletion, Driver seam, per-instance ROS domain, and local development loop. - `references/cloud-run-tuning.md`: verified demo-specific Cloud Run resource, networking, affinity, and billing behavior. - `references/session-ui.md`: shared browser lifecycle and honest state/copy contract consumed by the publishing layer. - `examples/demo_gateway.py`: verified ROS/WebSocket gateway reference (production Robot Navigation lineage, 2026-07-13). - Upstream: [Cloud Run docs](https://cloud.google.com/run/docs), [Foxglove deep links](https://docs.foxglove.dev/docs/visualization/shareable-links), [gz-transport relay](https://gazebosim.org/api/transport/14/relay.html), [Lichtblick](https://github.com/lichtblick-suite/lichtblick), and [Gradio embedding](https://www.gradio.app/guides/sharing-your-app). Sibling skills: `app-publishing`, `cloud-run`, `runpod`, `foxglove`, `integration`, `testing`, and `environments`. ## Changelog <!-- One dated line per battle-tested change, added by skill-author hardening sessions. --> - 2.0.0 (2026-08-28): re-scoped around hosted runtime lifecycle, gateway, provider, capacity, and viewer handoff. Public project identity, overview, article, catalog, and reusable publishing composition moved to the new app-publishing skill; added the shared session-UI contract derived from the ACT/PushT workspace refactor. - 1.3.3 (2026-08-03): style pass; removed em dashes throughout (no content changes). - 1.3.2 (2026-08-01): decision-table rows anchored (learning-engine Phase 1 follow-up); no content changes. - 1.3.1 (2026-08-01): anchor IDs added to claim-bearing items (learning-engine Phase 1); no content changes. - 1.3.0 (2026-08-01): Cloud Run deployment mechanics delegated to the new cloud-run skill while this skill retained demo-specific tuning. - 1.2.0 (2026-07-31): absorbed local single-instance Gradio claim/deadlock behavior and the Gradio/FastAPI gateway shape from manipulation trials. - 1.1.1 (2026-07-15): refreshed production domains for robium.ai. - 1.1.0 (2026-07-13): added the host-level orchestrator pattern and local/cloud Driver seam from the production navigation demo. - 1.0.0 (2026-07-13): created from the production navigation live demo.