Skip to Content
SDK ReferenceConstellation API

Constellation API

The constellation() function is the main SDK entry point. It returns an API for declaring account constellations — the Safes, Roles modules, and users that make up your onchain setup.

import { constellation } from '@zodiac-os/sdk'

Scoping to a workspace and chain

Each constellation is scoped to a single workspace and chain. The workspace option must be a valid workspace name from your org.

const eth = constellation({ workspace: 'GG', label: 'Production', chain: 1, })

After zodiac pull-org, the workspace name, chain id, and account/role/user labels all autocomplete and type-check against your real org.

Referencing existing accounts

Bracket access gives you existing Safes and Roles modules from the selected workspace — both vault accounts surfaced in the workspace UI and any constellation accounts previously created by a push().

// Reference an existing Safe — no invocation needed const ggDao = eth.safe['GG DAO'] // Reference an existing Roles mod const ggDaoRoles = eth.roles['GG DAO Roles'] // Optionally invoke with overrides const ggDaoOverridden = eth.safe['GG DAO']({ threshold: 5 })

When a bracket label matches an existing account, all overrides become optional — you pass only the fields you want to change against the live config.

Creating new accounts

Use bracket access with a new label to create new nodes. Every mandatory field must be supplied explicitly — the SDK injects no runtime defaults, so a missing field is a compile-time error.

// New Safe — nonce, threshold, owners are required const newSafe = eth.safe['New Safe']({ nonce: 0n, threshold: 2, owners: [ eth.user['Alice Sample'], '0xb8e48df6818d3cbc648b3e8ec248a4f547135f7a', ], modules: [ggDaoRoles], }) // New Roles mod targeting an existing Safe const newRoles = eth.roles['New Roles']({ nonce: 0n, target: ggDao, })

A Roles node takes either nonce (deploy a new module) or address (bind to a module already deployed onchain but not in your workspace) — never both. Binding by address makes Zodiac diff your spec against the live module and update only what changed.

Forward references between new nodes

New nodes can reference each other before either has been invoked — the uninvoked factory works as a forward reference. References resolve by label at push() time, so both sides of the cycle must be in the call.

const safe = eth.safe['New Safe']({ nonce: 0n, threshold: 1, owners: [eth.user['Alice Sample']], modules: [eth.roles['New Roles']], // forward ref }) const roles = eth.roles['New Roles']({ nonce: 0n, target: safe, })

Referencing users

eth.user[handle] resolves a user to their personal Safe address on the current chain — useful in owner lists and role-member arrays:

const aliceAddress = eth.user['Alice Sample']

Pushing

push() takes all nodes and sends them to the Zodiac OS API. Pass either a named object (keys become refs) or an array. All referenced nodes must be included.

import { push } from '@zodiac-os/sdk' await push({ ggDao, ggDaoRoles, newSafe, newRoles })

By default push() builds an API client from the ZODIAC_API_KEY environment variable. Pass a custom client to override:

await push({ ggDao, newRoles }, { api: new ApiClient({ apiKey: '...' }) })

In the template, bun push wraps this call and opens the browser to review the diff and sign. See Permissions & the allow kit for scoping what a role can actually call.

Last updated on