Implement LLM-driven governance architecture with structured memory

This commit completes the transition to a pure LLM-driven agentic
governance system with no hard-coded governance logic.

Core Architecture Changes:
- Add structured memory system (memory.py) for tracking governance processes
- Add LLM tools (tools.py) for deterministic operations (math, dates, random)
- Add audit trail system (audit.py) for human-readable decision explanations
- Add LLM-driven agent (agent_refactored.py) that interprets constitution

Documentation:
- Add ARCHITECTURE.md describing process-centric design
- Add ARCHITECTURE_EXAMPLE.md with complete workflow walkthrough
- Update README.md to reflect current LLM-driven architecture
- Simplify constitution.md to benevolent dictator model for testing

Templates:
- Add 8 governance templates (petition, consensus, do-ocracy, jury, etc.)
- Add 8 dispute resolution templates
- All templates work with generic process-based architecture

Key Design Principles:
- "Process" is central abstraction (not "proposal")
- No hard-coded process types or thresholds
- LLM interprets constitution to understand governance rules
- Tools ensure correctness for calculations
- Complete auditability with reasoning and citations

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Nathan Schneider
2026-02-08 14:24:23 -07:00
parent 5fe22060e1
commit bda868cb45
26 changed files with 8683 additions and 187 deletions

643
ARCHITECTURE_EXAMPLE.md Normal file
View File

