DAO Governance: Members, Editors, Proposals
Anything that publishes to a DAO space needs to know its governance state — who can vote, how many members exist, what proposals are open or closed. The pattern below covers the three core reads: counts, member/editor lookups, and proposal status.
Counts at a glance
query GovCounts($spaceId: UUID!) {
membersConnection(first: 1, filter: { spaceId: { is: $spaceId } }) {
totalCount
}
editorsConnection(first: 1, filter: { spaceId: { is: $spaceId } }) {
totalCount
}
proposalsConnection(first: 1, filter: { spaceId: { is: $spaceId } }) {
totalCount
}
}
{ "spaceId": "41e851610e13a19441c4d980f2f2ce6b" }
{
"data": {
"membersConnection": { "totalCount": 233 },
"editorsConnection": { "totalCount": 15 },
"proposalsConnection": { "totalCount": 312 }
}
}
The AI space currently has 233 members, 15 editors, 312 lifetime proposals.
List proposals (most recent first)
query SpaceProposals($spaceId: UUID!) {
proposals(
first: 10
filter: { spaceId: { is: $spaceId } }
orderBy: CREATED_AT_DESC
) {
id
name
proposedBy
startTime
endTime
executedAt
yesCount
noCount
abstainCount
}
}
{
"data": {
"proposals": [
{
"id": "0083d2a4b69642658e359eb8fed91aa1",
"name": "Fix stale relations from wrong-space bug",
"proposedBy": "f3dab79cb5a3d9d1759656dd5361d1c6",
"startTime": "1774634797",
"endTime": "1774721197",
"executedAt":"1774634803",
"yesCount": "1",
"noCount": "0",
"abstainCount": "0"
}
]
}
}
Status is implicit in the timestamps:
executedAtset → executed (yes-vote passed and the on-chain action ran)endTimepast with noexecutedAt→ failed or expired (vote closed, didn't execute)endTimein the future → active (still accepting votes)
Members of a specific space
query SpaceMembers($spaceId: UUID!) {
members(filter: { spaceId: { is: $spaceId } }, first: 100) {
memberSpaceId
}
}
memberSpaceId is the personal-space ID of each member. To resolve those to wallet addresses or person entities, fan out queries on the result set.
Check whether a wallet is a member or editor
query IsAuthorized($spaceId: UUID!, $personalSpaceId: UUID!) {
members(filter: {
spaceId: { is: $spaceId }
memberSpaceId: { is: $personalSpaceId }
}) {
memberSpaceId
}
editors(filter: {
spaceId: { is: $spaceId }
memberSpaceId: { is: $personalSpaceId }
}) {
memberSpaceId
}
}
Any non-empty array means yes; empty means no. Useful before showing a "Propose Edit" button in your UI.
Vote breakdown on a proposal
The proposal record already includes vote counts (yesCount, noCount, abstainCount — note: returned as string-encoded BigInt). For the individual votes:
query ProposalVotes($proposalId: UUID!) {
proposalVotes(filter: { proposalId: { is: $proposalId } }) {
voterId
vote
createdAt
}
}
vote is the vote value (yes / no / abstain), voterId is the voter's personal space ID.
Notes
- Counts are strings, not numbers.
yesCount: "1"is a BigInt. Coerce withBigInt(p.yesCount)orNumber(p.yesCount)depending on what you need. - Personal spaces vs. wallet addresses: members are tracked by their personal space ID, not the wallet address directly. The personal space is the identity used in DAO governance.
- Filter shapes are different from
entities:MemberFilterusesspaceIdandmemberSpaceId; theEntityFilterusesspaceIds(plural). Easy to mix up — check the reference for the exact shape. - Proposal
nameis human-readable but proposers control it — don't rely on a structured format. proposedByis the proposer's personal space ID, same asmemberSpaceIdsemantics.