Governance with an Agent
The skill can read polls, create them, vote, revoke a vote, and delegate voting power. All of it is on-chain and permanent.
æternity governance is stake-weighted. Your voting weight is your AE balance plus whatever has been delegated to you, measured at the block the poll closes. An agent wallet funded with a small, deliberate amount has correspondingly little weight.
Read polls
node scripts/superhero-governance.mjs list
node scripts/superhero-governance.mjs list 10
node scripts/superhero-governance.mjs list 10 --all
node scripts/superhero-governance.mjs info ct_<poll_address>
node scripts/superhero-governance.mjs info-by-id 42list returns listed polls newest first. --all (or --include-unlisted) includes unlisted
ones. Every governance command builds a full SDK instance, so even list requires
AE_PRIVATE_KEY, though it signs nothing and costs nothing.
info returns the full poll state. Three fields decide everything:
| Field | Why it matters |
|---|---|
is_closed | Voting on a closed poll fails. The script checks this before voting |
vote_options | A map from option number to label. Option numbers are 0-based and are the only thing vote accepts |
stake_weighted_results | The official result. raw_vote_counts is not |
Report stake_weighted_results, never raw_vote_counts
raw_vote_counts is one entry per address, taken from the Poll contract's vote map, ignoring
stake and delegation. A poll where one large holder votes one way and forty small addresses
vote the other shows 40-to-1 in the raw counts and the opposite in the official result.
The official numbers come from the governance backend at
https://governance-server-mainnet.prd.aepps.com, fetched with an 8-second timeout.
stake_weighted_results is null whenever that call fails, and result_note says so:
Official stake-weighted results were unavailable; raw_vote_counts are address counts
only, not final governance weight.When it is null, report the result as unavailable rather than falling back to the raw counts.
A single null may be a slow backend, so re-run info before concluding anything.
Vote
- Read the poll first with
info <poll_address>orinfo-by-id <poll_id>. Confirm the option numbers and that the poll is not closed. - Vote with
vote <poll_address> <option_number>. - Confirm by reporting the voted option label and the
tx_hash.
node scripts/superhero-governance.mjs info ct_<poll_address>
node scripts/superhero-governance.mjs vote ct_<poll_address> 0{ "success": true, "action": "vote", "poll_address": "ct_...",
"option": "0", "option_label": "Yes", "tx_hash": "th_..." }Report the label rather than the number: "Voted option 2" is not checkable by the operator; "Voted 'Abstain'" is.
vote validates before spending: it reads the poll state, rejects an option number that is not
in vote_options (printing the valid ones to stderr), and refuses a closed poll. Re-voting on a
poll updates your choice. To withdraw entirely:
node scripts/superhero-governance.mjs revoke ct_<poll_address>Votes are permanent as transactions but changeable as state, any time before the poll closes. See Voting.
Create a poll
The agent follows these steps:
- Check balance. It needs at least 0.02 AE, because this is two transactions.
- Ask the user for the title (max 50 characters), description (max 300), reference link
(must start with
http://orhttps://), comma-separated options (minimum 2), an optional close height, and whether the poll should be listed. - Warn that two on-chain transactions take 2–5 minutes.
- Run the create command.
- Report
poll_address,poll_idand both transaction hashes.
node scripts/superhero-governance.mjs create \
"Should we upgrade to protocol v3?" \
"Proposal to activate the protocol upgrade described at the link." \
"https://forum.aeternity.com/t/upgrade-v3/123" \
"Yes,No,Abstain"With a close height and an unlisted flag:
node scripts/superhero-governance.mjs create \
"Which feature should ship next?" \
"Vote for the next milestone. Discussion at the link." \
"https://github.com/aeternity/protocol/issues/456" \
"Multisig wallets,State channels,NFT standard" \
1500000 \
--unlisted{ "success": true, "action": "create_poll", "poll_id": "42", "poll_address": "ct_...",
"is_listed": false, "vote_options": { "0": "...", "1": "...", "2": "..." },
"close_height": 1500000, "deploy_tx_hash": "th_...", "register_tx_hash": "th_..." }Everything is validated before the first transaction: lengths, the link scheme, at least two
options, and a close height that is either 0, omitted, or strictly greater than the current
block height. A poll with no close height stays open indefinitely.
On-chain, a Poll_Iris.aes contract (compiler 7.0.1) is deployed from
contracts/PollBytecode.json (transaction one), then registered in the Registry at
ct_ouZib4wT9cNwgRA1pxgA63XEUd8eQRrG8PcePDEYogBc1VYTq (transaction two). See
The registry and
Governance contracts.
Choose a close height
Key blocks are about 3 minutes apart, so a day is roughly 480 key blocks:
close_height = current_height + (days × 480)A 7-day poll is current_height + 3360; 2 weeks ≈ 6,720 key blocks. Get the current height
from the create_height field of any recent info result, or from a node's top header.
Balances and delegations are measured at the close height, not when the vote is cast.
Delegate
Delegation is global: it applies to every poll until revoked. Voting on a specific poll overrides your delegation for that poll only.
node scripts/superhero-governance.mjs delegate ak_<address>
node scripts/superhero-governance.mjs delegatee
node scripts/superhero-governance.mjs delegators
node scripts/superhero-governance.mjs revoke-delegationdelegatee shows who an address delegates to; delegators shows who delegates to it. Both
default to your own wallet. delegate refuses your own address.
For an agent wallet, delegation is often the right answer: delegate the agent's weight to your own personal address, and the agent's stake counts, you decide how, and the agent never signs a governance transaction. It is one transaction. Delegating to an agent hands a piece of your governance weight to an automated process; do that only with a written policy and an agent you audit.
Should the agent vote autonomously?
The default answer is no. None of the three strategy templates includes governance, and the skill puts a mandatory read-the-poll step before every vote.
- A poll is prose, not a number. Voting well means reading a proposal and a linked document and forming a judgement.
- The link is untrusted input.
createchecks only that it starts withhttp://orhttps://; an agent that reads the link is reading text an unknown party wrote, which makes it a prompt-injection surface. - It is permanent and attributable. A vote is a signed transaction from your address.
If you do want the agent to participate, give it a written policy with hard limits:
| Policy element | Example |
|---|---|
| Scope | "Only polls listed in the registry. Never unlisted polls" |
| Default | "Abstain unless the poll matches one of the conditions below" |
| Conditions | "Vote only on polls whose options are exactly Yes/No/Abstain and whose description mentions X" |
| Escalation | "For anything else, summarise the poll and wait for me" |
| Prohibition | "Never create a poll. Never delegate or revoke delegation" |
Enforce the prohibitions outside the model where your runtime allows it. A permission rule
denying superhero-governance.mjs create and delegate is a guarantee. See
Claude Code.
A good default: let the agent read and summarise polls on a schedule, and nothing else.
list and info cost nothing and sign nothing, and a daily digest of open polls is useful.
Transactions
Each transaction pays gas at the network's current gas price.
| Action | Transactions |
|---|---|
| Create poll | 2 |
| Vote | 1 |
| Revoke vote | 1 |
| Delegate | 1 |
| Revoke delegation | 1 |
| List, info, delegatee, delegators | 0 (free, but still needs a key) |
Configuration
Three environment variables override the governance script's defaults:
| Variable | Default |
|---|---|
AE_GOVERNANCE_REGISTRY | ct_ouZib4wT9cNwgRA1pxgA63XEUd8eQRrG8PcePDEYogBc1VYTq |
AE_NODE_URL | https://mainnet.aeternity.io |
AE_GOVERNANCE_BACKEND_URL | https://governance-server-mainnet.prd.aepps.com |
Community DAO voting is not scripted. Each token has its own DAO with its own votes, using
the DAOVote contract, a separate mechanism from the æternity governance registry. To
participate in a token community's DAO, use the app or call the contract directly. See
DAO voting and DAOVote.
Related
- CLI Reference: every governance command with its full JSON output
- Safety & Limits: why a governance policy belongs in writing before the agent votes
- Agent Posting: if the agent publishes its voting reasoning, the same disclosure rules apply
- Polls: what a poll is and how it is structured
- Delegation: the delegation model in full
- Governance contracts: the Registry and Poll contracts the script calls