jcode is an open-source AI coding agent
that runs as a local server and drives your editor. It's distributed as a
single self-contained executable, which sounds simple, until you try to run itin a pure Nix environment: no system package manager, no Nix channels, no
/usr/bin/env
. This post walks through installing the official Nix build fromGitHub releases, the surprising gotchas you will hit, and how to fix them.
What you need #
- A machine where the Nix store is present and mounted: a
bwrap-nix
sandbox,
NixOS, or any host withnix
installed. The jcode binary is dynamically
linked against the glibc shipped in the store, so the store must be there at
runtime. curl
andsha256sum
for down and verifying the release.- A writable
~/.local/bin
(or any directory on yourPATH
).
Step 1: Find the release #
jcode publishes Nix builds as GitHub releases tagged nix-vX.Y.Z
, for examplenix-v0.66.0
. Each release carries one asset per platform:
jcode-nix-linux-x86_64
The release page shows the exact sha256
digest for every asset, so you can
verify your download:
curl -s https://api.github.com/repos/grigio/jcode/releases/tags/nix-v0.66.0 \
| jq -r '.assets[] | .name + " " + .digest'
Step 2: Download and verify #
mkdir -p ~/jcode-install && cd ~/jcode-install
curl -sSL -o jcode-nix-linux-x86_64 \
https://github.com/grigio/jcode/releases/download/nix-v0.66.0/jcode-nix-linux-x86_64
sha256sum jcode-nix-linux-x86_64
Compare the output against the digest published on the release page. For
v0.66.0 it is:
2faea9dc9f560e6f9a73da360d57b3c1d32f4ccfa90bbea2352237ba43472bb3 jcode-nix-linux-x86_64
A checksum mismatch means a corrupted download or a tampered asset. Stop and
re-download.
Step 3: Confirm it is a real executable #
The Nix build is a genuine ELF binary, not a script. file
should show a
dynamically linked PIE with a Nix store interpreter:
file jcode-nix-linux-x86_64
Then check the version:
chmod +x jcode-nix-linux-x86_64
./jcode-nix-linux-x86_64 --version
Step 4: Install #
Put the binary on your PATH
:
mkdir -p ~/.local/bin
cp jcode-nix-linux-x86_64 ~/.local/bin/jcode
chmod +x ~/.local/bin/jcode
~/.local/bin/jcode --version
Replacing a running jcode: "Text file busy"
If you are upgrading and a jcode server is currently running from that path, a
plain cp
fails with Text file busy
. Linux refuses to truncate an executable
that is mapped by a live process. Copy to a temporary name and atomically
rename it instead:
cp jcode-nix-linux-x86_64 ~/.local/bin/jcode.new
chmod +x ~/.local/bin/jcode.new
mv -f ~/.local/bin/jcode.new ~/.local/bin/jcode
The old server keeps running from its in-memory image; the new version is used
by the next server start.
Step 5: Understand jcode's layout #
jcode manages its own builds under ~/.jcode/builds/
:
~/.jcode/builds/
shared-server/jcode # what the server actually launches
stable/jcode # the stable build
versions/<version>/ # per-version builds from self-update
shared-server-version # version marker
stable-version # version marker
After a manual Nix install, point the shared-server
and stable
symlinks at
the real ELF in ~/.local/bin/jcode
:
ln -sfn "$HOME/.local/bin/jcode" "$HOME/.jcode/builds/shared-server/jcode"
ln -sfn "$HOME/.local/bin/jcode" "$HOME/.jcode/builds/stable/jcode"
and keep the version markers in sync:
echo 0.66.0 > ~/.jcode/builds/shared-server-version
echo 0.66.0 > ~/.jcode/builds/stable-version
The Nix gotcha: self-update breaks the sandbox #
jcode self-updates by down a new build into~/.jcode/builds/versions/<version>/jcode
and pointing shared-server/jcode
at it. That downloaded file is not the binary. It is a wrapper shell script
whose first line is:
#!/usr/bin/env sh
In a Nix-only environment /usr/bin/env
does not exist (the env
binary lives
in the store under coreutils
), so execve(2)
fails with ENOENT
and the
server never starts. Verified with strace:
execve(".../.jcode/builds/shared-server/jcode",
["...", "--provider", "auto", "serve"], ...) = -1 ENOENT
Two equivalent fixes. Do one of them.
Option A (recommended): point shared-server at the real binary
ln -sfn "$HOME/.local/bin/jcode" "$HOME/.jcode/builds/shared-server/jcode"
No wrapper, no interpreter, no breakage. This also pins the server to the
binary you installed instead of an untested self-update.
Option B: provide /usr/bin/env
Give the shebang what it wants by symlinking the store env
into /usr/bin
(only possible when /usr/bin
is writable):
ln -sf "$(dirname "$(readlink -f "$HOME/.local/bin/env")")/env" /usr/bin/env
Run the server #
~/.jcode/builds/shared-server/jcode --provider auto serve
or directly:
~/.local/bin/jcode --provider auto serve
Notes:
- Only one server instance may run per runtime dir. A second launch fails
withError: Another jcode server process is already running for runtime dir /tmp/<...>/jcode-<uid>
. To restart, kill the existing PID first, then start
again. - Verify the daemon is alive with
jcode --version
or by checking the runtime
dir (/tmp/<...>/jcode-<uid>/
) forjcode.sock
andjcode-debug.sock
.
Upgrading to a new release #
The process is the same every time: download the new jcode-nix-linux-x86_64
asset, verify its digest, mv
it over ~/.local/bin/jcode
, re-run the
symlink command if anything changed, update the version markers, and restart
the server. The old binary can be kept as a rollback:
cp ~/.local/bin/jcode ~/.local/bin/jcode.v0.65.0.bak
Checklist #
- [ ]
sha256sum
matches the digest on the release page - [ ]
file
reports an ELF, not a shell script - [ ]
~/.local/bin/jcode --version
printsjcode vX.Y.Z (nix-build)
- [ ]
shared-server/jcode
andstable/jcode
are symlinks to the ELF - [ ] version markers match the installed version
- [ ] the server starts and binds its socket
Conclusion #
Installing jcode on Nix is straightforward once you know the rules: download
the Nix-built ELF, verify it, drop it on your PATH
, and keep jcode's own
symlinks pointed at the real binary instead of a self-update wrapper. The/usr/bin/env
trap is the one thing that will bite you, and Option A above
makes it a non-issue forever.