Skip to main content

Getting Started


What this helps you do

Use this page to prepare a local Green Goods checkout, choose the right development profile, start the services you need, and verify that the web stack responds before you begin package work.

Before you start

Before cloning, install the tools the setup script cannot reliably provide:

ToolMinimumRequired forInstall
Node.js22+Running npm run setup and repo toolingnodejs.org
GitanyCloning and contributinggit-scm.com
Docker Desktopcurrent stableFull-stack and indexer developmentdocker.com

Node includes npm, which is enough to run the first setup command. npm run setup installs Bun automatically if it is missing, installs workspace dependencies, and prints the env-bootstrap commands to run next.

Additional tools are workflow-specific:

ToolRequired forInstall
FoundryContract development and testscurl -L https://foundry.paradigm.xyz | bash && foundryup
cloudflaredHTTPS tunnel for mobile-device testingbrew install cloudflared

Docker, Foundry, and cloudflared warnings do not block setup unless you are working in the matching workflow.

Operating system support

OSSupport levelNotes
macOSNativeStandard local path. Full stack uses the Docker-backed indexer to avoid native Envio/Rust issues.
LinuxNativeGood path for native indexer work, provided Docker and generated indexer dependencies are ready.
WindowsWSL2 or dev containerNative PowerShell is not a supported target yet because repo scripts use POSIX shell tools such as sh, bash, lsof, xargs, pkill, and shell env syntax.

Use WSL2 for Windows contributors until a dedicated native Windows script pass lands.


Running Development Setup

git clone https://github.com/greenpill-dev-guild/green-goods.git
cd green-goods
npm run setup # first-clone bridge: deps and workspace install
bun run env:sync # materializes .env from .env.template via 1Password (op inject)
bun run dev:doctor -- --profile web # non-mutating web readiness check
bun run dev:web # starts client, admin, docs, and Storybook
bun run dev:smoke:web # confirms browser surfaces respond locally

bun run env:sync requires the 1Password CLI signed in with desktop app integration on. If you are not on the team and do not have vault access, copy .env.template to .env and fill local values directly (see Required Secrets & Variables).

npm run setup is the only npm entrypoint in the normal workflow. It exists because a fresh machine may not have Bun installed yet. After setup, use bun run ... for package operations and repo scripts.

What npm run setup does

The setup script (scripts/dev/setup.js) runs through three steps:

  1. Dependency check -- verifies Node.js 22+ and Git, installs Bun if needed, and warns about missing workflow-specific tools.
  2. Install packages -- runs bun install across all workspaces if node_modules does not exist yet.
  3. Next steps -- prints the env-sync, doctor, frontend stack, full stack, and test commands.

Environment files are materialized separately by bun run env:sync (which runs op inject against .env.template). See Required Secrets & Variables below.

Role profiles

RoleRequired local stateFirst command
Frontend QANode.js, Git, Bun from setup, root .env, ports 3001/3002/3003/6006 availablebun run dev:doctor -- --profile web
Full-stack / indexerFrontend QA plus Docker, packages/indexer/generated, and generated dependenciesbun run dev:doctor -- --profile full
ContractsFrontend QA plus Foundrybun run dev:doctor -- --profile contracts
Upload-capable QAFrontend QA plus VITE_API_BASE_URL and PINATA_JWT_OP_REF=op://... or PINATA_JWT in root .envbun run dev:doctor -- --profile upload

Run bun run dev:doctor -- --profile web|full|contracts|upload any time you need a non-mutating check of the current machine. It reports missing tools, Docker state, Pinata readiness, passkey RP ID posture, indexer generated state, stale environment keys, and port conflicts without printing secret values. Add --json for machine-readable output in CI, containers, or agent workflows.


Required Secrets & Variables

Green Goods uses one root .env plus the committed .env.schema (full key contract) and .env.template (team-shared file with 1Password refs for shared secrets and plain values for non-secrets). Do not create package-level env files.

The standard flow:

bun run env:sync     # materialize .env from .env.template via op inject (Touch ID once)
bun run env:check # verify .env satisfies .env.schema

For details on regenerating the template (e.g. after a new key lands in .env.schema), and for first-time setup without 1Password access, see Environment management.

VariableRole
APP_ENVEnvironment selector (development, test, staging, production)
VITE_CHAIN_IDSets the target chain at build time (42161 for Arbitrum, 11155111 for Sepolia)
VITE_PASSKEY_RP_IDOptional passkey relying-party override. Leave blank for localhost development fallback; set localhost for explicit local passkey QA.
VITE_API_BASE_URLBrowser API origin. Upload-capable flows call the agent for short-lived Pinata signed upload URLs.
PINATA_JWTServer/script Pinata JWT used by the agent upload signer and maintenance scripts. Not embedded in browser bundles.
VITE_PINATA_GATEWAY_URLPublic Pinata gateway URL for reading IPFS media.
SEPOLIA_RPC_URLRPC endpoint for Sepolia fork tests

Variables prefixed with VITE_ are embedded into frontend bundles at build time.

For personal local-only credentials, put direct values in root .env. For shared Green Goods credentials (upload-capable QA, deploys, CI), edit .env.template to use 1Password URIs in the op://Vault/Item/field form, sign in to the op CLI, and run bun run env:sync.

Running services

Frontend stack

bun run dev:web launches the frontend developer stack through PM2:

PM2 processPackageDefault port
clientpackages/client3001
adminpackages/admin3002
docsdocs3003
storybookpackages/shared6006

This is the recommended first target for onboarding and frontend QA because it avoids Docker, indexer generated-code setup, and agent credentials.

