Skip to content

Packages & environments โ€‹

A notebook running on a gate worker manages its own dependencies from the UI โ€” open the ๐Ÿ“ฆ Packages panel (โ˜ฐ โ†’ Packages).

The environment model: fork-and-extend โ€‹

A notebook never pollutes the repo it lives in, and it always runs in one consistent, fully-resolved environment (never a stacked LOAD_PATH, so there are never two versions of a shared dependency). It runs in one of three modes, chosen automatically:

  • Base โ€” the notebook has no packages of its own, so it runs directly in the enclosing project. Zero overhead, exactly like a plain script.

  • Forked โ€” the first time you add a package, the notebook forks off its parent into its own environment (kept under the depot), seeded from the parent (the parent package is dev'd in and its deps + Manifest are copied, versions preserved) and resolved as one environment. Adds and pins re-resolve the whole env, so the notebook can override the base. Forking reads the parent and does not modify it.

  • Detached โ€” no enclosing project, so the notebook environment is everything.

You rarely have to open the panel to install something. When a cell fails on a using for a package that is not installed, the error itself offers an Add button that installs it into the notebook's environment, pinned to the version your global environment already had where that is known, and then re-runs the stale cells.

That banner also offers Add to project, which writes the dependency into the enclosing Project.toml so every notebook in the project gets it. It appears only when there is a project to add to, and it is the one path that modifies the parent.

If the enclosing project's Manifest.toml later changes, a forked notebook auto-resyncs on open: it re-seeds from the parent and re-adds your packages (preserved), keeping it one consistent environment.

The panel โ€‹

The panel shows the environment with provenance, in two groups:

  • Notebook โ€” the packages this notebook added (removable โœ•).

  • Parent project โ€นdirโ€บ โ€” inherited from the enclosing project (read-only).

The status line reads e.g. 3 notebook ยท 41 from parent (or ยท detached).

  • Add โ€” Pkg.add in the notebook's own env (forking first if needed), then the notebook re-runs so a using lights up live. The first add can take a while (seed + resolve + precompile); the kernel dot pulses while it works. The box takes more than a registry name: a version pin (CSV@0.10), a git URL with an optional #rev, or a local path, which is dev'd so it hot-reloads and travels to a remote worker. Several entries separated by spaces or commas install in one resolve and one precompile. The panel badges a dev'd checkout dev and a git dependency git, since neither resolves on another machine unless the source travels with it.

  • Remove โ€” Pkg.rm from the notebook env, confirmed first. Parent rows can't be removed.

The Packages panel installs a package you can already name. To find one, open the ๐Ÿงฉ Extensions gallery (โŒ˜K โ†’ "Extensions", or โ˜ฐ โ†’ Extensions): a browsable catalog of Slate extension packages โ€” custom @bind controls, output renderers, domain tooling โ€” from a curated registry.

Each entry shows what the package does, what it provides, and a starter snippet. Install adds it to this notebook's environment through exactly the same path as the Packages panel, then offers to drop the starter cell in โ€” installing a package doesn't using it, and that offer is what closes the gap. Installed extensions are also tracked for updates.

See the Extensions gallery for the whole of it: browsing and filtering, what the first install does to your Julia depot, updating, and what an extension can add once it's loaded.

When a notebook has packages of its own, the .jl carries an auto-maintained, human-readable footer recording just that delta (the packages beyond the parent), with versions + UUIDs:

julia
# โ•”โ•โ•ก Slate.env ยท notebook packages (auto-maintained โ€” manage via the package panel)
#   CSV 0.10.14 336ed68f-0bac-5ca0-87d4-7b16caf5d00b
#   Plots 1.40.5 91a5bcdd-7333-5406-abb4-e4a6da0a7c5c
# โ•šโ•โ•ก

It round-trips cleanly (it's never parsed as a cell), only changes when your packages change, and is reconstructed on open: if you git clone a notebook whose env dir is gone, opening it rebuilds the environment from the footer (seed from parent, add the pinned packages). For a fully self-contained artifact โ€” the complete Project + Manifest + local source โ€” see Export โ†’ self-contained .jl.

Requirements โ€‹

Package management needs a gate worker โ€” i.e. the notebook lives inside a Julia project (or is detached but gate-capable). For an in-process notebook the panel is read-only and explains why: there is no notebook environment to manage.

Under the hood โ€‹

The UI calls GET /api/<id>/packages (provenance via the set difference active โˆ’ parent โˆ’ parent-package) and POST /api/<id>/package ({op: "add"|"rm"|"update", name, target: "notebook"|"project"}). Operations run through worker tools (__slate_pkg, __slate_pkg_parent for a write to the enclosing project, __slate_registry_add for installing a registry into the worker's depot, and __slate_fork / __slate_sync_parent / __slate_reconstruct for the env lifecycle); on success the notebook restales and re-runs and the footer refreshes.