Highly configurable provisioning for:
dev: local development machine bootstrap (packages, dotfiles, utilities)vps: end-to-end VPS bootstrap from your machine (users, SSH hardening, firewall, reverse proxy, app runtime)
This project uses Ansible for idempotent provisioning, with:
- a typed Python CLI wrapper for safer command generation
- environment-specific YAML config
- a small web app to quickly compose setup configs and launch commands
One command. No clone, no prerequisites beyond curl and a sudo-capable user:
curl -fsSL https://raw.githubusercontent.com/guilyx/setup/main/install.sh | bashIt installs git/python/uv, clones this repo to ~/.local/share/setup, installs
the Ansible collections, and provisions the machine from config/defaults.yaml.
Preview without changing anything:
curl -fsSL https://raw.githubusercontent.com/guilyx/setup/main/install.sh | bash -s -- --checkOther flags: --config PATH, --ref BRANCH, --dir PATH, --print-only.
Each has an environment variable equivalent (SETUP_CONFIG, SETUP_REF,
SETUP_DIR), which is how you pass them when piping into bash:
curl -fsSL .../install.sh | SETUP_REF=my-branch bash- Shell:
zsh+oh-my-zshwith autosuggestions, syntax highlighting and completions, plus thestarshipprompt - Productivity:
tmux,fzf,zoxide,bat,eza,ripgrep,fd,jq,yq,htop,btop,tree,ncdu,duf,httpie,tldr,direnv,xclip - Languages: Python (
pipx,virtualenv,pre-commit), Node 22 from NodeSource with corepack, Rust viarustup(opt-in Go) - AI coding tools: Claude Code and Cursor
- Git/Collaboration:
gh,git-lfs,tig, opinionated global git config, PR template, CODEOWNERS - Quality:
pre-commit,shellcheck,shfmt,yamllint - Containers:
docker.io,docker-compose-v2, with your user added to thedockergroup - Desktop bars/launchers:
polybar,rofi,picom,feh,dunst,waybar(opt-in)
Package installation is resilient: a group is installed in one transaction, and if a name does not exist on your Ubuntu release the group is retried package-by-package so the rest still lands.
See docs/dev-tooling-catalog.md and docs/review-policy.md.
Dotfiles are managed by chezmoi by default, from
guilyx/chezmoi. The chezmoi role:
- installs the
chezmoibinary - writes
~/.config/chezmoi/chezmoi.tomlfromchezmoi.datain your config, sochezmoi initnever stops to prompt during provisioning - runs
chezmoi init --applyon first run andchezmoi updateon later runs
Day to day:
chezmoi edit ~/.zshrc # edit the source
chezmoi diff # preview
chezmoi apply -v # apply
chezmoi update -v # pull and applyThe older GNU stow workflow is still available: set dotfiles.manager: stow.
The two managers are mutually exclusive — whichever one is selected owns the
home directory, and the other role skips itself.
See docs/chezmoi-guide.md.
This repo provisions the machine. The apps themselves — what runs, on which
port, started how — live in guilyx/chezmoi.
Provision first, then bring the apps up:
curl -fsSL https://raw.githubusercontent.com/guilyx/setup/main/install.sh | bash
exec zsh # docker group applies to new sessions only
cd ~/apps/chezmoi && make configure && make upSetting apps.enabled: true makes this repo do the clone and configure step
for you during provisioning. Starting the stacks stays opt-in, since it needs
secrets. See docs/ecosystem-handoff.md.
Set leharness.enabled: true to also install
guilyx/LeHarness — the harness that
detects the machine's hardware tier (DGX-class multi-GPU, single-GPU
workstation, Jetson AGX Orin, or CPU-only), serves local models through vLLM
or Ollama accordingly, and exposes one OpenAI-compatible endpoint
(http://127.0.0.1:8000/v1). The role clones the repo, verifies the GPU
container runtime (installing nvidia-container-toolkit when needed), and
reports the detected profile; actually starting the engine
(leharness.start: true) stays opt-in because it downloads model weights.
- Full docs index:
docs/README.md - Architecture and diagrams:
docs/architecture.md - Provisioning execution flows:
docs/provisioning-flows.md - Config schema and examples:
docs/configuration-reference.md - Operational procedures:
docs/operations-runbook.md - Web UI usage and extension:
docs/webapp-guide.md - Reusable diagram snippets:
docs/diagrams-snippets.md
- Idempotent: rerunning playbooks converges to desired state.
- Granular: role variables map directly to setup capabilities.
- Composable:
dev,vps, and dotfiles are independent roles. - Auditable: declarative config + Ansible logs.
- Safe defaults: dry-run capable and explicit inventory.
If you cloned the repository yourself rather than using the curl entrypoint:
- Install dependencies:
./scripts/bootstrap.sh- Copy and customize config:
cp config/defaults.yaml config/local.yaml- Run local dev provisioning:
./scripts/run-dev.sh --config config/local.yaml- Run VPS provisioning:
cp inventory/vps.example.ini inventory/vps.ini
# edit inventory/vps.ini with your host(s)
./scripts/run-vps.sh --config config/local.yaml --inventory inventory/vps.iniinstall.sh- curl-able entrypoint for a fresh machineplaybooks/dev.yml- local machine setupplaybooks/vps.yml- VPS setuproles/*- granular provisioning logicconfig/defaults.yaml- baseline configuration knobstooling/setup_cli.py- typed command builder for playbookswebapp/app.py- quick browser UI for generating/running setup commands
Run:
uv run python -m webapp.appThen open http://127.0.0.1:8080.
The UI:
- generates
config/web-generated.yaml - displays the exact command that will be run
- allows running
devsetup locally - provides
vpscommand and--checkpreview for safe copy/paste execution - supports deploy-user SSH key input (one public key per line) for VPS bootstrap
uv run pytest- Never commit real secrets or private keys.
- Keep host-specific secrets in
secrets/(ignored by git). - Use dedicated deployment SSH keys and locked-down SSH config.