Shared
@green-goods/shared is the single home for everything the apps have in common: hooks,
providers, stores, protocol data modules, domain types, translations, and the Storybook-backed UI
foundations. If logic could ever serve two surfaces, it lives here first; the client, admin, and
agent packages stay thin on purpose.

Inside src
Shared is layered. Modules talk to the protocol and the network; stores and workflows hold state
and state machines; hooks and providers expose both to React; components render on top. Nothing in
a lower layer imports from a higher one. src/MODULES.md is the folder-by-folder map and the
authority on where a new piece goes.
| Directory | What lives there |
|---|---|
src/modules/ | Protocol and platform modules, one folder each: data/ (EAS, gardens, vaults, hypercerts, Karma, IPFS, GraphQL clients), job-queue/ (the offline-first work queue), commitment-pooling/ (pool, settlement, credit and voucher-pilot data and job executors), app/ (logger, environment), and the rest |
src/stores/ and src/workflows/ | Client state stores and the XState machines behind multi-step flows |
src/hooks/ | Domain hooks by area: auth, garden, work, assessment, vault, cookie-jar, hypercerts, conviction, and more |
src/providers/ | App-level providers (auth, chain, query) |
src/components/ | Shared UI primitives with Storybook coverage, including the token stories |
src/styles/ | The theme and the generated DesignMD tokens every surface reads |
src/utils/, src/types/, src/config/ | Pure helpers (addresses, errors, explorers), the domain types, and the query keys and chain config |
src/public-contracts/ and src/lib/ | The public API contracts the agent serves, and the Hypercerts library bindings |
src/commitment-pooling/ and src/profile-avatar/ | Entry points that gather one feature's modules and hooks behind a declared export, such as @green-goods/shared/commitment-pooling and its public-site subset @green-goods/shared/commitment-pooling/public; the pooling code itself lives in src/modules/commitment-pooling/ and src/hooks/commitment-pooling/ |
src/i18n/ | en.json, es.json, pt.json; every user-facing string ships in all three |
src/ontology/ | The domain ontology the docs and guards project from |
src/__tests__/ | Vitest suites and the test support the apps import through @green-goods/shared/testing |
Run and test
bun run --cwd packages/shared test
bun run --cwd packages/shared typecheck
bun run --cwd packages/shared check:stories proves story coverage when UI foundations change;
bun run --cwd packages/shared test --scope all-configured --coverage is the fuller pass.
How it connects
Everything downstream imports shared through its
declared package exports, never src/** paths. That boundary is what lets a hook
change ship with confidence: consumers see only the public surface. The flip side is fan-out, so
when you change a hook signature, data shape, or exported utility, validate from the repo root
rather than only inside this package.
Conventions that will bite you
- All reusable hooks live here. A hook created in
clientoradminis a bug by convention. - Tailwind classes in shared ship in both apps. Each app's
index.cssscans shared source (@source "../../shared/src/**/*.{ts,tsx}", minus tests, mocks, and stories), so a utility written in a shared component is in both bundles. The trap is narrower: a class that appears only in a story or a test is not scanned, and a class assembled from strings at runtime is never seen, so verify a new utility in the running app, not only in Storybook. - Query keys come from the central
queryKeys; ad-hoc query arrays break invalidation. - Application defaults use
useCurrentChain()orDEFAULT_CHAIN_ID, never wallet chain state. - Shared gates decide what the apps may offer, so check them before describing a feature as
available.
SETTLEMENT_ENABLEDinsrc/config/app.tsis on today; when it is false, the shared mutations and job executor refuse settlement writes and new G$ rewards in every app. The voucher pilot reads its deployed contracts only for voucher offers and the voucher reward a request can carry. Offers come through the receipt-backedSERVICE_LIVE_ROUTESinsrc/modules/commitment-pooling/service-access-live-config.ts.SERVICE_ISSUER_ROUTESinsrc/modules/commitment-pooling/service-issuer-metadata.tspins the reward module a request's reward binds, and it holds only Green Goods' issuer route, with its confirmed terms and capacity; Tech and Sun has not confirmed its own. The credit hooks insrc/hooks/commitment-pooling/useCredit.tshave no app consumer. - Prefer event-driven invalidation over polling.
- New user-facing strings land in all three locale files in the same change, or the i18n gate fails.
Go deeper
packages/shared/AGENTS.mdis the full package contract.- The live Storybook at design.greengoods.app is the source of truth for shared UI foundations.
- API Index lists every declared export.