Windows, via WSL
Most people reading this are on Windows. WSL runs a real Linux system next to your normal Windows apps. Everything below happens inside that Linux system, except step 1.
Steps
-
Open PowerShell as Administrator. Run:
This may ask you to restart your computer.wsl --install -d Debian - Open "Debian" from the Start menu. The first time it opens, pick a Linux username and password (different from your Windows login).
-
From inside that Debian window, run this one line:
$ cd && sudo apt-get update && sudo apt-get install -y curl git && sh -c "$(curl -fsSL https://raw.githubusercontent.com/intellectual-frontiers/workspaces-host-v3/main/install.sh)"sudoasks for the password from step 2. That's the only password prompt in the whole process. It takes a few minutes the first time; safe to run again later. -
Fill in your credentials and apply them:
$ nano ~/.config/workspaces-host/credentials $ workspaces-host-update - Close this window and open a new one. Look for the new prompt and autosuggestions as you type. That's your confirmation it worked.
New window looks the same as the old one? Run doctor. It names the exact problem and the exact fix. See Checking your environment.
Using VS Code with WSL
- Install VS Code on Windows (not inside Debian): code.visualstudio.com.
- Install the "WSL" extension in that Windows VS Code (published by Microsoft).
- From your Debian window, in any project folder, run
code .The first time, this installs a small VS Code Server inside WSL and opens a normal VS Code window running entirely inside Linux.
Linux
Open a regular terminal. Most VM/cloud images already have curl/git/xz; a bare-bones one won't.
$ sudo apt-get install -y curl git xz-utils # Debian/Ubuntu
$ sudo dnf install -y curl git xz # RHEL/Fedora/CentOS
$ sudo pacman -Sy --noconfirm curl git xz # Arch
Then run:
$ sh -c "$(curl -fsSL https://raw.githubusercontent.com/intellectual-frontiers/workspaces-host-v3/main/install.sh)"
install.sh auto-detects which of those three families you're on for anything else it needs. Want to build or run this repo's container images too?
$ sudo apt install -y docker.io # Debian/Ubuntu; see docs.docker.com for other distros
macOS
curl, git, and xz are already there. Apple Silicon or Intel, run the same one-liner:
$ sh -c "$(curl -fsSL https://raw.githubusercontent.com/intellectual-frontiers/workspaces-host-v3/main/install.sh)"
Container sandboxing (the network-restricted image) doesn't run on macOS. Everything else does.
Manual, step by step
If you'd rather run each step yourself instead of the one-liner:
$ sudo apt update && sudo apt install -y curl git xz-utils # skip on macOS
$ sh <(curl -L https://nixos.org/nix/install) --no-daemon
$ mkdir -p ~/.config/nix
$ echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf
$ git clone https://github.com/intellectual-frontiers/workspaces-host-v3.git ~/.workspaces-host-v3
$ cd ~/.workspaces-host-v3
$ nix build ".#homeConfigurations.current.activationPackage" --impure
$ export HOME_MANAGER_BACKUP_EXT=pre-workspaces-host-backup
$ ./result/activate
install.sh in the repository is the real source of truth for these steps.
Verify it worked
$ doctor
One PASS/WARN/FAIL line per check. Exits non-zero only if something's actually broken. A WARN for anything you haven't configured yet (like a blank credential) is normal.
Autocomplete UX
This repository uses bash by default. Bash here gets fish-like real-time syntax highlighting and history autosuggestions from blesh, layered on top of plain bash so every tutorial and copy-pasted snippet still works unchanged. If typing feels slower than you'd expect, here's why, and two ways to fix it.
blesh's default configuration auto-triggers full completion, not just the lightweight grey suggestion, on almost every keystroke. That's the expensive part: it can shell out to real completion scripts (git, docker, and so on) before you've even pressed Tab.
Option (a): turn off just that one setting. Tab-completion itself is unaffected; you only lose the auto-popup that runs before you press Tab. Try it in your current shell first:
$ bleopt complete_auto_complete=
That change lasts for the current shell only. To make it permanent, add it to your personal, machine-specific override file (never touched by workspaces-host-update, so it survives every sync):
$ nano ~/.config/workspaces-host/local.nix
{ ... }:
{
programs.bash.initExtra = ''
bleopt complete_auto_complete=
'';
}
Then run workspaces-host-update to apply it.
Option (b): switch to the fish persona. If you want the real thing instead of a workaround, fish's own line editor (fish 4.x is written in Rust) does highlighting and suggestions natively, with nothing layered on top. It also gives you a few things blesh doesn't try to replicate: richer tab-completion generated straight from a command's own man page (no separate bash-completion package to install), simpler scripting syntax (real arrays, no [[ ]]), and a visual settings tool (fish_config) for tweaking colors and prompt options in a browser tab instead of editing config by hand. See Personas below for the exact command.
Personas
The base profile stays small: your shell, git, credentials, ws-repos, and AI coding agent tooling. A persona adds one more specialized set of tools on top, when you actually need it. (Curious why the base profile stays small instead of including all of this? See Why the base profile stays small.)
| Persona | Adds |
|---|---|
backend | Java+Maven, PostgreSQL client/pgpass, Redis, docker-compose, httpie |
data | python3, uv, duckdb |
mobile | android-tools (adb/fastboot), watchman |
agent-ops | act, semtag/git-standup/git-extras, gopass, deno, llm |
compliance | osquery, cnquery, steampipe, openobserve, surveilr |
networking | Tailscale, Nebula |
fish | fish shell, with the same aliases and prompt bash gets |
Personas are additive and they combine: everything the base profile gives you is still there, plus every persona's extras, plus each other's. Activate none and nothing changes. Activate backend and fish both, and every future workspaces-host-update builds both together, automatically, for as long as you keep them activated.
The fish persona only makes fish and its config available. It never changes your login shell, the same way activating networking never joins a Tailscale mesh for you. To actually use it day to day, run these two commands (the same way on Linux generally, WSL included, and macOS - anywhere chsh validates against /etc/shells):
$ echo "$(which fish)" | sudo tee -a /etc/shells
$ chsh -s $(which fish)
The first line is required: a Nix-installed shell isn't in /etc/shells by default, and chsh refuses any shell that isn't. Then close this window and open a new one. doctor checks for either bash or fish as your login shell, so switching never shows up as a problem.
Finding and checking personas
Don't want to remember the table above? ws-persona prints it for you, along with the exact command to turn each one on:
$ ws-persona list
Not sure what you already have active?
$ ws-persona current
This shows two things, and they can briefly disagree: what's activated (recorded in ~/.config/workspaces-host/personas, applied on your next workspaces-host-update) and what's detected (one marker tool per persona, like mvn for backend, actually on your PATH right now). Activate a persona and it shows as activated immediately, but not detected until you actually rebuild.
Detection is a quick signal, not a certainty - it can occasionally miss or over-report if you've installed something similar yourself, outside this flake. Run doctor --all for the full, authoritative picture.
Activating one (or several)
Record it, then update:
$ ws-persona activate backend
$ workspaces-host-update
workspaces-host-update runs doctor right after, so you see immediately whether it worked. Activate as many as you want the same way; each one adds to the others rather than replacing them, and the choice sticks - no environment variable to remember on your next update, next week or next year.
Changed your mind about one?
$ ws-persona deactivate backend
$ workspaces-host-update
Want to try a persona once without committing to it - build it in isolation, see if you like it, without touching your activated list?
$ WORKSPACES_HOST_PROFILE=current-backend workspaces-host-update
That one-off build ignores your activated list entirely (it's just backend, nothing else), and doesn't change it either. Prefer the plain Nix commands instead of workspaces-host-update for that one-off?
$ nix build ".#homeConfigurations.current-backend.activationPackage" --impure
$ ./result/activate
What's next
Head to Using Your Sandbox for credentials, your shell, managing repos, and everything else you'll touch day to day. New to the command line? Try with AI has copy/paste prompts that hand the typing to an AI agent instead. Want to understand how this is built, or point an AI agent at the repository? Go to Contributing. Curious why any of this is built the way it is, or what it grew out of? See FAQ.