Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

1,036 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Sailwright

Sailwright is an opinionated cross-platform automation toolkit for setting up, testing, and maintaining developer environments on macOS, Linux, and Windows. It combines Ansible with host-specific VM and system tooling so teams can manage local machines, remote hosts, and disposable test systems through one repository.

It is especially useful when a team has a mixed device fleet and wants one repeatable way to:

  • onboard developers faster
  • keep machine setup consistent across operating systems
  • test provisioning changes safely before rolling them out
  • reduce one-off scripts, tribal knowledge, and repeated support work

Sailwright is not a replacement for classic MDM/UEM tooling. It complements those tools by handling the developer-tooling and workflow layer that often remains manual, team-specific, and hard to reproduce.

Unlike raw ansible-playbook runs, chezmoi, Nix/Devbox, or devcontainers, Sailwright pairs Ansible with disposable, host-specific VM build/provision tooling so the same playbooks can be tested against real macOS/Linux/Windows targets before they ever touch a developer's machine.

"Transform your system into a dev powerhouse with a touch of automation magic."

Sailwright quick-start: install, build, create, start, and provision a VM The VM autoinstall running unattended during the build

Left: the real quick-start commands. Right: a real, unattended VM build (Ubuntu autoinstall) β€” no clicks, fully automated. See demo/ and make demo-build-video.

Quick Start

