Installation
Prerequisites
- Docker Engine ≥24.0 with Compose V2
- git with
user.nameanduser.emailconfigured - Your own git repository — cheasee-pi runs from any repo you own (it does not clone/fork anything)
Install
Linux / macOS
curl -fsL https://raw.githubusercontent.com/SchneiderDaniel/cheasee-pi/main/scripts/install.sh | bash
Installs to ~/.local/bin (the single canonical location — no sudo needed).
If ~/.local/bin is not on your PATH, add it to your shell config:
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
macOS Gatekeeper may block the unsigned binary. Run
xattr -d com.apple.quarantine ~/.local/bin/cheasee-pior Ctrl-click → Open in Finder.
Windows
# PowerShell
$version = "0.55.1"
$arch = if ((Get-CimInstance Win32_ComputerSystem).SystemType -match "ARM") { "arm64" } else { "amd64" }
curl -Lo cheasee-pi.zip "https://github.com/SchneiderDaniel/cheasee-pi/releases/download/v$version/cheasee-pi_${version}_windows_$arch.zip"
tar -xf cheasee-pi.zip
Move-Item cheasee-pi.exe "$env:LOCALAPPDATA\cheasee-pi\"
# Add to PATH manually: https://gist.github.com/nex3/c395b2f8fd4b020168be
Verify
cheasee-pi --version
Setup
Full command reference — what every command does, checks, and needs as input: CLI Reference.
cheasee-pi init
Run init in an empty folder — cheasee-pi sets the workspace up itself:
- Verifies Docker Engine 24.0+ is installed and running
- Probes the folder — init is empty-folder-only (existing non-empty folders are refused; cheasee-pi never auto-initializes them)
- Asks for your project repo URL (
owner/repoor any GitHub URL) - Authenticates with GitHub (OAuth device flow — code shown in the terminal, browser opens)
- Bare-clones your repo to
<parent>/.bareand adds the main worktree into the folder - Scaffolds the dedicated
cheasee-settings.jsonat the folder root (gitignored, machine-local — docker memory/cpus, git identity, default provider; never overwrites an existing file) - Asks for custom skills (reusable instruction sets for pi) to install
into the container — entered skill repository specs are recorded in
cheasee-settings.json(skillRepos) and installed on firstcheasee-pi startvia pi (pi install -l, cloned to.pi/git/, reconcilable withpi update). One skill repo,DietrichGebert/ponytail, is installed by default and declared at the prompt. To remove it, delete it fromskillReposincheasee-settings.jsonand runpi uninstall ponytailinside the container — the clone stays in.pi/git/otherwise.
No docker files in your repo — the compose file and Dockerfile are CLI-managed
cache state, and pi’s own .pi/settings.json is self-scaffolded by pi on its
first run.
Custom skills?
cheasee-pi init --skill-repo owner/reporecords custom skills (git-hosted skill repository specs) without a prompt (repeatable; also acceptshttps://…orgit:host/user/repo[@ref]). Recorded skill repos are installed into the container oncheasee-pi startvia pi (pi install -l, project-local clones in.pi/git/, kept reconcilable withpi update). TheDietrichGebert/ponytailskill repo is preinstalled by default — drop it fromskillReposincheasee-settings.jsonand runpi uninstall ponytailin the container to remove it.
No GitHub?
cheasee-pi init --no-githubskips auth and the clone; you provide API keys separately.--no-inputneeds--repo-url <url>since there is no prompt.
Already initialized?
cheasee-pi init --reauthre-runs the authentications (GitHub OAuth device flow + provider API-key setup) without touching the clone or the settings scaffold. Plaincheasee-pi initstill refuses an initialized workspace —--reauthis the explicit redo entry point.
Add API keys later
cheasee-pi auth add opencode-go # pick your provider
cheasee-pi auth list # verify
cheasee-pi auth remove <provider> # drop a key
Run
Run cheasee-pi from your cheasee-pi workspace — or straight from an empty folder, which auto-runs init first:
# ✓ Auth config saved to ~/.config/cheasee-pi/auth.json after init
cheasee-pi start
cheasee-pi (alias start) gates on the workspace state:
- Empty folder → auto-runs
cheasee-pi init(repo URL prompt, bare clone- main worktree,
cheasee-settings.json), then stops — init never launches pi; runcheasee-pi startagain to start
- main worktree,
cheasee-settings.jsonpresent → initialized workspace; runs normally- Non-empty folder without
cheasee-settings.json→ refused with “not initialized; runcheasee-pi initin an empty folder”
On an initialized workspace it:
- Extracts the compose stack (Dockerfile, entrypoint, codeflow service) to
the CLI cache dir (
~/.cache/cheasee-pi/<version>/); the image build clones cheasee-pi’s own repository (github.com/SchneiderDaniel/cheasee-pi, DockerfileARG CHEASEE_REF, defaultmain) into/opt/cheasee-piand symlinks its resources into~/.pi/agent/— not your repo - Starts the container (first build downloads ~1GB of build-time
dependencies; can take several minutes on slower connections) with the
workspace
mounted at
/workspaces/mainand its sibling bare repo at/workspaces/.bare(the entrypoint rewrites worktree paths and locks them) - Injects keys from
~/.config/cheasee-pi/auth.jsonand opens pi TUI
Global operating instructions
The cheasee-pi operating instructions — system role, tool-routing matrix,
prohibited operations, execution protocols, package-safety audit — live in
APPEND_SYSTEM.md at the cheasee-pi repo root. The image symlinks it into
~/.pi/agent/APPEND_SYSTEM.md, pi’s global system-prompt append, so the
instructions are present in every repository the CLI runs in (not just
cheasee-pi workspaces). The repo-root AGENTS.md is a stub holding only
cheasee-pi-repo-specific policy plus a pointer to the global file.
In cheasee-pi workspaces the entrypoint re-points the global symlink at the live mounted repo file, so edits are live; in other repos the baked image copy is used (refreshed on image rebuild).
Pi is installed as @latest at image build time, and cheasee-pi start
rebuilds the image whenever the container isn’t running — pi updates to the
latest version automatically on every start. No manual update needed.
Stop the container when done:
cheasee-pi down
After setup
Edit cheasee-settings.json in your workspace root to configure cheasee-pi:
defaultProvider, defaultModel, docker.memory/docker.cpus, gitIdentity.
Pi’s own .pi/settings.json (skills, prompts, extensions,
theme) is self-scaffolded by pi on first run — the CLI never writes it.
cheasee-pi auth add/auth list round-trip the default provider/model
through cheasee-settings.json.
What’s next
- Daily Usage — parallel sessions, workflows, troubleshooting
- Zed — recommend for the workspace:
zed .
Troubleshooting
Container doesn’t start
Compose/Dockerfile live in the CLI cache dir. Rebuild and start:
cheasee-pi start --build
Still failing? The image may be corrupt — force a full no-cache rebuild plus prune:
cheasee-pi rebuild
cheasee-pi start
Raw compose needs the bind-mount env vars (compose interpolates
WORKSPACE_HOST_PATH/WORKSPACE_BARE_PATH from the environment — unset
variables are a hard error, even for build):
WORKSPACE_HOST_PATH=$(pwd) \
WORKSPACE_BARE_PATH=$(dirname "$(pwd)")/.bare \
docker compose -f ~/.cache/cheasee-pi/<version>/docker-compose.yml build --no-cache
Permission errors
The entrypoint auto-detects host UID/GID from the /workspaces/main mount.
On macOS/Windows mounts with unusual ownership, pass them explicitly:
HOST_UID=$(id -u) HOST_GID=$(id -g) \
WORKSPACE_HOST_PATH=$(pwd) \
WORKSPACE_BARE_PATH=$(dirname "$(pwd)")/.bare \
docker compose -f ~/.cache/cheasee-pi/<version>/docker-compose.yml up
macOS: repo outside Docker Desktop shared roots
Docker Desktop only shares /Users, /Volumes, /private, /tmp,
/var/folders by default. Repos elsewhere fail at mount time with “Mounts
denied” — move the repo under one of those roots or add it to Docker Desktop’s
file-sharing settings.
SELinux hosts (Fedora/RHEL)
Bind mounts are blocked without relabel labels. Set
CHEASEEPI_SELINUX_RELABEL=1 when starting to append :Z to the mounts.
Emoji not displaying
Install an emoji font on the host:
# Debian / Ubuntu
sudo apt install fonts-noto-color-emoji
# Fedora
sudo dnf install google-noto-color-emoji-fonts
# macOS / Windows — bundled, no action needed
For git branch icon (), install a Nerd Font:
wget -P /tmp https://github.com/ryanoasis/nerd-fonts/releases/download/v3.3.0/JetBrainsMono.zip
sudo unzip /tmp/JetBrainsMono.zip -d /usr/share/fonts/truetype/jetbrains-nerd
sudo fc-cache -fv
Then set the font in your terminal to JetBrainsMono Nerd Font.
API keys not picked up
Use cheasee-pi start (reads ~/.config/cheasee-pi/auth.json). If you must use raw docker, the container is named cheasee-pi-<repo-slug> (repo slug, not plain cheasee-pi):
CONTAINER=$(docker ps --format '' | grep '^cheasee-pi-')
docker exec -it \
-e OPENCODE_API_KEY=$OPENCODE_API_KEY \
-e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY \
--user agentuser -w /workspaces/main "$CONTAINER" /usr/bin/pi --approve
Uninstall
Standalone script (recommended)
curl -fsL https://raw.githubusercontent.com/SchneiderDaniel/cheasee-pi/main/scripts/uninstall.sh | bash
Add --force to skip the confirmation prompt, --dry-run to preview what would be removed. The script removes the binary (from /usr/local/bin, ~/.local/bin, or your PATH), the whole CLI cache dir, and the auth config (cheasee-pi/auth.json under your user config dir). Workspace files (.pi/, .git/, source checkouts) are never touched. It works even if the binary is already gone, and never needs sudo (root-owned files like /usr/local/bin are elevated per-operation).
CLI command
cheasee-pi uninstall removes the cache dir, auth config, and every
cheasee-pi binary (the running executable plus the canonical install
locations ~/.local/bin and /usr/local/bin):
cheasee-pi uninstall
Run it without sudo — under sudo, the config/cache paths resolve to root’s account and the command would delete root’s state, not yours. If the binary lives in a root-owned directory like /usr/local/bin, use the standalone script above instead: it elevates per-operation and never needs sudo. When the CLI itself can’t remove the binary, it prints a manual sudo rm hint with the full path.
Add --force to skip confirmation.
Next: Daily Usage guide