Shared business-logic package for the Aragon governance platform. It is the single home for everything a frontend consumer needs that isn't raw on-chain data — membership rules, voting-power math, delegation logic, permission checks, ENS profile enrichment. Paired with aragon-indexer (which provides only deterministic, indexed on-chain state), it lets any frontend consumer stay thin.
Today the package ships one capability — looking up the ENS text records attached to a member's .aragon.eth subdomain — with the rest of the surface area arriving as the Envio migration progresses.
On-chain events → Envio (aragon-indexer) → aragon-domain → Frontend consumers
aragon-indexer indexes raw on-chain state. aragon-domain queries that indexed data, pulls non-deterministic data from other sources, applies domain rules, and returns clean DTOs. Consumers (the App Next.js BFF, an MCP server, future mobile app, etc) call into a single AragonDomain controller.
Built with Domain-Driven Design on top of ddd-core-ts. Three layers, dependencies point inward:
| Layer | Purpose | Depends on |
|---|---|---|
| Domain | Pure business logic — value objects, aggregates, store interfaces | Nothing |
| Use Cases | Application logic that orchestrates domain objects and I/O | Domain |
| Infrastructure | Adapters for Envio and other external systems; the public controller | Domain + Use Cases |
Validation is done with zod inside domain value objects, and the Envio adapter talks to the indexer through graphql-request.
Requires Node >= 24.13 (pinned in .nvmrc) and pnpm >= 11 (pinned via packageManager in package.json). Use nvm for Node and Corepack for pnpm:
nvm install # installs the Node version from .nvmrc
nvm use
corepack enable # activates the pinned pnpm 11 version
pnpm install
pnpm run build
pnpm run testimport { AragonDomain, EnvioClient } from '@aragon/aragon-domain';
const envioClient = new EnvioClient({ /* ... */ });
const aragon = AragonDomain.load(envioClient);
const records = await aragon.getMemberProfileTextRecords({
subdomain: 'alice.aragon.eth',
});
// → [{ key: 'avatar', value: 'ipfs://…' }, …]
// Returns [] if the subdomain is unknown, has no resolver, or has no records.This package is the target for the Envio migration, which moves governance business logic out of app-backend and app and into a shared library. Upcoming areas, in rough order:
- Membership — list members for a plugin, routed by governance type (ERC20 vs. VE)
- Voting power — VP calculation per governance type, including VE locks
- Delegation — delegation relationships and validation rules
- Permissions — proposal-creation and membership permission checks
- Member detail — single-member views enriched with balances and ENS metadata
Scope is tracked against the Aragon Governance Membership Domain Model.
Snapshot releases let you test unreleased changes from a branch on npm without cutting a real version. The flow uses Changesets and a manually-dispatched GitHub Actions workflow.
-
Add a changeset locally describing the change:
pnpm changeset
Pick the bump type and write a short summary. Commit the generated file under
.changeset/and push your branch. -
Run the snapshot workflow. On GitHub, go to Actions → Publish → Run workflow and select your branch. The workflow builds the package, runs
pnpm changeset version --snapshot, and publishes to npm under a per-run dist-tag (snapshot-<run-id>). Publishing uses npm Trusted Publishing (OIDC) — no npm token is involved. -
Install the snapshot in a consumer — the exact command also appears in the workflow run's summary:
pnpm add @aragon/aragon-domain@snapshot-<run-id>
Each run gets its own dist-tag, so multiple in-flight branches can publish snapshots in parallel without colliding. The workflow won't publish anything if no changesets are pending.
| Package | Path | Relationship |
|---|---|---|
aragon-indexer |
/aragon-indexer |
Upstream — Envio indexer this package queries |
app |
/app |
Consumer — Next.js frontend and BFF |
app-backend |
/app-backend |
Consumer being replaced as logic moves here |