TAG="$(curl -fsSL https://api.github.com/repos/csautter/sailwright/releases/latest | sed -n 's/.*"tag_name": *"\([^"]*\)".*/\1/p' | head -n1)"
curl -fLO "https://github.com/csautter/sailwright/releases/download/${TAG}/sailwright_${TAG#v}_linux_amd64.tar.gz" && tar -xzf sailwright_*_linux_amd64.tar.gz
./sailwright install && ./sailwright build list

See πŸš€ Getting Started below for macOS/Windows steps, cloning the repo instead, and running your first full workflow.

Why It Helps

Without a shared automation baseline, cross-platform teams usually run into the same problems:

  • developers spend hours figuring out how a machine is supposed to look
  • onboarding depends too much on senior team members
  • setup differences become hard to debug and reproduce
  • OS-specific scripts drift over time

Sailwright addresses that by keeping setup logic in versioned Ansible roles and playbooks, then using host-appropriate tooling to apply and test them.

Support Snapshot

The project currently supports these host-to-target workflows:

Host OS What you can automate today
macOS Managed workflows for macOS (Tart), Ubuntu (UTM), and Windows 11 (UTM)
Windows Managed workflows for Ubuntu (Hyper-V) and Windows 11 (Hyper-V, plus VirtualBox as unstable)
Linux Managed workflows for Ubuntu and Windows 11 with native QEMU/KVM via libvirt/virt-manager, plus direct Ansible runs and Docker-based Linux testing

This means Sailwright can cover every currently supported guest OS family on a macOS host, and every currently supported family except macOS on a Windows host or Linux host.

Use the built-in discovery commands to see the exact combinations available on your current machine:

sailwright build list
sailwright create list
sailwright start list
sailwright provision list
sailwright stop list
sailwright destroy list

Note: macOS guests are only supported on macOS hosts due to Apple platform and licensing restrictions.

Base Model

Sailwright follows a few simple ideas:

  • Ansible roles and playbooks are the source of truth for machine setup
  • roles stay cross-platform where possible, with OS-specific handling where needed
  • runs are idempotent, so the same workflow can be applied repeatedly
  • execution is pull-oriented, so machines can run their own automation locally
  • --check mode matters, so changes can be previewed before they apply

That makes it practical both for daily developer use and for testing changes in VMs before applying them to real machines.

You can also use the built-in wrapper for host-local provisioning:

sailwright provision local --check
sailwright provision local --proto ssh --check
sailwright provision local --playbook ./playbooks/setup.yml --check
sailwright provision local

Use this when you want the same command surface on your real workstation that you use for managed test targets. A bare run uses the playbook from configfile ansible-role-sources.yml when configured; otherwise it falls back to the bundled role-source smoke/example playbook. For platform defaults, Windows transport behavior, cleanup flags, and rollback steps, see Local Provisioning and Windows Ansible Access. For direct ansible-playbook examples, use Running Playbooks.

πŸš€ Getting Started

1. Choose how you want to run it

You can either:

  • download a release binary for normal use
  • clone the repository when you want to edit playbooks, roles, or project code

Download a release binary

Release assets are published on the GitHub Releases page as sailwright_<version>_<os>_<arch>.

After extraction, the executable is named sailwright on macOS/Linux and sailwright.exe on Windows.

If you prefer the shorter sail command, create it yourself as a shell alias such as alias sail=sailwright, or install a sail symlink that points to the sailwright executable.

macOS / Linux example:

TAG="$(curl -fsSL https://api.github.com/repos/csautter/sailwright/releases/latest | sed -n 's/.*"tag_name": *"\([^"]*\)".*/\1/p' | head -n1)"
VERSION="${TAG#v}"
curl -fLO "https://github.com/csautter/sailwright/releases/download/${TAG}/sailwright_${VERSION}_linux_amd64.tar.gz"
tar -xzf "sailwright_${VERSION}_linux_amd64.tar.gz"
chmod +x ./sailwright
./sailwright build list

Windows example:

$Release = Invoke-RestMethod "https://api.github.com/repos/csautter/sailwright/releases/latest"
$Tag = $Release.tag_name
$Version = $Tag.TrimStart("v")
Invoke-WebRequest -OutFile "sailwright_${Version}_windows_amd64.zip" "https://github.com/csautter/sailwright/releases/download/$Tag/sailwright_${Version}_windows_amd64.zip"
Expand-Archive "sailwright_${Version}_windows_amd64.zip" -DestinationPath .
.\sailwright.exe build list

When you run a release binary outside a Git checkout, Sailwright extracts its embedded runtime assets into a managed app-data directory. See Managed Application Data for the default locations and override options.

Clone the repository

git clone https://github.com/csautter/sailwright.git
cd sailwright

2. Install host dependencies

macOS

sailwright install

This runs scripts/macos/sailwright-install-dependencies.sh.

Ubuntu / Debian

sailwright install

This runs scripts/linux/sailwright-install-dependencies.sh.

On macOS, Linux, and Windows, sailwright install --with-go also bootstraps the Go toolchain.

Windows

Run the command from your normal shell. Windows will prompt for elevation through UAC if needed:

sailwright.exe install
# optionally with Go and VirtualBox support:
sailwright.exe install --with-go --virtualbox

This runs scripts/windows/sailwright-self-setup.ps1.

3. Discover what your host supports

Start with the list commands before running a longer workflow:

sailwright build list
sailwright create list
sailwright provision list

Use --help when you want the supported flags for a command:

sailwright --help
sailwright build --help
sailwright provision --help

4. Run your first useful workflow

There are two common entry paths.

A. Configure the current machine directly

Use the built-in wrapper first when you want the shared command surface:

sailwright provision local --check
sailwright provision local --proto ssh --check
sailwright provision local --playbook ./playbooks/setup.yml --check
sailwright provision local

Configure ansible-role-sources.yml when you want the bare command to select your machine setup automatically. Without that config, it runs the bundled role-source smoke/example playbook. For more wrapper examples and platform-specific local behavior, use Local Provisioning. For direct localhost or remote-target ansible-playbook examples, use Running Playbooks.

B. Test the setup in a disposable VM first

Example on a supported host:

sailwright build ubuntu --type server --arch amd64
sailwright create ubuntu --type server --arch amd64
sailwright provision ubuntu --type server --arch amd64 --check
sailwright provision ubuntu --type server --arch amd64

If you are targeting Windows and remote access is not configured yet, start with Windows Ansible Access.

When you want to share reusable build artifacts through an OCI registry instead of rebuilding them locally, use sailwright push and sailwright pull; see the OCI build artifact registry workflow.

Trust & Privilege Model

Sailwright collects no telemetry and phones home to nothing: it makes no network calls except the ones you explicitly ask for (release/self-update downloads, OCI registry push/pull, and the Ansible/VM/network operations your playbooks define).

Elevation is scoped and temporary rather than "run everything as root/admin." On Windows, sailwright provision local creates a dedicated local admin account with a random or rotated password, enables WinRM-over-HTTPS or SSH only on the loopback address for the duration of the run, and restores the prior WinRM/SSH/firewall state during cleanup β€” see Windows Ansible Access for the exact mechanism. On macOS/Linux, install and provisioning scripts prompt for sudo only for the specific steps that need it.

Docs Map

The root README is the fast entry point. Use these guides when you want the next level of detail:

πŸ“¦ Example Roles

The repository already includes example roles for common developer tooling such as brew, java, jetbrains, k9s, kind, kubectl, kubelogin, openssh, python, and spotify.

Use Example Ansible Roles as the catalog and roles/ as the source of truth.

🀝 Contributing

Contributions are welcome. Good areas to improve include:

  • more roles and playbooks
  • broader cross-platform coverage
  • better docs and troubleshooting guidance
  • bug fixes and test coverage

See CONTRIBUTING.md for contribution terms and the Contributor License Agreement (CLA).

πŸ“œ License

Sailwright uses a dual-licensing model.

Copyright (c) 2026 Carl-Christian Sautter. Open source use is licensed under AGPLv3, and commercial licensing is offered separately.

Open Source

The community edition is licensed under the GNU Affero General Public License v3 (AGPLv3).

See LICENSE.md.

Commercial Use

If you need to use Sailwright in commercial products, SaaS platforms, or other closed-source environments without AGPL obligations, a separate commercial license is available.

See LICENSE_COMMERCIAL.md.

For commercial inquiries, visit www.c-sautter.de for contact details.

Historical Note

Early releases were published under the MIT License. If you use an older tag or release, refer to the license file included with that version.

πŸ’‘ Inspiration

This project grew out of real onboarding and support pain in mixed-OS teams. The goal is simple: make machine setup reproducible, testable, and much less dependent on memory or hand-written host-specific scripts.

About

Cross-platform dev environment automation with Ansible magic.

Resources

Contributing

Security policy

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages