Intro

Introduction to the ds CLI

What the ds CLI actually wraps, how ./ds resolves and runs a command, the global auth/bind flags, and the eighteen real top-level commands.

Introduction to the ds CLI

The ds command-line interface is the entry point for working with DevStride's AWS infrastructure and databases from a developer machine. It wraps AWS authentication and SST (the framework that deploys the backend Lambda/API Gateway stack and the frontend static site) behind a small set of Commander-based subcommands.

What ds Wraps

  • AWS, authenticated via AWS SSO (or, on an unattended agent machine, the machine's own certificate identity) — every AWS-bound invocation checks your session before doing anything else. The fully-local and machine-management commands skip that check; see The AWS SSO Gate.
  • SST — ds run backend runs sst dev (SST's live-lambda mode) against the backend; the frontend ships as an SST StaticSite in the same deploy.
  • Drizzle SQL migrations against the stage's bound PostgreSQL database.
  • Stripe, for a read-only billing inventory and test-mode proofs.
  • A CQRS code generator for scaffolding backend commands and queries.
  • The machine itself: the fully-local Docker stack, the fixed checkout pool and its leases, the secrets bundles that write .env, and an agent machine's certificate identity.

Postgres is hosted on Neon on every stage, and a few commands know that (ds golden push and import prefer the direct, non-pooled endpoint; ds data copy works around idle timeouts). Neon's copy-on-write branching is not exposed as a CLI operation: seeding goes through pg_dump/pg_restore and additive org copies instead. There is no infrastructure-as-code tool here beyond SST.

Entry-Point Mechanics

ds is not a single monolithic program — it's a thin bash dispatcher that compiles and runs one TypeScript file per invocation. The chain is:

./ds [-b] [-r] [-u] <command> [subcommand] [args]
    │
    ├─ ./ds                     ← root bash script: parses -b/-r/-u, runs the SSO gate,
    │                              resolves/regenerates the stage+region bind cache
    │
    ├─ ./cli/run_script.sh       ← esbuild-bundles cli/commands/<command>.ts
    │                              to .ds/.tmp/<command>.mjs
    │
    └─ node .ds/.tmp/<command>.mjs "$@"   ← the actual Commander program runs,
                                             then the temp bundle is deleted

Concretely, running ds migrations run:

  1. ./ds parses wrapper flags, runs the SSO gate (unless -u), resolves the stage/region bind cache, then hands off everything after the flags to cli/run_script.sh.
  2. cli/run_script.sh takes $1 (migrations) and calls node ./cli/bin/build.js ./cli/commands/migrations.ts ./.ds/.tmp/migrations.mjs — an esbuild bundle, built fresh on every single run.
  3. It executes that bundle with the remaining args (run), which resolves to a Commander subcommand inside cli/commands/migrations.ts.
  4. On exit, it deletes the temp .mjs/.mjs.map and propagates the child process's exit code.

Every top-level command is its own file under cli/commands/*.ts — there is no central command registry; each file builds its own Commander program and parses process.argv independently.

Global Wrapper Flags

These three flags belong to the ./ds wrapper itself, not to any subcommand, and must come before the command name:

./ds [-b] [-r] [-u] <command> [subcommand] [args]
FlagEffect
-bForce a re-bind of the stage/region config, even if a cached .ds/bind/<stage>-<region>.env already exists.
-rTarget remote: unsets IS_LOCAL and sets DEVSTRIDE_REMOTE=true.
-uSkip the AWS SSO auth check entirely for this invocation.

The AWS SSO Gate

For any AWS-bound command, ./ds runs an AWS auth check before your command's code ever executes:

  1. If DEVSTRIDE_DEV_PROFILE is set, it's exported as AWS_PROFILE.
  2. AWS_SDK_LOAD_CONFIG=1 is exported, so AWS SDK v2 (used by some Node-side scripts) reads SSO profiles from ~/.aws/config instead of only ~/.aws/credentials.
  3. aws sts get-caller-identity is run. If it succeeds, you'll see Already authenticated. If it fails, what happens next depends on who could finish a login:
    • A person at a terminal — stdin or stderr is a terminal — gets No active session found. Logging in... and the browser login (aws sso login). This includes a person pushing from a terminal, whose git hooks still show stderr.
    • No terminal at all — an agent's shell — gets one line naming the exact command, aws sso login --profile <profile>, and ./ds exits 1 without running your command. It used to open the device-code login where nobody could see it and appear to hang for minutes.
    • A machine certificate identity (a profile written by ds machine enroll) is never sent to a login, because a login cannot repair a certificate. ./ds says the identity was refused — the machine was revoked, its certificate expired, or its key is gone — and exits 1.

Stage/Region Bind Cache

After the SSO gate, ./ds resolves which stage and region you're targeting and caches that resolution to disk:

  • The cache file lives at .ds/bind/<DEVSTRIDE_STAGE>-<DEVSTRIDE_REGION>.env.
  • If that file doesn't exist yet, or you passed -b, ./ds runs node ./cli/bin/store_bind.mjs $DEVSTRIDE_STAGE $DEVSTRIDE_REGION to (re)generate it.
  • The resulting .env file is exported into the shell environment before cli/run_script.sh is invoked, so every subcommand sees a consistent, already-resolved stage/region without re-deriving it itself.

In practice this means the first ./ds command after switching DEVSTRIDE_STAGE or DEVSTRIDE_REGION pays a one-time bind cost, and every subsequent invocation reuses the cached file until you force a refresh with -b.

The 18 Top-Level Commands

There are twenty top-level commands, one file each under cli/commands/. Each is its own Commander program — there's no shared subcommand namespace beyond these eighteen.

CommandWhat it doesCovered in depth
ds runRuns the backend via sst dev (live-lambda mode), starts the frontend Vite dev server, or (ds run local) brings up the fully-local docker stack.Local Development
ds migrationsRuns Drizzle SQL migrations against the bound stage's PostgreSQL database.Local Development
ds dataImports, exports, wipes, or org-scoped-copies SQL table data on the bound stage.Local Development
ds goldenBuilds, publishes, imports, reanchors, and manages the Acme golden demo/test dataset.Golden Dataset
ds scriptA grab-bag of one-off maintenance, diagnostic, and codegen scripts (config push, orphan cleanup, DB reset, and more).Maintenance & Codebase Checks
ds stripeExports a read-only billing inventory and runs test-mode proofs of the Stripe behaviour billing relies on.Stripe Integration
ds gScaffolds a new CQRS command or query into a backend module.Local Development
ds worktreeManages sandboxed per-worktree docker instances (create/list/remove, run CLI commands against one). Like ds run local, it skips the SSO gate and bind entirely.Dockerized Worktree Development
ds poolReserves, resets and hands back the machine's fixed checkouts (main, wt1, wt2) with a lease; copies one customer organization in for a repro; or runs one checkout against this machine's own cloud stage.Dockerized Worktree Development
ds workStarts one item on the branch it belongs to — its Epic's integration branch, else the support train — and lands it there after the local checks. Never merges to develop or master.Dockerized Worktree Development
ds merge-pathSays whether a branch may open a pull request into develop: the same ALLOWED / BLOCKED verdict the required merge-path check posts.Command Reference
ds verifyRuns the local mirror of CI: land, the check every Story and one-off passes before it merges, and full, everything cloud CI runs on a release pull request, which posts the local-ci status every pull request into develop needs.Command Reference
ds secretsWrites every pool checkout's .env from the dev account's secrets bundles (and the agent's credentials to their own private file), and changes one value in a bundle.Credentials and access
ds machineTakes a bare machine to ready (setup, which ./setup runs), proves it works (ready), keeps its checkouts current (doctor), and gives an unattended agent machine its own certificate-backed AWS identity, shut off with a single revoke.Set up your machine
ds fleetLists every agent machine and its checkouts: who holds each, its branch and whether it is healthy.Command Reference
ds agentWires an agent's DevStride MCP connection and GitHub access from the agent bundle.AI Development
ds quickbooksReads QuickBooks Online through the agent's own grants — every call names the company.AI Development
ds graphLooks up Microsoft Entra accounts and rotates the agent app's own client secret.AI Development
ds seedAsks Seed to redeploy one chosen commit to one stage, with the team's shared Seed token (it can deploy production).Command Reference
ds neonRuns Neon's command-line tool with the team's shared Neon key and DevStride's organisation, never a person's own Neon sign-in.Command Reference

Next Steps

  • Command Reference — the complete list of every subcommand and flag across all eighteen commands
  • Local Development — running the backend and frontend day-to-day, migrations, and data import/export
  • Dockerized Worktree Development — many isolated no-AWS instances at once, one per git worktree, each with its own dataset
  • Golden Dataset — the Acme demo/test fixture and where its canonical docs live