docs
Python SDK

De-vendoring upstream code

Pull in upstream model code at a pinned commit with store.repo — no vendored trees, no hand-maintained dep forests, no git clone in your build

store.repo lets you use an upstream model repo without copying its files into your app. You pin a commit, optionally apply a fork delta, and import the upstream modules with normal import syntax. The repo's own dependency list splices straight into yours.

This replaces the old pattern of vendoring a copy of someone else's model code into your repo (which goes stale, bloats the tree, and hides what you changed) and the matching pattern of hand-copying their requirements.txt into your Dependencies.

Forking is encouraged — and fully supported

For anything substantial — larger diffs, production use cases — fork the upstream repo and make your changes there. You get full version control, review, CI, and history on your own diff, which is exactly what a real change deserves.

A fork looks like any other git repo to uRun. store.repo pins by repo@sha, so pointing it at your fork just works — no special path, no separate mechanism:

# Point store.repo at YOUR fork's repo + commit — same spec, your org.
REPO = store.repo("github.com/your-org/restyle-model@<fork-sha>", include=["restyle"])
DEPS = Dependencies(python=[*REPO.deps(), "torch>=2.5.0"])

Everything below — the diff= / overlay= deltas applied over someone else's pinned tree — is the way to avoid the overhead of a fork until you actually need one. It's a convenience for small, legible deltas, not a substitute for forking and not the recommended path for anything production-grade.

Declare the repo at module top

The repo handle is declared once, at module top, so its dependencies resolve at build/deploy time:

from urun import App
from urun.core import Dependencies

app = App("restyle")
store = app.store

REPO = store.repo("github.com/org/restyle-model@<sha>", include=["restyle"])
DEPS = Dependencies(python=[*REPO.deps(), "torch>=2.5.0"])

The handle does three jobs — declaring it is the whole setup, with no separate materialize step:

  • store.repo("<spec>@<sha>", include=[...]) — materializes the repo (or just the include=d subtrees) into the content-addressed store as a tree of lazy byte-leaves. The git tree is fetched once, SHA-pinned and shallow; identical files dedup to one blob. Always pin a commit SHA — an unpinned ref is non-reproducible.
  • REPO.deps() — the upstream's own dependency list, parsed at the pinned SHA from its requirements.txt / pyproject.toml [project.dependencies] / setup.py install_requires. Splice it into your Dependencies(python=[...]) so you stop hand-maintaining a copy of their dep forest. Selectors shape the splice: extra="name" picks an optional-dependencies extra, exclude=["dep", ...] drops upstream deps by name, and pin_overrides={"dep": "==1.2"} replaces a version spec — overrides apply first, so an overridden dep survives even if also excluded.
  • with REPO: — a scoped context manager. It puts the repo's modules on the import path only inside the block; the real upstream imports happen under the context and the path is removed after.

Import under the context manager

Do the upstream imports inside with REPO: — typically inside your @store.cache loader, so the heavy import happens exactly once:

@store.cache(key="restyle-14b")
def load_model(*, device):
    with REPO:
        from restyle.pipelines import RestylePipeline   # resolves off the store tree
    return RestylePipeline.from_pretrained(
        store.path("hf://org/restyle-14b")
    ).to(device)

Only weights stay local (*.pth / *.safetensors via store.path("hf://...")); the code comes from store.repo.

Small deltas without a fork: pin + diff

When your change is small enough that a fork would be overkill, keep pointing at the upstream repo and layer a delta on top. For a clean vendor (you use the upstream as-is), pin and import — nothing else. When you have a small delta that changes model behavior, apply it as a real unified/git diff with diff=:

REPO = store.repo(
    "github.com/org/restyle-model@<sha>",
    include=["restyle"],
    diff="fork.patch",          # inline diff string OR a path to a .patch file
)

diff= applies with git apply, so multi-line edits, new functions, and new imports are all expressible. A hunk that does not apply loud-fails (raises) — it is never silently skipped. For net-new files or whole-file replacements atop the pinned tree, use overlay= (a directory path or a relpath -> bytes|str mapping).

Patch order

Deltas apply deterministically: checkout the pinned @shadiffoverlay → store the tree. The cache key folds in the identity of every delta, so changing a patch re-materializes the tree while unchanged inputs hit the cache.

deps() splice and diff/overlay don't mix on one repo

urun deploy resolves REPO.deps(...) by static analysis — it never executes your app. A diff=/overlay= delta could rewrite the upstream's dependency metadata, so deploying an app that splices REPO.deps() from a repo that also carries diff=/overlay= aborts loudly — declare the resulting dependencies as literals instead. For the same reason the selector arguments (extra=, exclude=, pin_overrides=) must be literal constants in the app source.

Why this shape

  • No vendored trees: your repo holds your app, not a stale copy of someone else's model. The upstream files live content-addressed in the store, deduped across apps and tenants.
  • No dep drift: REPO.deps() reads the upstream's real dependency list at the exact pinned SHA — you can't fall out of sync with a copy.
  • The delta is visible. A diff= is the literal patch; a reviewer sees exactly what you changed versus upstream, and a bad hunk fails immediately instead of drifting out of sync. (Past a small patch, a real fork gives you that review surface with full history.)
  • No build-time git clone: the fetch is a single SHA-pinned shallow fetch into the content store, lazy on the import side — no per-app git dependency baked into your image.

Scoped `with REPO:` is the default — and compile-safe

with REPO: scopes the import path, not the loaded modules: after the block no new top-level repo import resolves, but everything imported inside it stays importable and resident for the process (normal Python import semantics). A model loaded under the block keeps working — including one traced later by torch.compile.

The scoped form is the app-side idiom — apps do not call REPO.install(). If the upstream code does late top-level imports (a lazy submodule resolved on first use), pre-import those modules inside the block so they're resident before it closes:

with REPO:
    from pkg import Thing
    import pkg.data.transforms          # pre-resolve upstream's lazy imports
    import pkg.scheduler.streaming_sampler

Related:

  • Dependencies — declaring Python / apt / post-install deps
  • Store — the content-addressed store store.repo rides on
  • Streaming Pipelines — the canonical app shape that uses store.repo

On this page