Installation
One command, one binary, no runtime to install first.
curl -fsSL https://freecode.website/install | bashOn Windows, use PowerShell — the bash installer detects Git Bash / MSYS and tells you to switch rather than installing something that will not work:
irm https://freecode.website/install.ps1 | iexThen, in any project:
freecodeIf the shell cannot find it, open a new terminal (the installer edits your shell
rc files, and the current shell has already read them) or run
export PATH="$HOME/.local/bin:$PATH".
What the installer actually does
Worth knowing, because it decides where your versions live and how rollback
works (scripts/install.sh, scripts/install.ps1):
-
Detects your platform and picks one release artifact —
linux-x86_64,linux-aarch64,macos-aarch64,macos-x86_64, orwindows-x86_64. -
Resolves the latest release through the GitHub API.
-
Downloads an archive, not a bare binary. The
.tar.gz(.zipon Windows) holds the executable and the ONNX Runtime shared library the memory-graph embedder loads at runtime —bun build --compilecannot embed a native.so/.dylib, so it ships beside the binary. -
Unpacks into a versioned directory and repoints a symlink:
~/.freecode/builds/ versions/0.25.16/freecode ← the real binary for this version stable/freecode → symlink to versions/<latest>/freecode stable-version ← plain-text version marker ~/.local/bin/freecode → symlink to builds/stable/freecode -
Clears the macOS quarantine flag on the unpacked directory, so Gatekeeper does not block the binary or the
.dylibit loads. -
Adds the install directory to PATH by appending an export line to
~/.zshenv,~/.bashrc,~/.profile, and fish’sconfig.fish— plus~/.zshrc,~/.zprofile, and~/.bash_profileif they already exist. It checks for the directory first, so re-running does not duplicate lines.
Because installs are versioned directories and stable is just a symlink, an
upgrade is a symlink swap and the previous version is still on disk.
| Variable | Default | Effect |
|---|---|---|
FREECODE_HOME | ~/.freecode | where versions and all app state live |
FREECODE_INSTALL_DIR | ~/.local/bin (%LOCALAPPDATA%\freecode\bin on Windows) | where the launcher symlink goes |
Both are read by the installer only. Set them for every install, or not at all —
freecode uninstall ignores them (known gaps).
Verifying
freecode --version
which freecode # should be the launcher in your install dirThe version string comes from FREECODE_BUILD_VERSION, baked in at build time.
If it prints unknown, you are not running a release binary — most likely a
build from a clone.
Updating
Three things update FreeCode, and the third one is the one to know about:
freecode update # re-runs the installer
curl -fsSL https://freecode.website/install | bash # identical, without the binaryFreeCode also updates itself on launch. A release binary checks the GitHub
API once per start with a 3-second timeout; if a newer release exists it runs
the installer and re-execs through ~/.freecode/builds/stable/freecode, so the
TUI you land in is already the new version (apps/tui/src/entry.ts:56). Any
failure — offline, rate-limited, install error — is swallowed and your current
version opens.
The re-exec goes through the stable symlink rather than the path of the
running binary, deliberately: the kernel resolves symlinks at exec time, so
re-running your own process.execPath would launch the old version again and
you would have to quit and retype freecode to actually get the update.
This check does not run when you are working from a clone — there is no release
to compare against. To turn it off, set FREECODE_NO_UPDATE=1 (an explicit
freecode update still works — that’s you asking).
Rolling back
Old versions are still in ~/.freecode/builds/versions/. To go back, run one
directly:
ls ~/.freecode/builds/versions
~/.freecode/builds/versions/0.25.15/freecodeTo stay on it, set FREECODE_NO_UPDATE=1 — otherwise that binary performs
the same update check at launch, installs the latest release, and re-execs you
into it.
Running from a clone instead
If you want to change FreeCode itself, install the monorepo rather than the binary — the backend is spawned from disk, so your edits take effect on the next run. See development setup.
One rule from that world is worth repeating here: never copy a pnpm build:sea artifact into ~/.freecode/builds/versions/. That build is a TUI
shell that does not bundle the backend and only works inside the monorepo;
dropping it where the installer expects a release binary gives you a freecode
that works in the repo root and is broken everywhere else.
Uninstalling
freecode uninstall # removes the binaries, keeps your data
freecode uninstall --dry-run # prints the list, deletes nothing
freecode uninstall --purge # also deletes ~/.freecode
freecode uninstall --force # skips the y/N promptIt prints what it will remove, then takes a freecode binary found in
/usr/local/bin, /usr/bin, ~/.local/bin, or ~/.cargo/bin, plus
~/.freecode/builds.
--purgeis the one that costs you something. Your sessions, rollout logs, per-project memory, prompt history, and usage data all live under~/.freecode/, and that flag is what deletes them. Nothing is backed up, so copy~/.freecode/projects/and~/.freecode/sessions/first if you might want them later.
There is also curl -fsSL https://freecode.website/uninstall | bash, for when
the binary itself is broken.
Known gaps
Found while writing this page; each is also tracked in TODO.md.
freecode uninstallignores the variables the installer honours. The handler hard-codes~/.freecodeand a fixed list of four Unix bin paths (cli/commands/uninstall.ts:44). An install done withFREECODE_HOMEorFREECODE_INSTALL_DIRset is not removed, and the Windows launcher in%LOCALAPPDATA%\freecode\binis not in the list at all — on Windows the command reports success while leaving the binary on PATH.- Nothing removes the PATH lines the installer wrote. Four or more rc files
get an
export PATH=…block appended; uninstalling leaves every one of them pointing at a directory that no longer exists.