DAOForm

Governance-as-Code for DAOs. Define governance in YAML, manage proposals in code, resolve votes with configurable quorum and threshold rules.

Quick Start

pip install daoform

# Initialize governance config
daoform init --name "MyDAO"

# Validate config
daoform validate

# Create a proposal
daoform propose --id PROP-1 --title "Fund development" --author alice.eth

Governance Model

# dao.yaml — your DAO's constitution
name: MyDAO
description: Community-governed protocol
quorum: 0.1              # 10% participation required
threshold: 0.5            # 50% approval to pass
voting_period_days: 7     # Proposals open for 7 days
timelock_days: 2          # 2-day delay before execution
token_address: null       # Governance token (optional)

Proposal lifecycle: DRAFT → ACTIVE → PASSED/REJECTED → EXECUTED

Quorum: Minimum total voting weight required. If not met, proposal is rejected regardless of vote split.

Threshold: Percentage of FOR votes (excluding abstain) needed to pass. 0.5 = simple majority.

Weight: Each vote has a weight representing voting power (e.g., token balance).

Python SDK

from daoform.engine import GovernanceEngine
from daoform.models import DAOConfig, Proposal, ProposalStatus, Vote, VoteChoice

config = DAOConfig(name="MyDAO", quorum=0.1, threshold=0.5)
engine = GovernanceEngine(config)

# Create and activate proposal
p = engine.create_proposal(
    Proposal(id="PROP-1", title="Fund core dev", author="alice.eth")
)
p.status = ProposalStatus.ACTIVE

# Cast votes
engine.cast_vote(Vote(proposal_id="PROP-1", voter="alice.eth", choice=VoteChoice.FOR, weight=10))
engine.cast_vote(Vote(proposal_id="PROP-1", voter="bob.eth", choice=VoteChoice.AGAINST, weight=3))

# Tally
tally = engine.tally("PROP-1")
# {'for': 10.0, 'against': 3.0, 'abstain': 0.0, 'total': 13.0}

# Resolve
status = engine.resolve("PROP-1")  # PASSED (76.9% > 50%)

Persistence

Proposals and votes are stored as YAML files in .daoform/:

from daoform.store import Store

store = Store(".daoform")

# Save
store.save_proposal(proposal)
store.save_vote(vote)

# Load
proposal = store.load_proposal("PROP-1")
votes = store.load_votes("PROP-1")
all_proposals = store.list_proposals()

The Store class is designed to be swappable — implement the same interface with PostgreSQL, SQLite, or on-chain storage for production.

CLI Reference

CommandDescription
daoform init --name MyDAOCreate dao.yaml governance config
daoform validate --config-file dao.yamlValidate config
daoform propose --id PROP-1 --title "..." --author aliceCreate proposal