Local Development Workflow
The 30-minute merge β deploy β rebuild cycle is a release pipeline, not the edit-test loop. Everything below runs entirely on your machine. You should only deploy to ship a change that already passed locally.
Golden rule: never merge to main to test. Merge is the last step, after
local tests pass on your branch.
The loop, start to finish
1. Start Claude
cd ~/Projects/accessibleclaudeOr let the dev script launch it for you (it starts the stack first β see below).
2. Start the emulators (the local stack)
One command brings up Supabase (Kong on :8000), MinIO, LocalStack, the API +
batch worker, and the Python sidecars (docx2acroform, flyer-tagger, veraPDF,
WeasyPrint, β¦):
docker compose -f docker-compose.yml -f docker-compose.dev.yml --profile local up -dOr use the wrapper, which also stops any stray CLI supabase stack, parks the
second API replica, streams logs, and (in a real terminal) launches Claude:
accessible-dev # web onlyaccessible-dev --all # every appaccessible-dev --apps=web,formsSupabase split-brain gotcha: use the compose Supabase (Kong
:8000), NOT the CLIsupabase startstack. If both run they fight over54322/3/4, the API points at nothing, and the web app silently talks to prod.setup-local.sh/accessible-devstop the CLI stack for you.
3. Work in the main checkout, on a branch
Use one checkout (~/Projects/accessible) and a feature branch inside it:
git checkout -b feature/<short-description>The stack serves whatever source is on disk in the checkout you launched
docker compose from. One checkout + one branch = the stack always serves the
code youβre editing. (Do not run the active task from a separate git worktree
β the stack would keep mounting the other directoryβs source and your changes
would appear to βnot run locallyβ. Worktrees are for parallel work and for
subagents; see below.)
4. Refresh AWS creds if the feature calls Bedrock or Textract
The AI paths (PDF vision, the forms AI rebuild, Textract image lane) call AWS. Inject short-lived SSO creds once per session:
dev-aws-creds # logs into SSO (browser), writes creds, recreates sidecarsRe-run when the session expires (1β12h). Without creds these paths fall back to their deterministic non-AI behaviour rather than erroring.
5. Edit β hot-reload β test
| Service | Reload |
|---|---|
| API / batch worker (TypeScript) | tsx watch β ~2s, automatic |
| docx2acroform (Python/Flask) | gunicorn --reload β ~1s, automatic |
| flyer-tagger (Lambda RIE) | rebuild the image β no in-process watcher (bind-mount + docker restart once it lands in base compose) |
| Next.js apps | Fast Refresh β instant |
Code edits are free. A new dependency (npm or pip) needs one rebuild:
dev-rebuild # TS services (api / batch worker)docker compose -f docker-compose.yml -f docker-compose.dev.yml \ --profile local build docx2acroform # a Python sidecarExercise the change directly β hit the endpoint or click through the app on
localhost (see dev-ports for the appβport map; dev-proxy gives HTTPS
*.localhost names mirroring prod).
6. Run the branchβs tests
npm run test # or the workspace-scoped equivalentPython tools: cd tools/<tool> && python3 -m pytest -q.
7. PR when ready β push β merge
Only now does the branch leave your machine:
git push -u origin feature/<short-description>gh pr create --base main --fill# CI green + review β mergegh pr merge --squashDeploy happens off main as the release step β it is never how you test.
Delegating to isolated subagents
For parallel or well-scoped work, hand a task to a subagent that owns the full branch β PR β merge lifecycle itself, and runs in its own git worktree so it never touches your main checkoutβs working tree or the running stack:
- Give the subagent a single, verifiable goal (βadd X, with tests, open a PR to
mainβ). - It creates its own branch in an isolated worktree, implements, runs tests,
pushes, and opens the PR β merging to
mainwhen green. - Because it is isolated, several can run at once without clobbering each other or your local stack. Your main checkout keeps serving your branch to the emulators the whole time.
This is the one case where worktrees are correct: isolation for background work, not for the branch you are actively hot-reloading in the foreground.
Quick reference
accessible-dev [--all|--apps=β¦] # start stack (+ Claude), hot-reloaddev-aws-creds # refresh Bedrock/Textract SSO credsdev-rebuild [--api|--batch|--all] # rebuild TS service images (new deps)dev-ports [<app|port>] # app β port β prod-domain mapdev-proxy [up|reload|down] # HTTPS *.localhost namesdev-tail [api|web|both] # tail dev-server logsSee also: the project-local-dev-loop note in Claude memory for the deeper
gotchas (baked-image staleness, Kong readiness probe, seed/auto-login fixes).