One-command developer environment setup for Linux, macOS, WSL, Windows, and GitHub Codespaces.
| Tool | Purpose |
|---|---|
zsh |
Shell -- installed and set as default on Linux/macOS |
uv |
Python package and environment manager (fast pip replacement) |
nvm + Node.js LTS |
Node Version Manager + latest Node LTS |
gh |
GitHub CLI |
| GitHub Copilot CLI | AI pair programmer in your terminal (gh copilot) |
vim |
Modal text editor -- installed on all platforms |
tmux |
Terminal multiplexer (Linux/macOS) |
psmux |
Terminal multiplexer (Windows) |
| Shell aliases | Shortcuts for common git and dev commands |
| Platform | Status | Entry point |
|---|---|---|
| Linux (native) | [x] | bash setup.sh |
| macOS | [x] | bash setup.sh |
| WSL (Windows Subsystem for Linux) | [x] | bash setup.sh |
| Windows (native PowerShell) | [x] | powershell -ExecutionPolicy Bypass -File setup.ps1 |
| Dev Container / GitHub Codespace | [x] | Automatic (runs on container creation) |
git clone https://github.com/primetimetank21/dev-setup.git
cd dev-setup
bash setup.shGitHub Authentication: During setup,
scripts/linux/tools/auth.sh(Linux/macOS/WSL) orscripts/windows/tools/auth.ps1(Windows) checks whether you are already authenticated with the GitHub CLI. If not, it launchesgh auth logininteractively so you can complete authentication. In non-interactive environments (CI, GitHub Codespaces, piped stdin), the prompt is skipped automatically and a warning is printed -- rungh auth loginmanually after setup completes if you need to authenticate.
git clone https://github.com/primetimetank21/dev-setup.git
cd dev-setup
powershell -ExecutionPolicy Bypass -File setup.ps1No action needed. Setup runs automatically on container creation via the postCreateCommand hook.
After running setup, complete these steps to activate your tools:
-
Activate Node.js:
nvm install --lts nvm use --lts
-
Dotfiles: Your shell config (
.zshrc/.bashrc) and aliases are automatically installed during setup. Restart your terminal or runsource ~/.zshrc(orsource ~/.bashrcfor bash) to load them.
-
Activate Node.js: Open a new terminal and run:
nvm install lts nvm use lts
-
Aliases: PowerShell aliases are automatically added to your profile. Restart your terminal to load them.
dev-setup/
+-- setup.sh -- Entry point for Linux / macOS / WSL
+-- setup.ps1 -- Entry point for Windows (PowerShell)
+-- ARCHITECTURE.md -- Technical architecture and team ownership map
+-- CHANGELOG.md -- Release history (Keep a Changelog format)
+-- CONTRIBUTING.md -- Contribution guide
+-- scripts/
| +-- lib/
| | +-- read-tool-version.sh -- POSIX sh: reads pinned version from .tool-versions
| | +-- Read-ToolVersion.ps1 -- PowerShell: Get-ToolVersion function
| | \-- ascii-sweep.py -- Sweep .md files for non-ASCII; preserves fenced code blocks (#322A)
| +-- linux/
| | +-- setup.sh -- Core Linux/macOS installer (orchestrates tool scripts)
| | \-- tools/ -- Individual tool install scripts
| | +-- auth.sh -- GitHub CLI authentication (interactive)
| | +-- copilot-cli.sh
| | +-- gh.sh
| | +-- nvm.sh
| | +-- uv.sh
| | \-- zsh.sh
| \-- windows/
| +-- setup.ps1 -- Orchestrator (dot-sources tools/ scripts)
| +-- uninstall.ps1 -- Idempotent reverse of the installer
| \-- tools/ -- Per-tool install scripts
| +-- auth.ps1 -- GitHub CLI authentication (interactive)
| +-- copilot.ps1, dotfiles.ps1, gh.ps1, git.ps1, nvm.ps1
| +-- profile.ps1, psmux.ps1
| +-- uv.ps1, vim.ps1
| \-- (9 files total)
+-- config/
| \-- dotfiles/ -- Dotfile templates (.aliases, .gitconfig, .editorconfig, etc.)
| \-- install.sh -- Dotfile installer
+-- hooks/
| +-- commit-msg -- Enforce Conventional Commits
| +-- pre-commit -- 4-check hygiene gate (branch ancestry + ASCII on .ps1/.md/.sh + branch refusal + shellcheck); see Git Hooks below
| +-- prepare-commit-msg -- Rewrite merge/revert messages to Conventional Commits form; see Git Hooks below
| \-- pre-push -- Block pushes to main; advisory linting
+-- tests/ -- Validation tests (bash + PowerShell)
| +-- test_aliases.sh
| +-- test_git_hooks.ps1
| +-- test_idempotency.sh
| +-- test_remove_custom_item.ps1
| \-- test_windows_setup.ps1
+-- .devcontainer/ -- Dev Container / Codespace configuration
+-- .github/workflows/ -- CI validation and automation
Root entry points (setup.sh, setup.ps1) are thin routers -- they detect the OS and delegate to the appropriate script under scripts/. They install nothing themselves.
After running setup, you get shortcuts for common git, dev, and utility commands. All aliases work on both Linux/macOS and Windows.
Git shortcuts: ga, gaa, gc, gcm, gcb, gco, gd, gds, gf, gfp, ggs, ggsls, ggsp, gl, glog, gp, gpf, gpl, grb, grbi, grs, grss, gs
GitHub CLI: ghpr, ghprl, ghprv, ghis, ghiv
Dev tools: uvr, uvs, ni, nr, nrd, nrt, py, c, gosquad
Utility: myip, pb, h, ep
tmux/psmux: ta (attach), tt (new session), tls (list sessions), tks (kill server)
Navigation (Linux/macOS only): .., ..., ...., ~, -
ls shortcuts (Linux/macOS only): ll, la, l, lh
Full definitions:
- Linux/macOS:
config/dotfiles/.aliases(bash/zsh only -- see header for the non-POSIX features in use) - Windows:
scripts/windows/setup.ps1(theWrite-PowerShellProfilefunction)
Three helper functions are available after setup:
create_tmux -- Create or attach to the tank_dev tmux session. If the session exists, attaches to it. If not, creates it first.
create_tmuxstart_up -- Shortcut that calls create_tmux. Use this in your shell startup for auto-attach.
start_upNew-PsmuxSession -- Create or attach to the tank_dev psmux session (Windows equivalent of create_tmux).
New-PsmuxSessionBoth setup.sh and setup.ps1 automatically configure git to use this repo's hooks directory:
git config core.hooksPath hooksNo manual copying needed. After running setup, four hooks are active:
Six ordered hygiene checks (fastest-first); the commit is blocked if any check fails:
- Branch ancestry -- feature branches must descend from
develop. Catches accidental forks-of-forks. - ASCII-only content on staged
.ps1,.md, and.shfiles. PS 5.1 on Windows uses CP1252, so non-ASCII bytes (em dashes, smart quotes, curly apostrophes) break string literals; Markdown and shell sources should also stay ASCII-clean for portablegrep/sed/diff. If a.mdfile trips this check, runpython scripts/lib/ascii-sweep.py --dry-runto preview fixes, then drop--dry-runto apply (see below). The sweep preserves fenced code blocks verbatim, so any non-ASCII inside...must be cleaned by hand. - Refuse direct commits on
develop/main/master-- create a feature branch first. - Shellcheck on staged
.shfiles. Silently skipped ifshellcheckis not installed.
Enforces Conventional Commits format:
type(scope): description
Valid types: feat, fix, docs, style, refactor, test, chore, ci, build, perf, revert. Hard reject on non-conforming messages.
Rewrites git's auto-generated merge/revert commit messages into Conventional Commits form so commit-msg can validate them (e.g. Merge pull request #N from USER/BRANCH -> merge(pr): #N from USER/BRANCH, Revert "SUBJECT" -> revert: SUBJECT). Non-matching messages are left unchanged.
- Blocks direct pushes to
main(hard stop). - Runs shellcheck on changed
.shfiles -- advisory, never blocks (Linux/macOS). - Runs PSScriptAnalyzer on changed
.ps1files -- advisory, never blocks (requirespwsh+ PSScriptAnalyzer module; silently skipped if absent).
Use --no-verify to bypass hooks in emergencies.
Auto-replaces common non-ASCII characters in repo source files -- em/en dashes, smart quotes, ellipsis, arrows, box-drawing glyphs, status emoji -- with ASCII equivalents. The usual trigger is pre-commit Check 2 rejecting a commit because a Markdown file picked up Unicode punctuation from a paste.
python scripts/lib/ascii-sweep.py --dry-run # preview replacements
python scripts/lib/ascii-sweep.py # apply in-placeWhen NOT to use it: the sweep deliberately preserves fenced code blocks (...) verbatim, so it will not touch non-ASCII inside code fences. The pre-commit ASCII check does NOT respect fence boundaries -- if your non-ASCII bytes are inside a code fence (e.g. a file-tree drawn with box-drawing glyphs), the sweep will report them as "remaining" and you must hand-convert. Added in Sprint 13 (#322A / PR #335).
Tool versions are pinned in .tool-versions at the repo root (asdf/mise format). This file is the single source of truth for every tool version installed by setup, including nvm-windows. Setup scripts read it directly via scripts/lib/read-tool-version.sh (POSIX) and scripts/lib/Read-ToolVersion.ps1 (Get-ToolVersion) -- no asdf or mise dependency needed.
nodejs 22.11.0
nvm 0.39.7
nvm-windows 1.2.2
uv 0.4.18
copilot-cli 1.0.48
gh 2.92.0
To bump a tool version, edit the version number in .tool-versions and re-run setup. Each line is toolname version, one per line. Blank lines and lines starting with # are ignored.
Dotfiles: Edit or add templates in config/dotfiles/. Each file is copied into your home directory on first run. Existing files are not overwritten unless you pass --force.
Adding a tool: Drop a new script in scripts/linux/tools/ (or scripts/windows/) following the naming pattern of existing tools, then call it from scripts/linux/setup.sh (or the Windows equivalent). Scripts must be idempotent -- check whether the tool is already installed before doing anything.
When a sprint wraps, every issue and PR carrying its sprint:N label needs the same end-state transition:
- remove
release:backlog(if present) - add
release:shipped-X.Y.Z(if missing)
Type, area, and priority labels are never touched.
This is done by scripts/sprint-end-labels.sh and the matching workflow .github/workflows/sprint-end-labels.yml.
Manual / local run (dry-run by default for safety):
scripts/sprint-end-labels.sh \
--sprint sprint:17 \
--release-label release:shipped-1.17.0 \
--dry-runRemove --dry-run to apply changes.
Workflow trigger: Actions tab -> "Sprint End Labels" -> Run workflow. Inputs: sprint_label, release_label, dry_run (defaults to true).
Verification (HARD REQUIREMENT): After every label op, the script re-queries the issue and asserts the desired state. On mismatch it retries the read (not the write) with exponential backoff -- 1s, 2s, 4s -- then fails loudly. The CLI's exit code alone is treated as necessary-but-not-sufficient.
Idempotent: Safe to run twice. A second run finds no work to do.
Tested by: tests/test_sprint_end_labels.ps1 -- six scenarios including a function-override harness that exercises both the retry-and-succeed and fail-loudly-after-3 paths without hitting the GitHub API.
See CONTRIBUTING.md for the full contributor workflow: branch naming (feat|fix|chore|docs|refactor/{issue}-{slug} from develop), PR checklist, Conventional Commits format, test harness pattern.
All commits follow Conventional Commits format: type(scope): description. Valid types: feat, fix, docs, style, refactor, test, chore, ci, build, perf, revert. The commit-msg hook enforces this; prepare-commit-msg rewrite auto-converts merge/revert messages to Conventional Commits form.
PRs to develop use regular merge commits (not squash) for full history preservation. Release cuts from develop to main also use regular merges.
- ARCHITECTURE.md -- full technical overview, OS detection logic, script conventions, Windows dependency order, and a guide for adding a new tool.
- CONTRIBUTING.md -- contributor workflow, branch naming, PR checklist, test harness pattern.
- CHANGELOG.md -- release history in Keep a Changelog format.
For deeper technical detail -- OS detection logic, script conventions, decision records -- see ARCHITECTURE.md.