An AI-native development foundation for Mac, Linux/WSL, and headless agent workspaces.
Built and maintained by Jason Dockery (GitHub).
Groundwork combines a reproducible development setup with a learning path for the fundamentals that stay useful when AI tools change: the shell, Git, project instructions, verification, and how to direct and supervise AI agents while the human remains the senior partner.
It installs the tools a developer may want, but the tools are not the point. Editors, multiplexers, launchers, and browsers are choices. The durable skill is learning how to make work observable: know where files live, read the diff, run the checks, understand what changed, and keep agent-assisted development accountable.
macOS is the primary desktop target. Linux, WSL, and headless containers share the same terminal layer so the workflow remains usable in local shells, CI, servers, and disposable agent environments. Native Windows is not a separate target; use WSL2 for the Unix development environment.
This repo is the complete, version-controlled source for the setup, docs, validation, and project scaffolds.
On a fresh Mac, run the bootstrap script. It is the source of truth for new-Mac setup and is safe to re-run after fixing any failure.
bash -c "$(curl -fsSL https://raw.githubusercontent.com/jasondockery/groundwork/main/bootstrap-mac.sh)"Want to inspect it first? (Reading a script before piping it into your shell is a habit worth keeping.)
curl -fsSL https://raw.githubusercontent.com/jasondockery/groundwork/main/bootstrap-mac.sh -o /tmp/bootstrap-mac.sh
less /tmp/bootstrap-mac.sh
bash /tmp/bootstrap-mac.shThat script installs every Brewfile package, lays down all configs, and runs the setup scripts.
Before you run it: this is an opinionated environment, not a passive app installer — it changes the Mac it runs on (shell, Git, editor, tmux, VS Code, Homebrew packages, selected macOS defaults). It backs up what it replaces first, and
groundwork-restoreputs the managed files and defaults back. Read Important — opinionated Mac setup for exactly what changes and what the restore does and does not cover.
New here and not ready to install? Read the docs at https://jasondockery.github.io/groundwork/, or keep reading below for what Groundwork is and who it's for.
Not on a Mac? See Supported Platforms — Linux, WSL2, and headless Docker share the same terminal layer.
Groundwork is for anyone who wants to build seriously, wherever you are starting from: brand new to development or deep into a career, new to the terminal or fluent in it, new to AI-native work or already practicing it. It sets up a machine, image, or container quickly with everything needed to work — tools, shell, shortcuts, and agent instructions in place — and the docs meet each reader at their own starting point.
Wherever you start, the destination is the same: a deeply skilled, technical agentic engineer — someone who understands the system, works the terminal confidently, and directs AI agents without depending on them. That is a long climb, not a weekend project. Every page is written in layers — terms defined once and a first successful path for those who need it, a skimmable workflow-and-config fast path for those who don't — so any reader can take what they need and move. It is deliberately not a children's learn-to-code introduction.
Groundwork is a progressive path. You do not have to do everything, and you can go as deep as you want:
- Overview. Understand AI-native development, the arc from vibe coding toward agentic engineering, and why fundamentals matter before setup begins.
- Quick wins. Provision a machine and do short practice steps that produce something real fast, because momentum matters.
- Substantial practice. Spend focused time on week-long tracks: a browser first-person shooter, a Unity first-person shooter, a web project, an app, and a generative-media image/video pipeline.
The tracks are branches on one shared spine: shell, Git, project instructions, validation, and agent-direction skills underneath whichever domain makes someone excited enough to practice.
Groundwork is an on-ramp, not the whole road. It will not turn someone into an agentic engineer by itself; it gives the big picture, the working environment, and the first serious reps so learners know what they are aiming toward.
New here? Read the public docs at https://jasondockery.github.io/groundwork/ or open docs/index.html locally from a checkout.
| Platform | Status | What applies |
|---|---|---|
| macOS desktop | Primary | Full terminal layer, Homebrew formulae, casks, App Store apps, selected macOS defaults, browser/app helpers |
| Linux / WSL2 | Terminal layer | zsh, Git, tmux, Neovim, shell tools, mise/uv, helper scripts; GUI apps and macOS defaults are skipped |
| Headless / Docker | Terminal layer | Non-interactive shell environment for agents, CI, and disposable dev containers; no GUI apps |
| Native Windows | Use WSL2 | Groundwork is Unix-shell-oriented. Install WSL2/Ubuntu, keep projects in the WSL filesystem, and use the Linux terminal layer there |
Groundwork uses one chezmoi source tree. .chezmoi.os skips macOS desktop apps on Linux/WSL, and the headless flag is reserved for explicit server, CI, and container profiles. The public docs version of this split lives in docs/platforms.html.
Headless Docker quick start:
docker build -t groundwork .
docker run -it --rm groundworkKeep the groundwork tag for the image you actually run. A build that only verifies a Dockerfile change (yours or an agent's) goes through the managed wrapper instead — groundwork-docker-build-scratch <purpose> . — which owns the ephemeral-build contract: it applies dev.roost.ephemeral=true, generates the RFC 3339 dev.roost.built timestamp itself, tags groundwork/scratch:<purpose>, and prints the image ID (add --rm-after to prove-and-delete in one step). Never hand-type the labels, and never docker tag a scratch image into a real name — labels live on the image, so promote by rebuilding. Scratch images are removed in the same session or left for groundwork-docker-tidy to remove after the 72-hour grace (see docs/platforms.html).
Groundwork treats AI as part of the development environment, not as a sidecar. The terminal, tmux, Neovim, Git, Raycast, Anybox, and the docs are arranged around a repeatable human-in-the-loop workflow:
- Start from a real project folder with clear
AGENTS.mdinstructions. - Ask an agent to inspect, plan, edit, test, or explain.
- Review the diff yourself before keeping changes.
- Run the repo's validation commands.
- Capture durable lessons in docs, skills, or the knowledge wiki.
Terminal-first is the interface; AI-native is the workflow. Agents operate through files, shell commands, Git diffs, project instructions, and verification steps, so the keyboard-first tooling is here to make supervising that work fast and teachable.
The long-term direction lives in one canonical file: AI_THESIS.md. Agent adapters, docs, and skills should reference that file instead of restating the thesis in parallel.
This repo is not a passive app installer. It is an opinionated development environment and it changes the Mac it runs on: shell config, Git config, terminal/editor/tmux settings, VS Code settings, Homebrew packages, selected macOS defaults, Finder behavior, keyboard repeat behavior, browser/developer preferences, and app-specific setup where macOS allows it.
On first apply, the setup creates a focused backup at ~/.local/state/groundwork/backups/latest before changing managed files and macOS defaults. Restore with:
groundwork-restoreThat restore is intentionally scoped: it restores the managed config files and macOS defaults this repo snapshots. It does not uninstall apps, undo Homebrew upgrades, reverse manual permissions, or replace Time Machine.
During chezmoi init, existing Macs are also offered an optional clean start for common conflict zones. Say yes only when you want old terminal/editor/tmux state moved aside before this setup applies. The moved files go to ~/.local/state/groundwork/reset/latest; they are not deleted.
Advanced users can override the clone URL, for example when using SSH:
GROUNDWORK_REPO_URL=git@github.com:jasondockery/groundwork.git bash /tmp/bootstrap-mac.shchezmoi update runs git pull from this repo and applies the result. If the repo changes an install hook, such as the Brewfile bundle, that hook can add newly declared tools; it still does not chase newer Homebrew or mise releases for tools already installed. The public repo does not require GitHub login for normal pulls.
Run update-all when you want a visible, batched refresh of Groundwork, Homebrew packages/casks, mise-managed tools such as Node LTS, and Homebrew-managed AI tools such as Codex and OpenCode. Claude Code stays on its vendor-supported latest channel. Upgraded tools take effect at your next shell prompt, even in already-open terminals. The shell prints a gentle reminder when that refresh has gone stale; set GROUNDWORK_UPDATE_REMINDER=0 in ~/.zshrc.local to silence it.
Groundwork is a shared base with a personal layer. Put small personal preferences in local override files that Groundwork intentionally loads last:
~/.zshrc.local
~/.gitconfig.local
~/.config/tmux/tmux.local.confSetup choices live in ~/.config/chezmoi/chezmoi.toml; re-run chezmoi init or edit that file, then chezmoi diff and chezmoi apply. For the full model, open docs/customizing.html.
Pre-release macOS: if you're on a beta/just-released macOS, Homebrew may not have bottles for a few formulae and will build them from source (slow) or skip them.
brew bundlecontinues past failures, so skim the output andbrew install <formula>anything that didn't land.
If you use GitHub for your own projects, authenticate the Mac as the person using it:
gh auth status # confirm it's the Mac user's GitHub account
gh auth switch # choose another already-authenticated account
gh auth login --git-protocol https
gh auth setup-git --hostname github.comSSH is fine if you already manage multiple GitHub accounts with ~/.ssh/config. If a clone was pointed at the wrong remote, point it back at the public HTTPS URL:
git -C "${GROUNDWORK_DIR:-$HOME/code/groundwork}" remote set-url origin https://github.com/jasondockery/groundwork.gitThe gh credential helper is baked into
home/dot_gitconfig.tmpl, so it survives every apply. Runninggh auth setup-gitalone isn't enough on its own —~/.gitconfigis chezmoi-managed, so without the template change the nextchezmoi applywould overwrite it.
Stored in ~/.config/chezmoi/chezmoi.toml; re-run with chezmoi init.
| Prompt | Notes |
|---|---|
| Is this a work machine? | no by default. yes gates personal apps and Docker Desktop off this Mac |
| Is this a server/CI Mac with no desktop apps? | Mac only. no by default. Most Macs should press Enter; yes skips Raycast, browsers, Obsidian, App Store apps, and macOS defaults. Linux/WSL skip macOS desktop apps by OS |
| What is your GitHub username? | Your own — sets your git identity, separate from the jasondockery repo address used for cloning |
| What name should Git use for commits? | Your human name in commit metadata |
| What personal email should Git use for commits? | Your personal commit email |
| What work email should Git use? | blank if none |
| Where should projects live? | default ~/code |
| Reset old terminal/editor/tmux state before applying? | no by default. Use yes on an already-used Mac if old Neovim, tmux, zsh completion, or plugin state may compete with this setup. Moved aside to ~/.local/state/groundwork/reset/latest |
| Which password manager should Groundwork configure for SSH + git signing? | 1password / bitwarden / none |
| What SSH public key should Git use for signing? | the public key; blank to skip commit signing |
| What should the Obsidian vault be named? | folder in iCloud Drive/Obsidian; default my_obsidian_vault, blank to skip |
| Install optional Unity game development tools? | no by default. Use yes to install Unity Hub and C# VS Code extensions for the Unity FPS track |
| Install Xcode for native Apple/iOS development? | no by default. Use yes to attempt the App Store Xcode install for signing, simulators, SwiftUI/iOS/macOS builds, or Unity Apple-platform builds |
These are the one-time steps macOS or the app vendor should own: account sign-in, App Store purchases, permission prompts, secrets, per-device hotkeys, display IDs, and cloud sync. Groundwork manages stable file/plist-backed defaults; the README keeps the operational checklist, and the linked docs carry the longer context.
- Karabiner — Groundwork opens Karabiner after install/update if it is not running, but macOS still requires you to approve Input Monitoring and the driver/system extension in System Settings → Privacy & Security. Enables Caps Lock = Esc/Ctrl. See
docs/keyboard.html. - Apple Developer / Xcode — optional and large. If you enabled the Xcode setup option, Groundwork attempts the App Store install; if it does not go through, get Xcode from the Mac App Store manually. Then open Xcode once, accept first-launch setup/license prompts, sign in at Xcode → Settings → Accounts, and let Xcode manage certificates/profiles. Never put certificates, provisioning profiles, or
.mobileconfigprofiles in dotfiles. Seedocs/macos.html. - Password manager — sign in, enable the SSH agent, and confirm signed commits work. See
docs/apps.htmlanddocs/git.html. - Bitwarden as default autofill — make Bitwarden the source of truth for macOS, browsers, and mobile autofill. See
docs/apps.html. - Obsidian — open the vault, keep it downloaded, restart once for plugins, and configure Smart Connections, Whisper, and Ollama only if you use AI over notes. See
docs/apps.htmlanddocs/knowledge.html. - Ollama (local AI) — optional local service for embeddings and note helpers; launch it once so it serves
localhost:11434, then runollama pull nomic-embed-text. Seedocs/apps.html. - Raycast — make it your ⌘Space launcher, run
raycast-extensions --open, set the core window/clipboard/bookmark/Anybox shortcuts, then use Raycast Cloud Sync or export/import for reproduction. Seedocs/apps.htmlanddocs/macos.html. - Raycast AI (optional) — leave it off unless you want Claude/GPT/Grok from Raycast. The launcher, clipboard, windows, Quicklinks, and Anybox search work without it. See
docs/apps.html. - BetterDisplay — optional display preset and external-monitor control layer; open it once, keep the menu-bar icon on, favorite the resolutions you use, and test brightness/DDC controls. See
docs/macos.html. - Anybox (Mac App Store) — paid link library; buy/Get it once per Apple Account, run it as a menu-bar app, add a few typed Quick Link keywords, and paste its API key into the Raycast extension. See
docs/apps.html. - Default browser — run
defaultbrowserto list installed browsers, thendefaultbrowser zen, and approve the macOS confirmation; keep Chrome for testing. Seedocs/apps.html. - Zen sync — sign in with Firefox Sync for bookmarks/history/logins/open tabs; recreate Spaces per machine. See
docs/apps.html. - Browser extensions — run
browser-extensionsto list the managed add-ons, orbrowser-extensions --browser zen --tier core --opento open the core Zen set. Seedocs/apps.html. - Codex desktop app — installed by the Brewfile alongside the CLI; open it (or run
codex app) and sign in once. Seedocs/codex.html. - Grok Build (optional to use) — the CLI is installed by the Brewfile, but using it needs a SuperGrok / X Premium+ subscription; run
grokin a project to sign in. Seedocs/grok.html. - Learning tracks — the browser/Three.js FPS track starts at
docs/game-dev.htmland needs no Unity install. If you enabledgame_dev, open Unity Hub, install the latest Unity 6 LTS editor, add the WebGL module, then followdocs/game-dev-unity.html. The web, app, and image/video tracks live atdocs/web-dev.html,docs/app-dev.html, anddocs/gen-media.html. - Work Mac only — start the Docker daemon:
colima start.
One repo, both machines. The work flag (answered at init) gates the work Mac:
- Off work: Claude Code + the Claude app, Codex (CLI + app), ChatGPT, Grok Build, Cursor, OpenCode, Zed, Obsidian, Dia, Docker Desktop, and AppCleaner. (Chrome, Zen, Karabiner, Raycast, BetterDisplay, and core terminal tools install on both machines.)
- On work: Docker becomes Colima + the Docker CLI (license-free). Confirm your employer permits the AI tools before enabling them there.
groundwork-help # show Groundwork commands, aliases, keys, and helper scripts
groundwork-help update # filter the command catalog
largest ~ # find large files/folders, then show cleanup guidance
groundwork-doctor # read-only machine health report (Docker hygiene, disk, leftovers)
groundwork-docker-tidy # dry-run tidy of ephemeral-labeled Docker scratch images, by enumeration (--yes to act)
groundwork-docker-cache-tidy # DAEMON-WIDE Docker cleanup preview (all projects; owner-run only, --yes to act)
groundwork-docker-build-scratch review . # build a disposable image under the ephemeral contract (wrapper owns labels + scratch tag)
groundwork-repos # table of every discovered repo: branch, dirty/clean, ahead/behind
groundwork-repos pick # fuzzy-pick a repo -> its lazygit tmux window (prefix+R in tmux)
groundwork-repos changed # lazygit window per dirty repo (prefix+G in tmux)
scripts/validate-groundwork # validate/lint the repo before commit/release
browser-extensions --open # open vetted browser add-ons for Zen/Chrome/Dia
raycast-extensions --open # open recommended Raycast Store entries
chezmoi diff # preview pending changes before applying
chezmoi apply # apply source -> home
chezmoi update # git pull + apply managed config
update-all # visible refresh for Groundwork, brew, mise, and agents
chezmoi edit ~/.zshrc # edit a managed file at its source
chezmoi cd # shell into the source repo to commit/push
new-project myapp # scaffold AGENTS.md + .agents/ + vendor symlinks in a repo
new-wiki ~/code/notes # scaffold an LLM knowledge wiki repoIf
chezmoi applysays "run chezmoi init first," the config template (.chezmoi.toml.tmpl) changed. Runchezmoi init(it only regenerates the config and won't re-ask questions you've already answered), thenchezmoi apply. This is expected after pulling changes that touch the prompts or defaults.
Capturing what you install over time:
brew bundle dump --file=~/.config/homebrew/Brewfile --describe # snapshot brew
code --list-extensions > ~/vscode-extensions.txt # snapshot VS Code, then: chezmoi add ~/vscode-extensions.txt
# global node CLIs: add "npm:<pkg>" = "latest" to ~/.config/mise/config.tomlGroundwork is a normal visible project checkout, defaulting to ~/code/groundwork. The .chezmoiroot file tells chezmoi that only home/ maps into your home folder. Everything outside home/ is repo documentation, scaffolding, or project tooling.
.chezmoiroot # points chezmoi at home/
AI_THESIS.md -> home/.chezmoitemplates/ai-thesis.md
# canonical AI-native north star
bootstrap-mac.sh # new-Mac bootstrap script
AGENTS.md # operational agent instructions for this Groundwork repo
.claude/skills -> ../skills # project-skill discovery, canonical files stay in skills/
.codex/skills -> ../skills # same canonical skills tree for tools that support it
skel/llm-wiki/ # the `new-wiki` knowledge-base scaffold
docs/ # documentation source, published to the public site
scripts/validate-groundwork # local validation + ShellCheck linting mirrored by CI
home/
.chezmoitemplates/ai-thesis.md # one source for the AI-native thesis rendered into adapters
.chezmoi.toml.tmpl # the init prompts + per-machine data
dot_zshrc.tmpl # zsh config and aliases
dot_gitconfig.tmpl # git config (incl. the gh credential helper)
dot_zsh_plugins.txt # antidote plugin list
dot_claude/CLAUDE.md.tmpl # Claude Code adapter: shared thesis + Claude-only notes
dot_codex/AGENTS.md.tmpl # Codex adapter: shared thesis + Codex-only notes
dot_config/
ghostty/config # terminal
tmux/tmux.conf.tmpl # tmux
starship.toml # prompt
mise/config.toml # runtime / tool versions
private_karabiner/modify_karabiner.json # keyboard rule merged into Karabiner's app-owned JSON (700 dir, matching the app)
homebrew/Brewfile.tmpl # everything Homebrew installs
dot_local/bin/executable_new-project # per-repo AGENTS.md + .agents/ scaffolder
dot_local/bin/executable_groundwork-help # installed command catalog helper
dot_local/bin/executable_update-all # stable launcher: sync Groundwork, exec fresh runner
dot_local/bin/executable_groundwork-update-run.tmpl # post-sync update stages (brew, mise, AI tools)
dot_local/bin/executable_groundwork-platform # reports darwin / linux / wsl2 / wsl1 / wsl-unknown / unsupported
dot_local/bin/executable_groundwork-distro # reports the distro ID; --family reports debian / fedora / arch / opensuse / unknown
dot_local/bin/executable_largest # guided largest-file/folder scanner over dust
dot_local/bin/executable_groundwork-doctor # read-only machine health report
dot_local/bin/executable_groundwork-docker-tidy # label-scoped Docker tidy by enumeration, dry run by default
dot_local/bin/executable_groundwork-docker-cache-tidy # daemon-wide Docker cleanup, owner-run only
dot_local/bin/executable_groundwork-docker-build-scratch # disposable-build wrapper: labels + scratch tag
dot_local/share/groundwork/lib/docker-scan.sh # shared read-only scanner behind tidy and doctor
dot_local/bin/executable_groundwork-repos # discover repos under configured roots; picker, status, dirty-repo windows
dot_local/bin/executable_raycast-extensions.tmpl
# Raycast Store extension checklist helper
dot_local/share/groundwork/commands.tsv # source for groundwork-help
dot_local/share/groundwork/raycast-extensions.tsv
# source for raycast-extensions
vscode-extensions.txt.tmpl # VS Code / Cursor extension list
Library/.../Code/User/ # VS Code settings + snippets
run_*.sh.tmpl # install/setup scripts, run in numeric order
In short: managed configs live under home/dot_config/; the home/run_ scripts do installs and machine setup; global AI standards are in AGENTS.md; and new-project (installed to ~/.local/bin) scaffolds per-repo AI guides.
Groundwork uses semantic versioning — vMAJOR.MINOR.PATCH (e.g. v1.0.0),
the same scheme as its sibling project. Minor bumps add or revise content;
major bumps restructure the path. The git tag is the single source of
truth: the Pages build stamps the latest tag into every docs footer with a
link to release notes
(auto-generated from conventional commits). Versions are never hand-edited
into HTML; a local checkout's footers honestly read dev, so only the
published site ever claims a version. To view docs locally with your
exact checkout stamped in (tag + short commit SHA + dirty marker), run
scripts/serve-docs.sh.