Skip to Content
Getting startedInstallation

Installation

One command, one binary, no runtime to install first.

curl -fsSL https://freecode.website/install | bash

On 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 | iex

Then, in any project:

freecode

If 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):

  1. Detects your platform and picks one release artifact — linux-x86_64, linux-aarch64, macos-aarch64, macos-x86_64, or windows-x86_64.

  2. Resolves the latest release through the GitHub API.

  3. Downloads an archive, not a bare binary. The .tar.gz (.zip on Windows) holds the executable and the ONNX Runtime shared library the memory-graph embedder loads at runtime — bun build --compile cannot embed a native .so/.dylib, so it ships beside the binary.

  4. 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
  5. Clears the macOS quarantine flag on the unpacked directory, so Gatekeeper does not block the binary or the .dylib it loads.

  6. Adds the install directory to PATH by appending an export line to ~/.zshenv, ~/.bashrc, ~/.profile, and fish’s config.fish — plus ~/.zshrc, ~/.zprofile, and ~/.bash_profile if 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.

VariableDefaultEffect
FREECODE_HOME~/.freecodewhere 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 dir

The 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

Updating is always something you ask for:

freecode update # re-runs the installer curl -fsSL https://freecode.website/install | bash # identical, without the binary

FreeCode tells you when there is one, and never installs it behind your back. Shortly after the TUI opens, a release binary asks the GitHub API once (3-second timeout) whether a newer release exists. If there is one, a line appears under the version in the header:

>_ OmaCode (v0.40.0) update available (v0.40.0) · run freecode update

That is the whole of it — run freecode update when it suits you.

The check runs after the first frame is on screen and is never awaited. It used to be awaited ahead of the TUI, which put a GitHub round-trip on the path to first paint: ~1.1s of blank terminal on every launch, measured at 1.68s vs 0.58s time-to-input-ready with the check disabled. Any failure — offline, rate-limited, GitHub down — is swallowed and no line appears.

This check does not run when you are working from a clone — there is no release to compare against. To silence it, 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/freecode

It stays on that version: nothing updates on launch, so running an old binary keeps you there until you run freecode update. It will still show the “update available” line; FREECODE_NO_UPDATE=1 silences that too.

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 prompt

It 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.

--purge is 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 uninstall ignores the variables the installer honours. The handler hard-codes ~/.freecode and a fixed list of four Unix bin paths (cli/commands/uninstall.ts:44). An install done with FREECODE_HOME or FREECODE_INSTALL_DIR set is not removed, and the Windows launcher in %LOCALAPPDATA%\freecode\bin is 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.