Developer Guide

Set up your machine

From a Mac with nothing on it to READY with one pasted line: what to have ready, what setup asks, what it installs, your own AWS stage, and what to do after.

Set up your machine

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.

Before you start

Have these ready:

  • An administrator account on the Mac. Homebrew's installer and Docker's installer ask for its password.
  • Your GitHub and AWS access. An admin gives you both with one command (see For admins). You then:
    • accept the two GitHub invitations, to devstride/devstride (the product) and devstride/ds-docs (these docs, which setup clones beside it);
    • set your AWS password: sign in at https://devstride.awsapps.com/start with your work email, and follow the code or link AWS emails you. If nothing arrives, ask the admin: their command printed the one step that sends it.
  • A claude.ai account for Claude Code and a ChatGPT account for Codex.
  • Enough Mac for Docker. Setup checks that Docker has at least 4 CPUs and 8 GB of memory, which the test suite needs.

1. Paste the one line

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:

  1. installs Homebrew, the Mac's package manager (it asks for your Mac password once, and adds Apple's command line tools and git on the way);
  2. installs the GitHub CLI;
  3. signs you in to GitHub in the browser;
  4. clones the repository to ~/dev/devstride;
  5. runs ./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).

2. Answer the first questions

./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:

  • whether this is your own machine or an agent machine (press Enter for your own);
  • this machine's name (press Enter to keep the one shown, or type another: 2 to 41 lowercase letters, digits and hyphens). It also becomes the name of your AWS stage;
  • when git has none yet, your name and email for commits (GitHub's are offered; press Enter to take them).

3. Read the plan, then say yes once

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:

  • Claude Code's permission settings: every rule setup adds is printed, so you can read what Claude Code may then do here without asking you.
  • Claude Code trusting this repository, so its committed settings and hooks apply in all three checkouts without a first-session prompt.
  • Codex's approval of the repository's hooks (the merge guard, which stops a push straight to 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.

4. The moments it waits for you

Setup stops at each of these, says exactly what to do, and carries on by itself once you have done it:

  • Your Mac password, for Docker's installer. Installing Docker Desktop runs Docker's own installer, which accepts Docker's licence for you and sets up its helper. Setup forgets the password straight after.
  • Browser sign-ins: Claude Code (with your claude.ai account), Codex (with your ChatGPT account), AWS (once, with the sign-in your admin created), and GitHub again only if the GitHub CLI has been signed out. Each opens a browser window; approve the sign-in there. Where no browser can open, setup shows a link and a code instead.

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.

What setup installs

You install none of this by hand:

  • Tools, from the repository's 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.
  • Docker Desktop, started and checked for enough CPUs and memory.
  • Claude Code and Codex, signed in, with the DevStride plugin (the /devstride:* commands), the connection to DevStride and the settings both agents need here.
  • Google Chrome, with the Claude in Chrome extension waiting to be enabled. Agents do their browser work through it (see After setup).
  • On your own Mac only: the Claude and ChatGPT desktop apps, iTerm2 and Oh My Zsh (see Your own tools).

It then:

  • makes the two extra checkouts, ~/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;
  • writes each checkout's .env from the team's secrets (see Credentials and access);
  • starts the main checkout's app in Docker, and fills all three checkouts with the demo data;
  • builds this machine's own AWS stage (see Your AWS stage);
  • adds a marked block to your shell's startup files, and puts ds on your PATH (~/.local/bin/ds runs the ds of whichever DevStride checkout you are in);
  • clones the docs site to ~/dev/ds-docs.

Your Node stays your Node

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.

5. When it finishes

Setup ends by listing what it changed and, when anything is left, up to three lists:

  • Needs you: a step only you can do, with the command to do it.
  • Waiting on the above: steps that wait for one of those.
  • When you can (nothing waits on these): notes that never stop the machine being ready, such as enabling Claude in Chrome.

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.

READY

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:

  • pass: proven.
  • FAIL: not working, with the fix on the same line. Any FAIL makes the verdict NOT READY, which names the first failure.
  • held: another session is using that checkout, so it could not be proven. Not a failure; run the proof again when it is free.
  • you: a step only you can take, for example Claude Code's settings when an agent ran setup.
  • note: something to do when you can. Never a failure.

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.

After setup

A few things only you can do, once:

  • Enable Claude in Chrome. Open Chrome. It offers the Claude extension: click Enable, then sign in to Claude in it. Until you do, setup and ds machine ready remind you under When you can.
  • Sign in to the desktop apps (your own Mac): open Claude and ChatGPT from Applications and sign in.
  • Open the app. The main checkout's app is running at http://localhost:8080. Sign in with a demo login: 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.

Your AWS stage

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:

  • a copy of the demo data on its own Neon database branch (stage-<stage>, made from the team's golden-data branch);
  • the stage's config and its first deploy;
  • the database migrations, the demo logins (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:

  • Stripe. Your stage uses the team's test-mode keys, but needs its own webhook. In the Stripe test dashboard, add the endpoint 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.
  • Removing it. 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.

Running it again

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.

Agent machines

./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:

  • One AWS approval, then its own identity. Setup asks you to approve one AWS sign-in in the browser, and uses it to issue the machine its own certificates for the dev and production accounts. AWS exchanges those for short sessions named after the machine, so no person needs to sign in again until the certificates are renewed, once a year. Setup then removes that sign-in. The approval must come from someone who can sign with the management account (an administrator); without that access, setup names the other route: an administrator signs the machine's two requests on their own machine, and you save the two certificates where setup says and run it again (the administrator route has the steps).
  • No changes to what the agents may do. Setup never writes Claude Code's settings, trust or Codex's hook approval on an agent's behalf: the first person to run ./setup at that machine's own terminal and type y does.
  • It stays awake on mains power: setup asks for your Mac password once more to set this.
  • Docker Desktop starts by itself whenever you sign in to the Mac.
  • An hourly health check (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.
  • FileVault: setup reports whether it is on and leaves the choice to you. On, the machine's disk (and its keys, which reach production) stays encrypted if it is lost, but after a restart it waits at the unlock screen until someone signs in. Off, it can sign in by itself after a restart; only choose that for a machine kept somewhere physically secure.

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.

Your own tools

On your own Mac, and never on an agent machine, setup also installs these, so every developer starts from the same place:

  • The Claude and ChatGPT desktop apps, from Homebrew.
  • iTerm2, a terminal app, from Homebrew. Open it from Applications or Spotlight and use it instead of Terminal.
  • Oh My Zsh, which gives zsh its prompt, themes and plugins, with its own installer. On a new Mac, setup starts ~/.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.

Linux

./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.

Trying it on a blank Mac

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