# Roadmap: zc-workstation

> The plan to replace aurora-mac with zc-workstation, a Go CLI on top of chezmoi that sets up macOS, Linux and Windows from one repo.

aurora-mac sets up one kind of machine, a Mac, with about 850 lines of shell. Its successor, **zc-workstation**, sets up macOS, Linux and Windows from one repo. It is a new repository. aurora-mac stays as it is until zc-workstation reaches parity on macOS, and then it is archived.

## Decisions

 
| Question | Decision |
| --- | --- |
| 
Engine

 | 

chezmoi applies the dotfiles. A thin Go CLI does the glue that chezmoi does not do.

 |
| 

Platforms

 | 

Phased: macOS parity first, then Linux, then native Windows.

 |
| 

Repository

 | 

New repo `github.com/ZoolCoder/zc-workstation`, MIT. The CLI binary is `zc-workstation`, with a short alias `zcw`.

 |
| 

Scaffold

 | 

Generated from go-tool-template with `zoolfleet new` (class `oss`, license MIT), so it gets the plan/apply engine, `doctor`, MCP, skills, evals, Antora docs and release workflows that the other tools already share.

 |

## Found on GitHub

Searched first, so that the new code is only the glue nobody else provides.

   
| Project | License | Verdict | Why |
| --- | --- | --- | --- |
| 
[twpayne/chezmoi](https://github.com/twpayne/chezmoi) (Go, ~22k stars)

 | 

MIT

 | 

Adopt

 | 

Dotfiles on macOS, Linux and Windows. Per-OS templates, `run_onchange_` scripts, secrets from password managers, and a symlink mode. It replaces `link()` in `install.sh` and every per-OS branch we would otherwise write. Used as an external binary, not as a library.

 |
| 

[jdx/mise](https://github.com/jdx/mise) (~35k stars)

 | 

MIT

 | 

Keep

 | 

Already manages Java, Node and Python, and works on all three systems. Its `aqua` and `github` backends can also install CLI tools (starship, lazygit, yazi, delta, atuin) the same way everywhere, which shrinks the per-OS package lists.

 |
| 

go-tool-template (private) and [toolshell](https://github.com/zoolcoder/toolshell)

 | 

MIT

 | 

Adopt

 | 

Our own. Provider/plan/apply engine, `toolshell/doctor` checks, MCP server, admin UI, docs and release pipeline.

 |
| 

[charmbracelet/huh](https://github.com/charmbracelet/huh)

 | 

MIT

 | 

Adopt

 | 

The pick list for `catalog`. It replaces fzf, so the picker also works in a Windows console.

 |
| 

[goreleaser](https://github.com/goreleaser/goreleaser)

 | 

MIT

 | 

Adopt

 | 

Builds the binaries and publishes a Homebrew tap formula, a Scoop/winget manifest and Linux packages.

 |
| 

[topgrade-rs/topgrade](https://github.com/topgrade-rs/topgrade)

 | 

GPL-3.0

 | 

Optional

 | 

Upgrades every package manager on a machine. `update` calls it only when it is installed, as a separate program. It is never vendored or linked, so its GPL does not reach this repo.

 |
| 

[comtrya](https://github.com/comtrya/comtrya), [rotz](https://github.com/volllly/rotz), [dotter](https://github.com/SuperCuber/dotter)

 | 

MIT

 | 

Skip

 | 

Rust tools that overlap with chezmoi. They are smaller and younger, and comtrya says it is early in its development.

 |
| 

[yadm](https://github.com/yadm-dev/yadm), dotbot

 | 

GPL-3.0 / MIT

 | 

Skip

 | 

Symlinks plus shell commands, with weaker Windows support than chezmoi.

 |
| 

Package manager wrappers (pm, pkm, tux)

 | 

various

 | 

Skip

 | 

Shell, Unix only. The package provider is ours, about 200 lines of Go.

 |

## How it fits together

```
zc-workstation/
  cmd/zc-workstation/      CLI: init, plan, apply, update, doctor, catalog, mcp
  internal/provider/
    dotfiles/              runs chezmoi (source: home/)
    packages/              brew + Brewfile, apt, dnf, winget; one manifest per OS
    tools/                 mise install
    settings/              macOS defaults, GNOME gsettings, Windows registry
    services/              launchd, systemd --user timers, Task Scheduler
    keyboard/              keyd on Linux
  home/                    chezmoi source state; *.tmpl where the OS changes the file
  packages/
    Brewfile               macOS
    apt.txt, dnf.txt       Linux
    winget.json            Windows (winget import format)
  docs/                    Antora
```

-   `plan` shows what each provider would create, update or delete, and changes nothing.
    
-   `apply` runs a plan after a person says yes, from the CLI, the UI or an agent through MCP.
    
-   `doctor` replaces `doctor.sh`, built on `toolshell/doctor`, and adds `--json` for agents and CI.
    
-   `update` replaces the `update` alias: pull the repo and the overlay, `apply`, upgrade (topgrade when installed), then `doctor`.
    
-   The overlay stays a separate private repo. It is a second chezmoi source with its own state file and its own package manifests, applied after the public one. The path moves to `~/.config/zc-workstation/overlay`.
    
-   The scripts in `bin/` (git-tidy, gh-summary, prompt-pr, ci-watch, catalog) become subcommands only where they must run on Windows. Unix-only helpers stay shell scripts under `home/`.
    

## What carries over

   
| Part | macOS | Linux | Windows |
| --- | --- | --- | --- |
| 
zsh, antidote, starship, atuin

 | 

yes

 | 

yes

 | 

starship and atuin in PowerShell

 |
| 

tmux

 | 

yes

 | 

yes

 | 

inside WSL only

 |
| 

Terminal

 | 

Ghostty

 | 

Ghostty

 | 

WezTerm until Ghostty ships for Windows

 |
| 

git, delta, lazygit, yazi, mise

 | 

yes

 | 

yes

 | 

yes

 |
| 

VS Code, IntelliJ settings

 | 

yes

 | 

yes

 | 

yes

 |
| 

Claude Code config and hooks

 | 

yes

 | 

yes

 | 

yes, hooks rewritten where they call Unix tools

 |
| 

Theme (Catppuccin Latte/Mocha follows the system)

 | 

yes

 | 

GNOME first

 | 

yes

 |
| 

Caps Lock and Hyper key

 | 

Karabiner

 | 

keyd

 | 

PowerToys Keyboard Manager

 |
| 

Launcher

 | 

Raycast

 | 

GNOME default

 | 

PowerToys Run

 |
| 

Menu bar, window borders

 | 

SketchyBar, JankyBorders

 | 

none

 | 

none

 |
| 

Scheduled jobs

 | 

launchd

 | 

systemd --user

 | 

Task Scheduler

 |
| 

System settings

 | 

`macos.sh`

 | 

gsettings

 | 

registry

 |
| 

Clean-machine test

 | 

`scripts/vm-test.sh` (tart)

 | 

container in CI

 | 

Windows runner in CI

 |

## Where it stands

  
| Piece | State | Notes |
| --- | --- | --- |
| 
Engine, CLI, MCP server, dashboard

 | 

Done

 | 

From go-tool-template. The dashboard shows coverage, missing items and the programs each target needs.

 |
| 

`os` filter per target

 | 

Done

 | 

One config for every machine. Targets for another system are skipped.

 |
| 

`packages`: brew, mas, apt, dnf, winget

 | 

Done

 | 

Installs only, never uninstalls. Read-only status matches the aurora-mac Brewfile: 78 of 80 installed.

 |
| 

`dotfiles` through chezmoi

 | 

Done

 | 

Applies only the planned paths. `mode: symlink` is supported, which settles the copy-or-link risk below.

 |
| 

`tools` through mise

 | 

Done

 | 

Untrusted configs stay a `MANUAL` step.

 |
| 

`settings` and `services` providers

 | 

Done on macOS, Linux and Windows

 | 

macOS `defaults`, Homebrew services and launchd agents; GNOME gsettings and systemd user units and timers; the Windows registry under `HKCU` and Task Scheduler.

 |
| 

Security checks in `doctor`

 | 

Done on macOS

 | 

\`doctor.sh’s FileVault, firewall, screen lock, Gatekeeper, SIP, update, File Sharing, Touch ID and exposed-server checks, as warnings with their fix.

 |
| 

`list`, `capture`, upgrades

 | 

Done

 | 

`list` shows outdated and undeclared packages and runtimes in about two seconds. `capture` writes a Brewfile, package list or mise config from the machine. `upgrade: true` plans upgrades per target.

 |
| 

aurora-mac config moved to a private config repo

 | 

Done

 | 

A private zc-workstation-config repo holds the Brewfile, the mise config and a chezmoi `home/` source, so nothing personal enters this repo.

 |
| 

aurora-mac steps beyond links

 | 

Done

 | 

The git identity, hooks and signing key, app settings (VS Code, IntelliJ, Chrome, CodexBar), `gradle.properties`, git maintenance and Claude Notify are chezmoi `run_onchange_` scripts in the config repo; macOS defaults and background services are `settings` and `services` targets.

 |
| 

`add`, `remove`, `-upgrade` and `-only`

 | 

Done

 | 

`add` declares an item with why it is there. `remove` uninstalls and drops it from the manifest. `sudo` asks in a macOS dialog when there is no terminal.

 |
| 

`bootstrap.sh`, theme and `desktop` provider

 | 

Done on macOS

 | 

A new Mac in one command from the config repo. The ZoolCoder theme, wallpaper and screen saver.

 |
| 

ZCBar menu bar app and ZC Care

 | 

Done on macOS

 | 

The panel over the CLI, and a window that cleans junk and AI clutter, uninstalls apps, finds clutter and idle dependencies, and logs what it freed. Similar Images is still to come. See [Menu bar app and ZC Care](app.html).

 |
| 

CI on macOS, Linux and Windows runners

 | 

Done

 | 

`ci.yml` tests the CLI on Linux, macOS and Windows runners, and builds and tests ZCBar on macOS.

 |
| 

The toolbox

 | 

Done

 | 

A manual page per tool in the reference setup: what it is for, how it is configured, its keys. See [The toolbox](toolbox/index.html).

 |
| 

Repository hardening

 | 

Ready to apply

 | 

Git flow with `develop`, rulesets for `main`, `develop` and `v*` tags, pinned actions, CodeQL and govulncheck. `scripts/harden.sh` applies the GitHub settings.

 |
| 

First release, `v0.1.0`

 | 

Next

 | 

Binaries, the Homebrew cask, Linux packages and Windows zips through goreleaser.

 |

## Next

The concrete tasks are in [TODO.md](https://github.com/ZoolCoder/zc-workstation/blob/develop/TODO.md). In order:

1.  **Release.** Apply the repository settings, cut `v0.1.0`, and run `bootstrap.sh` from the cask on a clean macOS VM.
    
2.  **ZC Care.** Similar Images in My Clutter, and browser privacy data in Protection.
    
3.  **ZCBar distribution.** A Developer ID signature and notarisation, so Full Disk Access survives an update, and a cask for the app.
    
4.  **Linux and Windows.** Phases 2 and 3 below.
    

## Phases

Each phase ends with a check that proves it, not a date.

  
| Phase | Work | Done when |
| --- | --- | --- |
| 
0\. Scaffold

 | 

`zoolfleet new go-tool-template` as zc-workstation (oss, MIT). Push the empty repo, with CI green.

 | 

`make lint test build` passes on macOS, Linux and Windows runners.

 |
| 

1\. macOS parity

 | 

Move the config folders into `home/` as chezmoi source state. Write the dotfiles, packages, tools, settings and services providers. Port `doctor.sh` checks and `catalog`. Port the overlay. Release through goreleaser and a Homebrew tap.

 | 

On a clean macOS VM, `zc-workstation apply` gives the same result as `install.sh`. `doctor` is clean on both of your Macs. aurora-mac is no longer used.

 |
| 

2\. Linux

 | 

Templates for Linux paths, `apt.txt` and `dnf.txt`, systemd timers, gsettings theme, keyd. Ubuntu LTS and Fedora.

 | 

`apply` then `doctor` pass in Ubuntu and Fedora containers in CI.

 |
| 

3\. Windows

 | 

`winget.json`, PowerShell profile, WezTerm, PowerToys, registry settings, Task Scheduler. WSL gets the Linux profile.

 | 

`apply` then `doctor` pass on a Windows CI runner.

 |
| 

4\. Retire aurora-mac

 | 

Archive the repo on GitHub with a pointer to zc-workstation. Rename aurora-mac-overlay to zc-workstation-overlay. Update CLAUDE.md and memory paths.

 | 

Nothing on any machine still reads `~/Developer/Tools/aurora-mac`.

 |

## Docs

The docs move to zc-workstation with the code and change shape:

-   **Per-OS getting started.** One page each for macOS, Linux and Windows, in place of today’s macOS-only setup page.
    
-   **Generated reference.** The command reference comes from the CLI’s help, and the package list comes from the manifests, so neither can drift.
    
-   **Split by purpose.** Tutorials (first setup), how-to (add a package, add a dotfile, write an overlay), reference (commands, manifests, providers) and explanation (why chezmoi, the threat model).
    
-   **Workstation notes.** Claude Code, Git, Flutter, PostgreSQL, disk management and maintenance stay as notes modules, each marked with the systems it applies to.
    
-   **No personal paths.** Before the repo goes public, the five pages that still name personal paths are made generic. The personal detail moves to the overlay.
    
-   **Published.** The template’s `docs.yml` workflow publishes the site to GitHub Pages.
    

## Risks

-   **chezmoi copies files by default.** Editing `~/.zshrc` directly no longer edits the repo. Either use `chezmoi edit` and `chezmoi re-add`, or set `mode = "symlink"` for the files that you edit often. Decide this in phase 1.
    
-   **Windows has no tmux or zsh.** The Windows profile is PowerShell-first, with WSL for the Unix workflow. Parity there means the same tools and theme, not the same shell.
    
-   **Two dotfile engines in phase 1.** Until parity, aurora-mac and zc-workstation must not both manage one machine. Test zc-workstation on a VM, then switch each Mac once.
    

## Not planned

-   Managing servers or fleets of machines. That is Ansible’s job.
    
-   Nix or home-manager. They do not cover native Windows.
    
-   Applying a plan without a person’s yes.
