- Monorepo managed by Yarn workspaces and Lerna Lite. Primary code lives under
packages/*(e.g.,SwingSet,zoe,ERTP,smart-wallet). - Go components are under
golang/(e.g.,golang/cosmos). - Tests reside per package in
packages/<name>/test/. - Utilities, CI and developer tooling scripts are in
scripts/. Integration assets live ina3p-integration/andmultichain-testing/.
corepack enable && yarn install: Set up the repo with the pinned Yarn version and install dependencies.yarn build: Build all workspaces (generates kernel bundles where needed).yarn test: Run unit tests across all packages (AVA).yarn lint|yarn lint-fix: Check or auto-fix lint issues across packages.yarn run -T tsc --noEmit --incremental: Fast typecheck within a package; do this after changes.- Watch mode for type errors in active workspaces: run
yarn run -T tsc --noEmit --incremental --watch --preserveWatchOutputin the workspace(s) being edited, and keep the terminal output visible so Codex can monitor errors.
- Watch mode for type errors in active workspaces: run
yarn typecheck-quickto do a fast typecheck over the whole repo (4-7 seconds)yarn format: Format code via dprint;yarn lint:formatto check only.- Git hooks: installed by
scripts/install-git-hooks.sh.- Install or refresh hooks with
yarn hooks:install. - Pre-commit runs
scripts/git-hooks/pre-commit-dprint.sh, which formats staged JS/TS files with the pinned local binary./node_modules/.bin/dprint, auto-restages files that were fully staged already, and prints a custom message if formatting changes touched partially staged files.
- Install or refresh hooks with
./scripts/env-doctor.sh: Verify toolchain (Node, Go, compiler) versions.- Example, single package:
cd packages/eventual-send && yarn test. - Packing/debugging workflow:
- Full sequential prepack pass across publishable packages:
yarn lerna run --reject-cycles --concurrency 1 prepack - If a package fails, fix it and verify locally in that package with
yarn postpack && yarn prepack - Resume from the failed package and include dependents needed for validation:
yarn lerna run prepack --since <failed-package-name> --include-dependencies --concurrency 1 --reject-cycles - After any prepack run, clean generated artifacts and restore package trees with:
yarn lerna run --reject-cycles --concurrency 1 postpack
- Full sequential prepack pass across publishable packages:
- ESM by default; JS and TypeScript both used. Target Node ^20.9 or ^22.11.
- dprint enforced (Prettier-compatible options include single quotes and trailing commas).
- ESLint configured via
eslint.config.mjs(includes AVA, TypeScript, JSDoc, and repository-specific rules). - Package names: publishable packages use
@agoric/*; private/local packages use@aglocal/*(verify withyarn lint:package-names). @aglocalpackages are private and never published;@agoricpackages are published and may only depend on published packages, so@agoricpackages must never import@aglocalpackages.- For elapsed duration measurement (benchmarks, latency logs, monotonic timeout windows), prefer
performance.now()overDate.now(). UseDate.now()for wall-clock timestamps, IDs, and protocol deadlines. - Entrypoints vs modules
- Keep ambient authority (e.g.,
process.env,console, filesystem, network) in entrypoints - pass explicit capabilities (e.g.,
io.console) into shared JS modules. - Never
@endo/initin modules; best practice is at the beginning of an entrypoint
- Keep ambient authority (e.g.,
This is a capability-security codebase. Apply the Principle of Least Authority by default: every object — facet, capability, callback — should hold and expose only the authority needed to do its legitimate job. POLA "limits the damage that can happen if there is an exploitable bug."
When you add a method or pass a capability, ask "who can reach this, and what stops an unauthorized caller?" Use the answer to decide placement:
- Per-principal operations (acting on one portfolio, account, vault, …) belong on that principal's facet, not on the public facet. Zoe exposes a contract's
publicFacetto anyone with the instance (E(zoe).getPublicFacet(instance)), so a method placed there is reachable by anyone — only acceptable when it creates new state owned by a verifiable principal, returns pure info, or carries its own proof of authority. - A dispatch lookup that throws on miss (e.g.,
wallet.foo.get(id)) is often the entire enforcement mechanism for "the caller must own this thing." Don't sidestep that pattern when adding a new op — route through the same per-principal reference. - Pass narrowed capabilities into modules, not whole objects. Inline adapters like
{ publish: node.setValue }are cheap; over-broad refs are expensive when they leak. The "Entrypoints vs modules" rule above is one instance of this. - Default to read-only first; split (e.g.,
agoricNames/agoricNamesAdmin) before exposing write access.
The facet splits in contracts like packages/portfolio-contract/src/portfolio.exo.ts (reader, reporter, manager, planner, evmHandler, …) are textbook POLA — study a few before adding a method.
- Framework: AVA. Test files follow
**/test/**/*.test.*within each package. - Run all:
yarn test. Per-package:yarn testfrom that package directory. - Coverage: in a package, run
yarn test:c8and opencoverage/html/index.htmlafteryarn c8 report --reporter=html-spaif needed.
- Async-flow runs each invocation as an activation with durable lifecycle states:
Running,Sleeping,Replaying,Failed,Done. - Upgrade-safe behavior depends on deterministic replay of prior host interactions; divergence during replay or invalid interactions can move an activation to
Failed. Donemeans the activation outcome is settled and replay bookkeeping is dropped; logic that assumes continued activation state after completion is erroneous. Once the async-flow is done, any promises not yet settled will never see their reactions run. That's because the vow settling on the host side no longer translates into a settlement of the guest promise.- Interleaving changes can also break replay: adding an
awaitinside an async helper, or calling one without awaiting it immediately, can move later effects into a different turn and reorder them relative to the caller. - For
*.flows.*modules, keep replay behavior in mind and prefer code that is explicit about lifecycle boundaries and awaited dependencies. - When reviewing
*.flows.*modules, readpackages/async-flow/docs/async-flow-states.md.
- A3P tests run inside a Docker container built from an agoric-sdk checkout, so the container can access the full repo filesystem, not just published npm packages.
- The container’s canonical agoric-sdk checkout is based on the last formal release, so any workspace updates needed by A3P must be copied into the image and resolved correctly.
- A3P supports building proposals from agoric-sdk
HEADand copying the artifacts into the image- this avoids copying all sources needed to build proposals.
- it's configured by
agoricProposal.sdk-generatein the proposal package.json - it's performed by
a3p-integration/build-submission.sh
- Use Conventional Commits in titles and commits (e.g.,
feat(swingstore): add snapshot…). - Branches should reference an issue number (e.g.,
123-fix-solo-reconnect). - PRs: link related issues, describe changes and risks; ensure
yarn build,yarn test, andyarn lintpass. Prefer “Squash and merge.” - Integration tests: use labels
force:integration/bypass:integrationwhen appropriate; otherwise they run as part of the merge queue. - Commit hygiene (codegen, lockfile updates, formatting, linting, tests): see
docs/commit-hygiene.md.