After the processes are up, run bun run dev:smoke:web in another terminal. It reruns the web doctor, then checks that the client, admin, docs, and Storybook respond on their local ports.

Full stack

bun run dev launches every service through PM2:

PM2 processPackageDefault port
clientpackages/client3001
adminpackages/admin3002
docsdocs3003
indexerpackages/indexer (Docker / GraphQL)8080
agentpackages/agent--
tunnelcloudflared HTTPS tunnel--
browserlocal URL opener--
storybookpackages/shared6006

Stop everything with bun run dev:stop.

Individual packages

You can also run packages directly without PM2:

bun run dev:client      # Gardener PWA
bun run dev:admin # Operator dashboard
bun run dev:docs # Docusaurus site
bun run dev:indexer # Envio indexer (Docker Compose)
bun run dev:contracts # Anvil local chain
bun run dev:agent # Agent bot

Mobile device testing

Green Goods is a mobile-first PWA, so testing on a real phone is essential. When you run bun run dev, a cloudflared tunnel starts automatically alongside the other services. It creates a temporary public HTTPS URL (e.g. https://random-words.trycloudflare.com) that points to your local client on port 3001.

Once the tunnel is ready, the landing page QR code automatically switches to the tunnel URL. Open https://localhost:3001 on your laptop and scan the QR code with your phone — you'll get the full PWA experience including service worker, install prompts, and passkey auth.

# Tunnel starts automatically with bun run dev.
# To run it standalone (e.g. for the admin dashboard):
bun run dev:tunnel # default: port 3001
bun run dev:tunnel -- --port 3002 # admin on port 3002

If cloudflared is not installed, the tunnel service exits silently and the QR code falls back to window.location.origin. Install it with brew install cloudflared.

Alternative: ADB port forwarding

If you prefer a wired connection, plug in your Android device with USB debugging enabled and run:

adb reverse tcp:3001 tcp:3001

Then navigate to https://localhost:3001 on Android Chrome. Since localhost is a secure context, the service worker registers without a trusted CA certificate.

How to know it worked

  1. 1

    Read project rules

    Start with `AGENTS.md`, `CLAUDE.md`, and `.claude/context/*` for conventions.

  2. 2

    Configure env bootstrap

    Keep the generated root `.env` for baseline web dev. Add direct personal values only when needed; use 1Password refs for shared team, deploy, upload, or CI secrets. Never add package-level env files.

  3. 3

    Check role readiness

    Run `bun run dev:doctor -- --profile web` before debugging setup. It does not mutate files or start services.

  4. 4

    Start services

    Run `bun run dev:web` for frontend QA or `bun run dev` for the full Docker-backed stack.

  5. 5

    Smoke the web stack

    Run `bun run dev:smoke:web` once client/admin/docs/Storybook are starting. It verifies local HTTP/HTTPS reachability.

  6. 6

    Run the quality gate

    Run `bun run format:check`, `bun run lint`, `bun run test`, and `bun run build` before pushing changes.

Development workflow

The standard edit-test-build-lint cycle:

# 1. Run tests for the package you changed (always `bun run test`, never `bun test`)
cd packages/shared && bun run test

# 2. Check formatting and lint the workspace
bun run format:check
bun run lint

# 3. Build (respects dependency order: contracts -> shared -> indexer -> client/admin)
bun run build

# 4. Format before committing
bun run format
bun test vs bun run test

bun test invokes Bun's built-in test runner, which ignores your Vitest config. Always use bun run test to run the package.json script with proper environment setup.


If something goes wrong

SymptomCauseFix
forge: command not foundFoundry not installedcurl -L https://foundry.paradigm.xyz | bash && foundryup
Indexer fails to startDocker not runningStart Docker Desktop, then retry bun run dev:indexer
VITE_CHAIN_ID is undefinedMissing .envRun bun run env:sync, or copy .env.template to .env and fill values manually
Pinata forbidden or upload failsMissing signer or Pinata server credentialConfirm VITE_API_BASE_URL points at the agent and add PINATA_JWT to root .env (or set it via 1Password ref in .env.template and re-run bun run env:sync), then rerun bun run dev:doctor -- --profile upload
Client PM2 process is online but localhost:3001 does not respondVite failed to read envRun bun run dev:doctor -- --profile web and bun run env:check. For 1Password-resolved env, ensure op CLI is signed in via desktop integration, then bun run env:sync.
bun run dev:smoke:web fails before checking portsWeb doctor failedFix the doctor failures first; smoke only probes services after the web profile is ready.
Passkey registration fails on localhostRP ID mismatchLeave VITE_PASSKEY_RP_ID blank for fallback behavior, or set VITE_PASSKEY_RP_ID=localhost for local passkey QA
Port 3001/3002 in useAnother dev server runningKill the process or change the port in the package's Vite config
bun install hangsStale dependency stateDelete node_modules, then bun install
No QR code on landing pagecloudflared not installedbrew install cloudflared, then restart bun run dev
Tunnel URL not appearingClient not ready yetThe tunnel waits up to 60s for port 3001 — check PM2 logs with bunx pm2 logs tunnel

Non-negotiables

  • All React hooks live in packages/shared -- client and admin only have components and views.
  • The target chain derives from VITE_CHAIN_ID at build time. There is no runtime chain switching.
  • Deployment changes go through bun deploy:* wrappers, never raw forge commands.
  • User-facing strings must be added to all three translation files (en.json, es.json, pt.json).

Next page

Next best action

Keep momentum by moving to the next high-value step in this journey.

Architecture