On this page you take a Mac with nothing on it to a working DevStride machine. You paste one line into Terminal; setup installs and configures the rest, stops only when it needs you, builds your machine its own AWS stage, and finishes by proving the machine works with the word READY. The same page covers an agent machine (one that runs Claude Code with nobody at the keyboard): the differences are under Agent machines.
Have these ready:
devstride/devstride (the product) and devstride/ds-docs (these docs, which setup clones beside it);Open Terminal and paste this line, all of it:
{ command -v brew >/dev/null || [ -x /opt/homebrew/bin/brew ] || [ -x /usr/local/bin/brew ] || /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"; } && eval "$(command -v brew >/dev/null && brew shellenv || /opt/homebrew/bin/brew shellenv 2>/dev/null || /usr/local/bin/brew shellenv)" && { command -v gh >/dev/null || brew install gh; } && { gh auth status -h github.com >/dev/null 2>&1 || gh auth login -h github.com -p https -w; } && { [ -d ~/dev/devstride/.git ] || gh repo clone devstride/devstride ~/dev/devstride || { echo "Your GitHub account cannot see devstride/devstride yet: ask an admin to run ds team add-developer for you, accept the invitation, then paste this line again."; false; }; } && cd ~/dev/devstride && ./setup
It does five things, skipping any that are already done:
~/dev/devstride;./setup.Pasting it again on a machine that has some or all of this just carries on, and an existing clone keeps its branch and your changes. If it stops with "Your GitHub account cannot see devstride/devstride yet", your access has not been granted or accepted: see Before you start.
For an agent machine, answer agent at setup's first question, or run ./setup --agent <name> (see Agent machines).
./setup first installs what it needs to run at all: mise (a tool that installs the exact Node and pnpm versions the repository pins), Node, pnpm and the repository's dependencies. Then it asks a few questions, each remembered for later runs:
Setup checks everything and lists every change it would make, stage by stage, then the moments it will wait for you, then the changes to what your agents may do. On a blank Mac the list is long; its last part reads like this:
It stops and waits for you at:
containers: install Docker Desktop and run its installer (accepts Docker's licence) — asks for your Mac password
agents: sign in to Claude Code in the browser
agents: sign in to Codex in the browser
aws: sign in to AWS once in the browser
machine: wait for you to sign in to GitHub when the GitHub CLI is signed out (gh auth login)
Then it proves the machine works:
proof: ...
Answering y also allows these changes to what your agents may do (--yes never does):
plugin: Setup is about to change what Claude Code may do on this machine without asking you: ...
plugin: Setup is about to mark ~/dev/devstride trusted in Claude Code: ...
plugin: Setup is about to make ~/dev/devstride a trusted Codex project and approve its committed hooks, ...
Nothing that is already right is touched, and running this again is safe.
Proceed? [y/N]
Type y and press Enter. That one answer covers everything listed, including the three changes to what your agents may do:
develop or master, and the AWS sign-in check). Setup records it exactly as Codex's own /hooks screen would, and lists the commands Codex will then run.Pressing Enter alone means no: setup then only reports and changes nothing. ./setup --yes answers the plan for you but never allows those three changes, and setup never makes them when an agent ran it.
Setup stops at each of these, says exactly what to do, and carries on by itself once you have done it:
If Codex still does not run the repository's hooks after setup recorded the approval (because a new Codex release changed its record, say), setup opens Codex for you to approve them by hand once: type /hooks, approve the repository's hooks, then type /quit.
Every question and sign-in comes before the last stages. Once the demo data starts building, setup needs nobody: the demo data takes a few minutes, and your AWS stage after it about half an hour more. A good moment to get a coffee.
For a sign-in or an installer, setup runs it first and, if it did not finish, offers s to skip it for now. Setup then finishes everything that does not depend on that step and lists what is left. Ctrl-C stops setup at any point. Either way, run ./setup again later: it picks up from where it stopped.
You install none of this by hand:
Brewfile: the AWS CLI and AWS's credential helper, git, jq, Neon's command-line tool, OpenSSL 3, psql (PostgreSQL 15's client, linked onto your PATH only when you have no psql already) and poppler (which turns PDF pages into images, for the agents). Node and pnpm at the versions the repository pins, unless the right ones are already there./devstride:* commands), the connection to DevStride and the settings both agents need here.It then:
~/dev/devstride/.worktrees/wt1 and wt2 (agents work there; the clone itself is the main checkout, where you work), with their dependencies and their own generated types;.env from the team's secrets (see Credentials and access);ds on your PATH (~/.local/bin/ds runs the ds of whichever DevStride checkout you are in);~/dev/ds-docs.If you already run Node through nvm, fnm, Homebrew or another version manager, setup's shell block keeps the Node your terminal runs today. After writing the block, setup opens a fresh login shell, compares the Node and pnpm it finds with the ones before, and if either would change it takes its block back out and tells you. Your startup files are then exactly as they were (setup also keeps a copy of each file it changed, ending .before-devstride-setup). See Troubleshooting.
Setup ends by listing what it changed and, when anything is left, up to three lists:
Open a new terminal now. ds and the pinned Node come from the startup block setup just added, so a new terminal finds them. (In the terminal setup ran in, use ./ds.) Setup writes that block for zsh and bash; for any other shell it prints the lines to add yourself.
Setup's last stage proves the machine works: ds machine ready. It ends with one word. READY means no proof failed. Check again at any time:
ds machine ready # the full proof: a few minutes, it starts apps and runs a landing check
ds machine ready --quick # in seconds: no app started, no model called (what the hourly check runs)
A quick proof right after setup looks like this (shortened):
Proving this machine (jane-mac, a person's own machine) — quick: no app started, no model called:
pass tools: node, pnpm, git, gh, aws, jq, neonctl, OpenSSL 3, psql, pdftoppm, docker, claude, codex, python3
pass aws: dev account, secrets
pass github: your sign-in
pass devstride: agent key, Claude Code's connection, Codex's connection
pass checkouts: main dependencies, main demo data, main database, wt1 ..., wt2 ...
pass claude: signed in, plugin, settings, trusts this repository, hooks, guard refuses a push to develop, ...
pass codex: signed in, reads all of AGENTS.md, review engine settings, plugin
pass machine: git identity, shell startup files, ds from anywhere, docs repository
pass credentials: main .env, wt1 .env, wt2 .env, agent file
pass stage: recorded, stacks, config, database
READY
Each line is one of:
The full proof also starts each checkout's app and signs in as the demo user, runs the landing check (the same check every change runs before it lands) in a free checkout, and asks Codex one line.
A few things only you can do, once:
ds machine ready remind you under When you can.acme.devstride, password Demo@123 (a username, not an email). After a restart, start Docker Desktop, then run ds worktree up main. Local Development explains the local stack.Every machine gets its own AWS stage: a full copy of DevStride in the dev account, named after the machine, that you and your agents can deploy to and test against without touching anyone else's. Setup's stage step builds it once the demo data is in place, in about 30–40 minutes, unattended:
stage-<stage>, made from the team's golden-data branch);acme.devstride and the others, password Demo@123) and today's dates.Its name and database are recorded in your machine's secrets bundle, so every checkout's .env knows them. After that, setup only checks the stage: it never redeploys it because develop moved on.
To run a checkout against your stage instead of Docker:
export DEVSTRIDE_SESSION=<your name>
ds pool checkout wt1 --purpose "<what you are doing>" # take wt1; export the token it prints as DEVSTRIDE_LEASE_TOKEN
ds pool cloud wt1 # run wt1's own code against your stage: the backend in live mode, and the UI
ds pool cloud wt1 --off # back to Docker
ds pool checkin wt1 # hand wt1 back when you are done
One checkout per machine can run against the stage at a time. The Develop page explains the checkout pool and its leases.
When ds machine ready notes that the stage's database is behind your checkout's code, bring it level from that checkout:
DEVSTRIDE_STAGE=<stage> DEVSTRIDE_REGION=us-east-1 ./ds -b migrations run
Two more things you may need:
https://api-<stage>.devstride.dev/v1/subscriptions/stripe/webhooks, listening to charge.refunded, charge.refund.updated and refund.updated on your account. Store its signing secret in your machine bundle: pbpaste | ds secrets set machine STRIPE_WEBHOOK_SECRET, then ds secrets pull.ds stage remove --dry-run shows what removing your stage would delete; without --dry-run you retype the stage name to confirm. It is permanent: the stage's data and sign-in users go with it. Running ./setup again builds a fresh one.The stage needs the team's Neon key on your machine. If setup lists the stage under Needs you, see Troubleshooting.
Run ./setup whenever you like; every step checks before it changes anything. On a machine that is already set up it prints Nothing to change. and then still runs the proof. ./setup --dry-run only reports. ./setup --skip <stages> leaves stages alone (for example --skip stage to leave your AWS stage for another day). Setup treats a skipped stage as already done, so a later step that relies on it still runs, and reports what it could not do. ./ds machine setup --help lists every option, and the command reference lists the eleven stages.
Setup's own log is .ds/machine-setup.log in the main checkout; the demo-data build writes to .ds/machine-setup-data.log, the stage's first deploy to .ds/stage-deploy.log in the checkout it deployed from, and the full proof to .ds/machine-ready.log.
./setup --agent <name> sets up a machine that will then run Claude Code sessions with nobody at the keyboard. You sit at it while setup runs. The name you give it (2 to 41 lowercase letters, digits and hyphens, for example m5-philreynolds) becomes its AWS identity, its own secrets bundle, its AWS stage and its row in ds fleet status. Never reuse a name another machine has had.
What setup does differently:
./setup at that machine's own terminal and type y does.ds machine doctor) keeps the idle checkouts current and reports every checkout's health to ds fleet status. It runs as a launchd job (launchctl print gui/$UID/com.devstride.machine-doctor shows it) and logs to ~/.devstride/logs/machine-doctor.log.Browser sign-ins are yours to do once. A few sites have no key an agent can hold: the Seed and Neon consoles, Stripe, Intuit, Azure and the DevStride app. On each agent machine, add a Chrome profile named DevStride Agent in the same macOS user the agent runs as, enable Claude in Chrome there, and sign that profile in to each site once. Agents then work there and never type a password. Nothing can check a browser's sign-ins, so the READY report lists them as a reminder.
Renewing (yearly, or to replace a machine's identity): ds machine enroll <name> --force, then ./setup --agent <name>, which signs and installs the new certificates from one approval.
Retiring or losing a machine is an admin's job: see For admins.
On your own Mac, and never on an agent machine, setup also installs these, so every developer starts from the same place:
~/.zshrc from Oh My Zsh's template (the robbyrussell theme and the git plugin) and keeps its own startup block after it. To change the theme or the plugins, edit ZSH_THEME and plugins in ~/.zshrc, outside setup's marked lines.If your ~/.zshrc already has lines of your own, setup never rewrites it. It installs Oh My Zsh in ~/.oh-my-zsh and, at the end of that run, lists under When you can the four lines that turn it on. If your shell is not zsh, setup leaves Oh My Zsh out. Setup looks for all of these on every run, so it installs any one again if it has been removed.
./setup runs on Linux too, but only the Mac route has been tried end to end. It needs Homebrew (it installs it only when Node or pnpm is missing too) and python3, and lists what it cannot install with the command to run yourself: Docker Engine (and adding yourself to the docker group) and Codex (npm install -g @openai/codex). Chrome, the desktop apps and keeping the machine awake are Mac-only; the hourly check runs as a systemd timer.
Before a change to setup is released, someone runs it on a Mac that has never had DevStride on it: a new Mac, or one erased (a new user account is not enough, because Homebrew and Docker are installed for the whole Mac). Paste the line above with one change, so it clones the branch being tested: replace gh repo clone devstride/devstride ~/dev/devstride in it with gh repo clone devstride/devstride ~/dev/devstride -- --branch <the branch>.
When a step fails, send back the line setup printed for that step, .ds/machine-setup.log, and for the demo data .ds/machine-setup-data.log. Every place this page and the Mac disagree is a bug in one of them. The repository's setup rehearsal proves setup's order and waits on every change, with stand-ins for every outside program; only a real blank Mac proves Homebrew's and Docker's own installers.
If something goes wrong, see Troubleshooting.
Next: Credentials and access
Overview
The developer guide's path from a Mac with nothing on it to your first merged story: what you will have at the end, how long it takes, and where you are needed.
Credentials and access
Where every tool's key on a DevStride machine comes from, who creates and rotates it, how setup fetches the team's keys, and what a retired machine still holds.