@@ -0,0 +1,643 @@
# Governance Architecture: Complete Example
This document shows how the agentic governance system works through a complete process lifecycle, using a **proposal** as the example.
**Note**: The system uses "process" as the generic concept for any governance activity. Proposals are just one type of process. The same architecture handles disputes, elections, discussions, do-ocracy actions, jury selection, and any other process type defined in your constitution.
## Example Process: Standard Proposal
User `@alice` initiates a proposal process. Let's see how the system handles it WITHOUT hard-coded logic.
### Step 1: User Submits Proposal
```
@alice: "@govbot I propose we change the moderation policy to require 2 moderators for bans"
```
### Step 2: Agent Parses Intent (LLM)
```python
agent._parse_intent_with_llm(request, actor="@alice")
```
**LLM Response**:
```json
{
"intent_type": "create_proposal",
"query": "What are the rules for creating a proposal about moderation policy?",
"parameters": {
"proposal_text": "change the moderation policy to require 2 moderators for bans",
"topic": "moderation_policy"
},
"confidence": "high"
}
```
### Step 3: Query Constitution
```python
constitution.query(
question="What are the rules for creating a proposal about moderation policy?",
context="Actor: @alice, Request: [proposal text]"
)
```
**Constitutional Reasoner Returns**:
```json
{
"answer": "Standard proposals address routine governance matters including policy changes. They require a 6-day discussion period and pass when more people vote agree than disagree.",
"sections": [
{
"title": "Article 3, Section 3.1: Proposal Types",
"content": "Standard Proposals address routine governance matters:\n- Discussion period: 6 days minimum\n- Passage threshold: More Agree than Disagree votes"
}
],
"confidence": "high"
}
```
### Step 4: Query Memory for Context
```python
memory.get_active_processes()
```
**Memory Returns**:
```python
[
ProcessMemory(
id="process_123",
type="standard_proposal",
status=ACTIVE,
created_by="@bob",
deadline=datetime(2026, 2, 10),
# ... other active proposals
),
# ... more processes
]
```
**Memory Context Summary**:
```json
{
"active_processes": [
"Process process_123: standard_proposal by @bob, deadline 2026-02-10",
"Process process_124: urgent_proposal by @carol, deadline 2026-02-09"
],
"overdue_processes": []
}
```
### Step 5: LLM Makes Decision
```python
agent._make_decision_with_llm(intent, constitution, memory, actor, context)
```
**LLM Prompt** (simplified):
```
You are a governance bot interpreting a community constitution.
INTENT:
User wants to create a proposal about moderation policy.
CONSTITUTIONAL GUIDANCE:
Standard proposals need 6-day discussion period and pass when more agree than disagree.
CURRENT MEMORY STATE:
2 active proposals currently running.
What should be done?
```
**LLM Decision**:
```json
{
"action": "create_process",
"reasoning": "This is a standard proposal about moderation policy. According to Article 3, Section 3.1, standard proposals require a 6-day discussion period and pass when more members vote agree than disagree. I should create a new process with these parameters.",
"constitution_citations": [
"Article 3, Section 3.1: Proposal Types"
],
"parameters": {
"process_type": "standard_proposal",
"deadline_days": 6,
"threshold_expression": "agree > disagree",
"initial_state": {
"proposal_text": "change the moderation policy to require 2 moderators for bans",
"proposer": "@alice",
"topic": "moderation_policy",
"votes": {}
}
},
"calculations": [
{
"tool": "datetime_add",
"days": 6,
"result": "2026-02-14T18:30:00Z"
}
]
}
```
### Step 6: Execute Decision
```python
agent._execute_decision(decision, actor="@alice", context)
```
**Memory Operations**:
1. **Create Process**:
```python
process = memory.create_process(
process_id="process_125",
process_type="standard_proposal",
created_by="@alice",
constitution_basis=["Article 3, Section 3.1: Proposal Types"],
deadline=datetime(2026, 2, 14, 18, 30),
initial_state={
"proposal_text": "change the moderation policy to require 2 moderators for bans",
"votes": {}
}
)
```
2. **Log Event**:
```python
memory.add_event(
process_id="process_125",
actor="@alice",
event_type="process_created",
data={"proposal_text": "..."},
context="Proposal created by @alice"
)
```
3. **Log Decision**:
```python
memory.add_decision(
process_id="process_125",
decision_type="process_creation",
reasoning="This is a standard proposal about moderation policy...",
constitution_citations=["Article 3, Section 3.1"],
result="created"
)
```
### Step 7: Generate Response
**Bot Response**:
```
@alice Your proposal has been created as Process #125.
Type: Standard Proposal
Discussion Period: 6 days
Deadline: February 14, 2026 at 18:30 UTC
Voting Threshold: More Agree than Disagree votes
Constitutional Basis: Article 3, Section 3.1 - Standard Proposals
The discussion period is now open. Community members may discuss and
vote on this proposal until the deadline.
```
---
## Scenario: Voting
User `@bob` votes on the proposal.
### Step 1: User Votes
```
@bob: "@govbot I vote agree on proposal 125"
```
### Step 2-4: Intent Parsing + Constitution + Memory
**Intent**: `cast_vote` on `process_125`
**Constitution**: "Members vote by replying to proposal thread. Votes can be changed before deadline."
**Memory**: Gets process_125, checks if active, checks if @bob already voted
### Step 5: LLM Decision
```json
{
"action": "record_vote",
"reasoning": "@bob is voting 'agree' on an active proposal. The constitution allows members to vote before the deadline. This vote should be recorded.",
"constitution_citations": ["Article 4, Section 4.2: Voting Process"],
"parameters": {
"process_id": "process_125",
"vote_type": "agree"
}
}
```
### Step 6: Execute
**Memory Operations**:
1. **Update Process State**:
```python
votes = process.state["votes"]
votes["@bob"] = {"vote": "agree", "timestamp": "2026-02-09T10:15:00Z"}
memory.update_process("process_125", state_updates={"votes": votes})
```
2. **Log Event**:
```python
memory.add_event(
process_id="process_125",
actor="@bob",
event_type="vote_cast",
data={"vote": "agree"},
context="@bob voted agree"
)
```
**Bot Response**:
```
@bob Your vote has been recorded: Agree
Current tally for Proposal #125:
- Agree: 1
- Disagree: 0
- Abstain: 0
Deadline: February 14, 2026 at 18:30 UTC
```
---
## Scenario: Deadline Reached
Bot checks deadlines and evaluates proposal.
### Step 1: Scheduled Check
```python
agent.check_deadlines()
```
**Memory Query**:
```python
overdue = memory.get_overdue_processes()
# Returns: [process_125]
```
### Step 2: Evaluate Process
```python
agent._evaluate_process_deadline(process_125)
```
**Get Votes**:
```python
votes = process.state["votes"]
# {"@bob": {"vote": "agree"}, "@carol": {"vote": "agree"}, "@dave": {"vote": "disagree"}}
vote_tally = tools.tally([{"vote": v["vote"]} for v in votes.values()], "vote")
# Result: {"agree": 2, "disagree": 1}
```
### Step 3: Query Constitution for Threshold
```python
constitution.query(
question="For a standard_proposal, what voting threshold is required for passage?",
context="Votes: agree=2, disagree=1"
)
```
**Constitution Returns**:
```json
{
"answer": "Standard proposals pass when there are more Agree votes than Disagree votes.",
"sections": ["Article 3, Section 3.1"],
"confidence": "high"
}
```
### Step 4: LLM Evaluates Threshold
**LLM Prompt**:
```
Process process_125 has reached its deadline.
Votes cast:
- Agree: 2
- Disagree: 1
- Abstain: 0
Constitution says: "More Agree than Disagree votes"
Does this proposal pass?
Use the calculate tool to evaluate: agree > disagree
```
**LLM Decision**:
```json
{
"action": "complete_process",
"reasoning": "The proposal has reached its deadline. According to the constitution, standard proposals pass when more members vote agree than disagree. The vote tally shows 2 agree and 1 disagree. Using the calculate tool: 2 > 1 = True. Therefore, the proposal passes.",
"constitution_citations": ["Article 3, Section 3.1: Passage threshold"],
"parameters": {
"process_id": "process_125",
"outcome": "passed"
},
"calculations": [
{
"tool": "calculate",
"expression": "agree > disagree",
"variables": {"agree": 2, "disagree": 1},
"result": true
}
]
}
```
### Step 5: Execute Completion
**Memory Operations**:
1. **Update Status**:
```python
memory.update_process("process_125", status=ProcessStatus.COMPLETED)
```
2. **Log Decision**:
```python
memory.add_decision(
process_id="process_125",
decision_type="process_completion",
reasoning="The proposal has reached its deadline...",
constitution_citations=["Article 3, Section 3.1"],
result="passed",
calculation_used="agree > disagree",
calculation_variables={"agree": 2, "disagree": 1},
calculation_result=True
)
```
3. **Log Event**:
```python
memory.add_event(
process_id="process_125",
actor="bot",
event_type="process_completed",
data={"outcome": "passed"},
context="Process completed: proposal passed"
)
```
### Step 6: Generate Audit Trail
```python
audit = AuditTrail.format_decision(process.decisions[-1], process)
```
**Audit Trail** (excerpt):
```markdown
# GOVERNANCE DECISION AUDIT TRAIL
**Decision ID**: process_125_2
**Timestamp**: 2026-02-14 18:30:15 UTC
**Decision Type**: process_completion
**Result**: passed
## Constitutional Basis
- Article 3, Section 3.1: Passage threshold
## Reasoning
The proposal has reached its deadline. According to the constitution,
standard proposals pass when more members vote agree than disagree.
The vote tally shows 2 agree and 1 disagree. Using the calculate tool:
2 > 1 = True. Therefore, the proposal passes.
## Calculation Details
**Expression**: `agree > disagree`
**Variables**:
- `agree` = 2
- `disagree` = 1
**Result**: `True`
```
### Step 7: Announce Result
**Bot Post**:
```
📊 Proposal #125 has PASSED
Proposal: "Change the moderation policy to require 2 moderators for bans"
Proposed by: @alice
Final Vote Tally:
✅ Agree: 2 (66.7%)
❌ Disagree: 1 (33.3%)
⚪ Abstain: 0
Constitutional Threshold: More Agree than Disagree
Result: 2 > 1 ✓
This proposal has passed and will now be implemented.
Full audit trail: [link]
```
---
## Key Differences from Old System
### Old System (Hard-Coded)
```python
# Hard-coded threshold check
def check_threshold(counts, "simple_majority"):
return counts['agree'] > counts['disagree']
# Hard-coded in agent
if threshold_type == "simple_majority":
passed = agree > disagree
```
### New System (Agentic)
```python
# Constitution defines threshold in natural language
"More Agree than Disagree votes"
# LLM interprets and uses tool
decision = llm.decide(
constitution="More Agree than Disagree votes",
votes={"agree": 2, "disagree": 1}
)
# Returns: "Use calculate tool with expression 'agree > disagree'"
result = tools.calculate("agree > disagree", {"agree": 2, "disagree": 1})
# Returns: True
```
---
## Auditability Example
Community member `@eve` wants to understand why proposal 125 passed.
### Query Memory
```python
process = memory.get_process("process_125")
audit = AuditTrail.generate_process_audit_file(process)
```
### Audit File Contents
```markdown
# Governance Process Audit: process_125
**Generated**: 2026-02-15 09:00:00 UTC
---
# Process Summary: process_125
**Type**: standard_proposal
**Status**: completed
**Created By**: @alice
**Created At**: 2026-02-08 18:30:00 UTC
**Deadline**: 2026-02-14 18:30:00 UTC
## Constitutional Basis
- Article 3, Section 3.1: Proposal Types
## Current State
- proposal_text: change the moderation policy...
- proposer: @alice
- topic: moderation_policy
- votes: 3 items
## Event Timeline
**[2026-02-08 18:30]** process_created
- Actor: @alice
- Context: Proposal created by @alice
**[2026-02-09 10:15]** vote_cast
- Actor: @bob
- Context: @bob voted agree
**[2026-02-10 14:22]** vote_cast
- Actor: @carol
- Context: @carol voted agree
**[2026-02-11 09:45]** vote_cast
- Actor: @dave
- Context: @dave voted disagree
**[2026-02-14 18:30]** process_completed
- Actor: bot
- Context: Process completed: proposal passed
## Decisions
**1. [2026-02-08 18:30]** process_creation
- Result: created
- Reasoning: This is a standard proposal about moderation policy...
**2. [2026-02-14 18:30]** process_completion
- Result: passed
- Reasoning: The proposal has reached its deadline. According to...
---
# Detailed Decision Log
[Full decision details with calculations, reasoning, citations...]
---
## Audit Trail Integrity
This audit trail represents the complete record of this governance process.
All decisions were made according to the community constitution...
```
**Key Point**: Every step is logged with:
- What happened
- When it happened
- Who did it
- Why (bot reasoning)
- What constitutional rule applied
- What calculations were used
Humans can inspect and verify every decision.
---
## Handling Different Templates
The beauty of this system: the SAME code works for different governance models!
### Example: Consensus (from templates)
**Constitution excerpt**:
```markdown
### Section 4.4: Block
"I block this proposal because..."
- Fundamental objection preventing consensus
- Must include explanation and reasoning
- Triggers deeper discussion
```
**User Action**:
```
@frank: "@govbot I block proposal 126 because it violates our privacy principles"
```
**Agent Flow**:
1. LLM parses intent: "cast_vote with type=block"
2. Queries constitution: "What happens when someone blocks?"
3. Constitution: "Triggers deeper discussion, proposal cannot pass until block resolved"
4. LLM decides: "Record block vote, update process status to 'blocked', notify proposer"
5. Memory updated with block and reasoning
6. Audit trail shows: "Block recorded. Constitutional requirement: must address concern"
**No code changes needed!** The agent interprets the constitution's block rules.
### Example: Jury/Sortition (from templates)
**Constitution excerpt**:
```markdown
Juries selected randomly:
- 5-7 members from eligible pool
- Random selection ensures fairness
```
**Agent Flow**:
1. LLM interprets: "Need to select 5-7 random members"
2. Uses tool: `random_select(eligible_members, count=5)`
3. Creates jury process in memory
4. Logs selection with seed for reproducibility
5. Audit shows: "Selected using random sortition per Article X"
---
## Summary
The system:
**No hard-coded governance logic** - All rules come from constitution
**LLM interprets and decides** - Based on natural language rules
**Structured memory tracks state** - Queryable by LLM and humans
**Tools ensure correctness** - Math done by calculator, not LLM reasoning
**Complete audit trails** - Every decision explained and cited
**Works with any template** - Consensus, do-ocracy, jury, etc.
The key insight: **Separate interpretation from execution**. LLM interprets what to do, tools execute it correctly, memory tracks everything, audits explain it all.