docs
Python SDK

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                      # status

Build 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 omits gpus for CPU-only).
  • Declares Python deps in Dependencies(python=[...]) and secrets in Credentials(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 inline doc.desired.* reads (structural change via doc.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.

On this page