AI-Assisted Setup
A compact spec for AI agents scaffolding uRun Python backends
This page is a dense, copy-ready reference for AI coding agents producing uRun Python apps. Everything here reflects the shipped urun library and urun-cli. For a human walkthrough, see Getting Started.
Mental model
uRun's product primitive is a real-time session. A deployed @app.function is invoked by name from a browser; the call returns a session with named media streams and a synced control doc. The same decorator also runs one-shot and distributed GPU work.
Five concepts: App (container), Function (@app.function), GPU spec (gpus=), Store (models/data), Dependencies + Credentials (remote environment).
An agent should produce a single Python file with one App, one or more @app.functions, a Dependencies declaration, and optional Credentials.
API patterns
App + imports
import urun
from urun import App, Context
from urun.core import Dependencies, Credentials
app = App("my-app")Function config (decorator kwargs are fixed at deploy)
@app.function(
gpus="b200:1", # "{type}:{count}" — see /docs/python-sdk/reference/gpu-specs for all types; or an int; omit for CPU-only
deps=DEPS,
credentials=CREDS,
lease=3600, # renewable session length, seconds (auto-renewed while connected)
max_session_s=14400, # HARD non-renewable cap; session ends with reason max_session_age
session_idle_timeout=300, # idle kick, seconds; 0 opts out (platform default 300)
warm=0, # idle replica floor; 0 = scale to zero (snapshot wakes)
snapshot=True, # snapshot after first validated boot; restores instead of cold boots
max_concurrency=4, # max concurrent sessions (platform default 2)
session_kind="realtime", # "realtime" (default) | "doc" for docs+artifacts apps (no media lanes)
)
def fn(ctx: Context):
...All of these are optional except what your app actually needs — the minimal decorator is @app.function(gpus="b200:1", deps=DEPS). Retired kwargs that raise TypeError: timeout (use lease / max_session_s), topology, gpus_per_replica, colocate_on_node, event_name, scaling. Env vars are never app config — env= and credentials= are for external inputs (secrets, runtime-injected values) only.
GPU shape and scheduling are deploy-time configuration. They are not session arguments — invocation args map 1:1 to the function's own args/kwargs and never override resources.
One-shot function (compute and return)
@app.function(gpus="l40s:1", deps=DEPS, credentials=CREDS)
def run_inference(prompt: str = "Explain transformers") -> dict:
from transformers import AutoModelForCausalLM, AutoTokenizer
model_path = urun.store.path("hf://Qwen/Qwen2.5-1.5B-Instruct")
tok = AutoTokenizer.from_pretrained(model_path)
model = AutoModelForCausalLM.from_pretrained(model_path, device_map="auto", torch_dtype="auto")
out = model.generate(**tok(prompt, return_tensors="pt").to(model.device), max_new_tokens=256)
return {"output": tok.decode(out[0], skip_special_tokens=True)}Streaming function (real-time session)
@app.function(gpus="b200:1", deps=DEPS, credentials=CREDS)
async def generate(ctx: Context):
pipe = load_pipeline(str(ctx.device)) # @store.cache(gpu_pin=True)
video = ctx.stream("video", codec="h264", fps=24)
control = ctx.doc("control")
def frames(*, stop_event, config):
while not stop_event.is_set():
prompt = control.desired.prompt.value or "a sunset" # live inline read
for f in pipe(prompt=prompt).frames[0]:
yield f
pipeline = ctx.source(frames, device="cuda") | ctx.pace(fps=24) | video
await pipeline.run()Cheap config is a live control.desired.* read inline in the stage. Structural change (model swap, resolution) uses doc.bind(construct, [doc.desired.some.prop]). There is no field-mapping form — pipeline.bind(doc, {...}) is retired.
Keep models warm
@urun.store.cache(key="pipeline") # gpu_pin=True is the default
def load_pipeline(device: str):
import torch
from diffusers import DiffusionPipeline
return DiffusionPipeline.from_pretrained(
urun.store.path("hf://org/model"), torch_dtype=torch.bfloat16
).to(device)Dependencies & Credentials
DEPS = Dependencies(
python=["torch>=2.5.0", "transformers", "accelerate"],
apt=["ffmpeg"], # system packages
post_install=["pip install flash-attn --no-build-isolation"],
)
CREDS = Credentials(env=["HF_TOKEN"], optional_env=["OPENAI_API_KEY"])Multi-GPU (SPMD)
@app.function(gpus="b200:4")
def render(ctx: Context):
print(f"rank {ctx.rank}/{ctx.world_size} on {ctx.device}")uRun launches one rank per GPU; the model owns its own parallelism (there is no topology kwarg — it is retired).
CLI
urun login --api-key urun_sk_<key> # or: export URUN_API_KEY=urun_sk_<key>
urun deploy app.py # package + register + build + wait
urun app list # statusBuild method: rebuild fresh, retire by default
uRun apps are rebuilt to the canonical shape (Anatomy of a uRun app), not iteratively thinned from a fat original. An existing fat app is a reference — read it to learn which model, which upstream repo@sha, which fork deltas matter, what the real compose path is — then write the app fresh to this shape and bring over only the app-specific glue.
Default to removing code. When rebuilding, keep code from the original only when it is necessary: keep it only if it is (a) the real model/compose path, (b) a fork delta that changes model behavior, or (c) app-specific glue with no primitive equivalent. Drivers, base classes, env-config forests, perf/debug scaffolding, hand-rolled IPC/sockets/threads, polling bridges, escape-hatch flags, redundant warmup/self-test machinery can all be removed. The goal is the smallest app that produces the intended output using platform primitives.
Docstrings are for a human. Write the function docstring as what it does and the shape — one line. Do not restate machine-enforced rules in docstrings — the checklist below and the strict-mode conformance guard enforce them. The docstring is for the reader.
Definition of done
A correct uRun app:
- Has exactly one
App("name"). - Has at least one
@app.function. - Sets the GPU shape via
gpus="type:count"(or omitsgpusfor CPU-only). - Declares Python deps in
Dependencies(python=[...])and secrets inCredentials(env=[...])/optional_env=[...]. - Uses
urun.store.path("hf://...")/urun.store.get(...)for model and data access. - If streaming: builds a pipeline with
ctx.source | … | ctx.stream(codec=…)and steers via live inlinedoc.desired.*reads (structural change viadoc.bind). - Deploys with
urun deploy app.py. - Passes no GPU/resource values as session arguments (args-purity).
- Uses none of the retired kwargs:
timeout,topology,gpus_per_replica,colocate_on_node,event_name,scaling. - Uses no env vars as app config — behavior is set by decorator kwargs and hardcoded constants; env is for secrets/runtime-injected values only.