How to install Julia inside Claude chat, Colab, and other sandboxes (when apt, sudo, and juliaup don't exist)
The wall I hit If you've ever tried to run Julia in a sandboxed environment, you know the sequence: You try apt install julia — permission denied. You try curl -fsSL https://install.julialang.org | sh — the domain is blocked, or the installer fails silently. You try juliaup — it wants to modify you

If you've ever tried to run Julia in a sandboxed environment, you know the sequence:
And then you look around and realize: the only tool you have that actually works is pip.
That was my exact situation. I was working inside Claude chat's sandbox — the environment where the assistant can run code on your behalf — and I wanted to test a Julia snippet. Julia simply wasn't installable. Not with the tools the Julia community officially provides.
So I wrote julialang: a pip package that installs, switches, and removes Julia versions using nothing but pip.
pip install julialang && julialang install && julia Enter fullscreen mode Exit fullscreen mode Three commands. No installer, no apt, no juliaup, no julialang.org.
The key insight is simple: the Julia language itself doesn't need to be inside the pip wheel. The wheel only needs to be a small, portable installer that knows how to fetch the real thing.
This is the same pattern ziglang uses for Zig, and it works beautifully for Julia too.
flowchart LR A[julialang.org<br/>downloads pages] -->|crawl| B[tools/sync.py] B -->|verify sha256 + md5| C[GitHub Releases] C -->|julia-list.json| D[pip install julialang] D --> E[julialang install] E -->|download + verify| F[~/.julialang/versions/<version>/] F --> G[julia / julialang run] What this buys you:
This is the exact scenario I built it for. In a Claude chat, the assistant can run shell commands and Python, but you can't install Julia with the usual methods. Here's how it goes:
pip install julialang Enter fullscreen mode Exit fullscreen mode Step 2 — install Julia itself:
julialang install Enter fullscreen mode Exit fullscreen mode This downloads the latest stable Julia, verifies its sha256 and md5, and unpacks it into ~/.julialang/versions/<version>/.
julia -e 'println("hello from Julia ", VERSION)' Enter fullscreen mode Exit fullscreen mode If julia isn't on your PATH — which is common in sandboxes that don't pick up ~/.local/bin — use the shim instead:
julialang run -e 'println(VERSION)' python -m julialang run script.jl Enter fullscreen mode Exit fullscreen mode Both of these route to the same Julia binary. The shim exists precisely because sandbox environments are unpredictable about what ends up on PATH.
The same recipe works in Google Colab, GitHub Actions runners, locked-down CI containers, and any environment where pip is your only escape hatch.
flowchart LR subgraph Install I1[julialang install] --> I2[latest, becomes default] I3["julialang install '>=1.10,<1.13'"] --> I4[newest match] I5[julialang install 1.10 1.12] --> I6[multiple at once] end subgraph Run R1[julia script.jl] --> R2[shim → selected version] R3[julialang run -e '...'] --> R2 R4[python -m julialang run...] --> R2 end subgraph Manage M1[julialang use 1.10] --> M2[switch default] M3[julialang list] --> M4[see what's installed] M5[julialang uninstall 1.12] --> M6[remove one] M7[julialang self-uninstall] --> M8[purge + pip uninstall] end A fuller walkthrough:
# Install and inspect julialang install # latest Julia, becomes default julialang install 1.12 # the newest 1.12.x julialang install 1.10.5 # exactly this version julialang install ">=1.10,<1.13" # pip-style version specs julialang install 1.10 1.12 # several at once # See what you have julialang # status: installed, default, latest julialang list --installed # only what's on your machine julialang list --all # everything the mirror offers julialang latest # newest version available julialang which # path of the executable `julia` runs # Run julia # REPL julia script.jl # run a script julialang run -e 'println(VERSION)' # when `julia` isn't on PATH python -m julialang run script.jl # when even the shim isn't on PATH JULIALANG_VERSION = 1.10 julia -e 'print(VERSION)' # one command, another version # Switch between versions julialang use 1.10 julialang use latest # Upgrade and downgrade (these REPLACE the default) julialang upgrade # install latest, make it default, remove old default julialang upgrade 1.12 #... or the newest 1.12.x julialang downgrade 1.10 # towards an older version # Remove julialang uninstall 1.12.2 # one version julialang uninstall 1.10 1.11 # several julialang uninstall "<1.12" --yes # a spec that matches many versions julialang purge # remove every Julia version + data julialang self-uninstall # purge, then `pip uninstall julialang` Enter fullscreen mode Exit fullscreen mode How version selection works When you invoke julia or julialang run, the choice of which Julia to run is fully deterministic:
flowchart TD A[invoke julia] --> B{JULIALANG_VERSION set?} B -->|yes| C[use that version<br/>must be installed] B -->|no| D{default configured?} D -->|yes| E[use default] D -->|no| F{any version installed?} F -->|yes| G[use newest installed] F -->|no| H[error: run julialang install<br/>or set JULIALANG_AUTO_INSTALL=1] Two things are worth calling out:
If you've used pip version specifiers, these will feel familiar:
Quote specs that contain < or > so the shell doesn't treat them as redirection.
juliaup is excellent. It's the official tool, it's well-maintained, and if you can run it, you probably should. But juliaup assumes a few things that sandboxes don't always give you:
flowchart LR subgraph juliaup["juliaup"] J1[needs shell config] --> J2[writes to ~/.juliaup] J2 --> J3[fetches from julialang.org] end subgraph julialang["julialang (pip)"] P1[needs only pip] --> P2[writes to ~/.julialang] P2 --> P3[fetches from GitHub mirror] end julialang makes exactly one assumption: if your environment can install a Python package, it can install Julia.
One design decision I'm happy with is that the mirror sync and the package release are completely decoupled.
flowchart TB subgraph Sync["sync.yml — mirror only"] S1[push / weekly cron / manual] --> S2[crawl + download Julia] S2 --> S3[upload to GitHub Releases] S3 --> S4[update julia-list.json asset] end subgraph Wheel["wheel.yml — package only"] W1[push to master] --> W2[ruff + pytest] W2 --> W3[build wheel/sdist] W3 --> W4[smoke test on 5 OSes] W4 --> W5[beta prerelease] W6[tag vX.Y.Z] --> W2 W6 --> W7[GitHub release + PyPI] end S4 -.->|read at install time| W4 The dashed line is the only connection: the wheel's smoke test actually installs Julia from the mirror on five operating systems, so every release doubles as a health check of the mirror. But neither workflow triggers the other — a broken mirror doesn't block a release, and a release doesn't depend on the sync job finishing.
julia-list.json isn't in git — it's a release asset, regenerated after every mirrored version.
flowchart LR A[GitHub mirror] -->|archives| B[julialang install] A -->|julia-list.json<br/>sha256 + md5| B B --> C{hashes match?} C -->|yes| D[install] C -->|no| E[abort] F[⚠️ same origin] -.-> A That last note matters. The hashes and the archives come from the same repository, so this protects against corrupted downloads — not against someone taking over the mirror. I'm calling that out openly because it's the honest trade-off of this design.
In a high-security environment, juliaup from the official source is the safer choice. For everyone else — the person in a Colab notebook, a CI runner, a sandbox — the trade-off is worth it.
The state layout is simple: ~/.julialang/versions/<version>/ holds each Julia, and ~/.julialang/config.json records the default and installed versions. It re-syncs with the folders on every command, so you can even delete a version folder by hand.
pip install julialang julialang install julia -e 'println("it works: ", VERSION)' Enter fullscreen mode Exit fullscreen mode PyPI: https://pypi.org/project/julialang GitHub: https://github.com/MohammadRaziei/julialang If you've ever been stuck in an environment that only speaks pip, I'd love to hear whether this solves your problem — and what's still missing. Issues and PRs are very welcome.
Julia is a wonderful language. Getting to it shouldn't require admin rights.