Bringing community and environmental actions onchain to better measure, track and reward impact.
Green Goods is an offline-first platform for documenting ecological and social work and proving impact on-chain. Operators approve gardener submissions, and the protocol anchors results in Ethereum attestation infrastructure.
Install Node.js 22+ and Git. Install OrbStack or Docker Desktop if you plan to run the full stack or indexer locally. Node includes npm, and npm run setup installs Bun automatically if it is missing.
Optional tools: Foundry is needed for contract work. cloudflared is useful for mobile-device PWA testing. macOS and Linux are supported natively; use WSL2 or a dev container on Windows.
Use GitHub's Code button to choose the SSH or HTTPS remote that matches your local Git setup. Then run the setup commands from the repo root.
If you are using Codex, Claude Code, or another coding agent, start by loading ONBOARDING.md. It gives the agent the repo context, setup flow, environment model, and first-run checks before it starts changing files.
Read ONBOARDING.md and AGENTS.md, then walk me through first-time setup for this repo.
Start with prerequisites, run npm run setup, check web readiness, start the browser
stack, and explain any env blockers before making changes.
npm run setupAfter setup, use bun for repo scripts and package operations. npm run setup is the only documented npm entrypoint because fresh machines may not have Bun yet.
Green Goods uses a single root .env, materialized from .env.template via the 1Password CLI (op inject). Bun, Vite, and Node read it natively — no per-command secret fetch.
bun run env:template:init # one-time: scaffold .env.template from .env.schema
bun run env:sync # materialize .env from .env.template (runs `op inject`)
bun run env:check # validate .env satisfies .env.schema.env.schema defines the contract; .env.template is the team-shared file with op://Vault/Item/field refs for shared secrets and plain values for non-secrets. Keep personal local-only credentials directly in .env.
| Variable | Needed for | Default setup state |
|---|---|---|
APP_ENV |
Local tooling mode | Generated as development |
VITE_CHAIN_ID |
Client/admin chain selection | Generated for Sepolia |
VITE_DEV_CHAIN_MODE |
Optional local fork marker | Set by the repo-native dev stack for Green Goods fork mode |
VITE_LOCAL_FORK_RPC_URL |
Optional local fork RPC | Set by the repo-native dev stack to http://127.0.0.1:3009 |
VITE_ENVIO_INDEXER_URL |
Local indexer reads | Generated for local GraphQL; needs the indexer running for live local data |
VITE_PINATA_JWT |
Upload-capable media | Add only when testing uploads |
VITE_PIMLICO_API_KEY |
Passkey auth | Add only when testing passkey flows |
VITE_WALLETCONNECT_PROJECT_ID |
Wallet auth | Add only when testing wallet flows |
TELEGRAM_BOT_TOKEN |
Agent service | Add only when running a useful local agent |
For shared team secrets, edit .env.template and set the value to op://Vault/Item/field, then run bun run env:sync. For personal local credentials, set the variable directly in the root .env. Never create package-level .env files.
bun run dev:healthbun run dev:health runs the repo-native full-stack doctor. Use
bun run dev:doctor -- --profile web when you only need the browser-facing
readiness check.
bun run devStarts the repo-native PM2 full stack and opens the review URLs. The default
chain target is an Arbitrum One fork on port 3009, so client/admin reads and
wallet writes use chain id 42161 while transactions are mined only in local
Anvil state.
Plain local Anvil is still available for contract-only work, but it is explicit-only:
dev stop green-goods:anvil-arbitrum
dev launch green-goods:anvilFor fork-mode transaction testing, use a dedicated dev browser profile and a
disposable wallet. The Arbitrum fork launcher keeps Anvil startup output quiet
so fork RPC credentials do not appear in logs; local test-account details are
written to packages/contracts/.generated/runtime/arbitrum-fork.json with the
fork endpoint redacted. Import one of those local-only accounts, configure that
wallet to use http://127.0.0.1:3009 on chain 42161, and never use a real
everyday wallet profile with Anvil keys. ?mockAuth=operator is only a UI state
override; it does not sign transactions.
bun run dev:smoke:web
bun run dev:smoke:fullRun bun run dev:smoke:web after the browser stack is starting. Run
bun run dev:smoke:full after bun run dev when you need proof that the
browser surfaces, local agent, local indexer/Hasura/Postgres, and Arbitrum fork
are all responding. The local indexer stack mirrors the configured live
networks into local Docker services, so reliable lag proof requires
ENVIO_API_TOKEN; without it, HyperSync can rate-limit and the full smoke
should fail on indexer lag instead of pretending the local mirror is current.
- Node.js 22+ provides
npmfor first-clone setup. npm run setupinstalls Bun, installs dependencies, and creates the root.env.- Bun is the workspace runtime after setup.
.env.schema(key contract) +.env.template(1Password refs) materialize.envviabun run env:sync(op inject).- The repo-native PM2 stack manages normal single-repo local dev services.
- The shared dev workbench is for cross-repo orchestration and narrow targets.
- Docker powers full-stack indexer development.
- Storybook runs from the shared package.
- Full-stack work adds Docker-backed indexer services, the agent, tunnel, and workflow-specific env or secrets.
Client and admin can start with generated defaults. Live data, uploads, authenticated onchain flows, and the local agent depend on the matching env and services.
| Surface | URL | Started by |
|---|---|---|
| Client PWA + editorial website | https://localhost:3001 | bun run dev; narrow target: dev launch green-goods:client |
| Admin | https://localhost:3002 | bun run dev; narrow target: dev launch green-goods:admin |
| Docs | http://localhost:3003 | bun run dev; narrow target: dev launch green-goods:docs |
| Storybook | http://localhost:3004 | bun run dev; narrow target: dev launch green-goods:storybook |
| Agent | http://localhost:3005/health | bun run dev; narrow target: dev launch green-goods:agent |
| Indexer | http://localhost:3006/v1/graphql | bun run dev with Docker running; narrow target: dev launch green-goods:indexer-graphql |
| Arbitrum fork | http://127.0.0.1:3009 | started automatically by bun run dev; narrow target: dev launch green-goods:anvil-arbitrum |
bun run devRuns the repo-native Green Goods PM2 stack. The default stack starts the
Arbitrum fork, then the app surfaces that depend on it. The client opens both
review presentations on port 3001:
For cross-repo orchestration or a narrower workbench target, use the global workbench from anywhere:
dev launch green-goods:client
dev launch green-goods:admin
dev launch green-goods:indexer-graphqlFork-mode transaction testing uses wallet auth, not mock auth:
- Start the fork-backed stack with
bun run dev. - Open a dedicated dev browser profile.
- Add a wallet network named
Green Goods Local Arbitrum Forkwith RPChttp://127.0.0.1:3009, chain id42161, and currency symbolETH. - Import one disposable Anvil-funded account from
packages/contracts/.generated/runtime/arbitrum-fork.json; the fork endpoint is redacted in that generated file. - Connect that wallet in the app and sign normally.
The fork uses the real Arbitrum deployment artifact, but writes are mined only
in local Anvil state. Restarting the fork resets local chain state. Passkey and
smart-account writes are intentionally blocked in fork mode until local account
abstraction infrastructure exists. ?mockAuth=operator is useful for UI state
review, but it does not sign transactions and cannot replace the wallet step.
Check full-stack readiness first:
bun run dev:doctor -- --profile fullThen start the full repo-native stack:
bun run devUse the full stack for Docker/indexer, agent, or local transaction work. Run the full doctor first; some services need workflow-specific env or secrets before they are useful.
After the stack is up, run the non-mutating full-local smoke:
bun run dev:smoke:fullThis proves both client presentations, admin, docs, Storybook, local agent
health, Anvil chain id 42161, deployed Arbitrum bytecode on the fork, funded
Anvil accounts, local Envio/Hasura GraphQL, local indexer service health, and
the Postgres TCP listener. The indexer lag check proves the local read model is
close enough to live configured chain state for review; set ENVIO_API_TOKEN in
the root .env for reliable HyperSync catch-up. It does not submit
transactions.
Green Goods has three local-development modes. Use the production-backed modes only when you intentionally want local browser surfaces to talk to live infrastructure.
| Mode | Command | Chain target | Indexer | Agent/API | Writes |
|---|---|---|---|---|---|
| Fully local default | bun run dev |
Arbitrum fork on http://127.0.0.1:3009 with chain id 42161 |
Local Docker-backed Envio/Hasura on 3006-3008 |
Local agent on 3005 |
Wallet writes are mined only in local Anvil state |
| Hosted production-backed | bun run dev:prod |
Arbitrum One 42161 |
Hosted production indexer | https://agent.greengoods.app |
Wallet-confirmed writes are real Arbitrum transactions |
| Local live-indexer mirror | bun run dev:prod:mirror |
Arbitrum One 42161 |
Local Docker-backed Envio/Hasura indexing live Arbitrum | https://agent.greengoods.app |
Wallet-confirmed writes are real Arbitrum transactions |
Start hosted production-backed mode from the repo root:
bun run dev:prodbun run dev:prod starts the client, admin, docs, and Storybook locally. It
does not start local Anvil, the local indexer, the local agent, or a public
tunnel. The stack overlays Arbitrum One (VITE_CHAIN_ID=42161), the hosted
production indexer, and https://agent.greengoods.app, then runs a read-only
production smoke after the local ports are ready.
Live wallet writes are allowed in production-backed modes. If you connect a wallet on Arbitrum One and confirm a transaction, it is a real production transaction and can spend funds. The automatic smoke never submits transactions.
The production smoke proves:
| Check | What it proves |
|---|---|
| Local browser ports | Client 3001, admin 3002, docs 3003, and Storybook 3004 respond |
| RPC chain id | The configured Arbitrum RPC returns eth_chainId=42161 |
| Contract bytecode | At least one deployed Arbitrum contract address from packages/contracts/deployments/42161-latest.json has bytecode |
| Production agent health | https://agent.greengoods.app/health returns HTTP 200 with status: "ok" |
| Indexer GraphQL | Hosted production indexer, or the local mirror in mirror mode, returns Arbitrum chain metadata |
| Indexer lag | Indexed block is within the smoke threshold of Arbitrum head; override with --max-indexer-lag-blocks <blocks> when debugging |
| Local-service boundary | dev:prod skips local indexer services; dev:prod:mirror expects local indexer services |
The production smoke does not prove a full click-through, wallet confirmation, or production transaction broadcast. Use this manual live-write checklist when you need that proof:
- Use a dedicated QA wallet with only the funds you intend to risk.
- Select Arbitrum One in the wallet.
- Start
bun run dev:prodorbun run dev:prod:mirror. - Navigate to the action you need to validate and stop at wallet confirmation if you only need reachability proof.
- Broadcast only when the test intentionally mutates production state.
- Record the route, wallet network, expected contract/action, and transaction hash if a broadcast is intentionally submitted.
The hosted production agent has two health surfaces: /health and /ready.
The local production smoke intentionally uses /health. /ready is stricter
and can return 503 while optional AI/voice model readiness is still loading,
even when the agent, webhook, and routine API are usable.
For local indexer development against live Arbitrum, use the mirror mode:
bun run dev:prod:mirror:health
bun run dev:prod:mirrorThis starts the same browser surfaces plus the local Docker-backed
Postgres/Hasura/Envio stack on ports 3006-3008, while still targeting
Arbitrum One rather than the local fork. The mirror smoke checks local GraphQL,
the local indexer service, and indexer lag against live Arbitrum head; if it
fails lag, the mirror is reachable but not caught up enough to trust for
production-data review.
bun run dev:health and bun run dev:prod:mirror:health warn or fail clearly
when ENVIO_API_TOKEN is missing for reliable HyperSync catch-up. Without it,
the containers can still become healthy, but the local mirror may stall or
receive 429 Too Many Requests from HyperSync and smoke should fail on indexer
lag. Set ENVIO_API_TOKEN directly in the root .env, or set
ENVIO_API_TOKEN_OP_REF in .env.template and run bun run env:sync.
Run the production checks on demand:
bun run dev:prod:health -- --json
bun run dev:prod:mirror:health -- --json
bun run dev:prod:smoke
bun run dev:prod:smoke -- --mode mirror
bun run dev:prod:smoke -- --max-indexer-lag-blocks 5000Expected production-backed port boundary:
dev:prod:3001-3004listening;3005-3009free.dev:prod:mirror:3001-3004and3006-3008listening;3005and3009free.
bun run dev:web, bun run dev:stack, and bun run dev:stack:stop remain
available for focused PM2 debugging. Day-to-day agent and developer work should
use bun run dev.
bun run dev:stopRead the Greenpill Dev Guild contributing guide and the full How to Contribute guide before opening a pull request.
Run each command from the repo root before pushing.
bun run format:checkbun run lintbun run testbun run buildPaid implementation work is grant-dependent and must be clearly scoped with maintainers before work begins. Green Goods does not run open-ended bounties.
- Developer Getting Started - setup, env bootstrap, local services, and first-run workflow
- Architecture - system design, boundaries, and diagrams
- Builder API Index - package APIs, contracts, and shared surfaces
- Operations - build, deploy, environment, and workflow references
- How to Contribute - contributor workflow and expectations
- ONBOARDING.md - paste into Claude Code on day one for a guided setup walkthrough
- AGENTS.md - runtime rules and repo invariants for Codex and other coding agents
- CLAUDE.md - Claude Code commands, patterns, and working conventions