Initial commit: Platform-agnostic governance bot

Govbot is an AI-powered governance bot that interprets natural language
constitutions and facilitates collective decision-making across social
platforms.

Core features:
- Agentic architecture with constitutional reasoning (RAG)
- Platform-agnostic design (Mastodon, Discord, Telegram, etc.)
- Action primitives for flexible governance processes
- Temporal awareness for multi-day proposals and voting
- Audit trail with constitutional citations
- Reversible actions with supermajority veto
- Works with local (Ollama) and cloud AI models

Platform support:
- Mastodon: Full implementation with streaming, moderation, and admin skills
- Discord/Telegram: Platform abstraction ready for implementation

Documentation:
- README.md: Architecture and overview
- QUICKSTART.md: Getting started guide
- PLATFORMS.md: Platform implementation guide for developers
- MASTODON_SETUP.md: Complete Mastodon deployment guide
- constitution.md: Example governance constitution

Technical stack:
- Python 3.11+
- SQLAlchemy for state management
- llm CLI for model abstraction
- Mastodon.py for Mastodon integration
- Pydantic for configuration validation

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Nathan Schneider
2026-02-06 17:09:26 -07:00
commit fbc37ecb8f
27 changed files with 6004 additions and 0 deletions

View File

160
src/govbot/utils/config.py Normal file
View File

@@ -0,0 +1,160 @@
"""
Configuration management for Govbot using Pydantic.
Loads configuration from YAML file and environment variables,
with validation to ensure all required settings are present.
"""
from pathlib import Path
from typing import Optional
import yaml
from pydantic import BaseModel, Field
from pydantic_settings import BaseSettings
class MastodonConfig(BaseModel):
"""Mastodon instance configuration"""
instance_url: str = Field(..., description="Mastodon instance URL (e.g., https://mastodon.social)")
client_id: Optional[str] = Field(None, description="OAuth client ID")
client_secret: Optional[str] = Field(None, description="OAuth client secret")
access_token: Optional[str] = Field(None, description="Access token for bot account")
bot_username: str = Field("govbot", description="Bot's Mastodon username")
class AIConfig(BaseModel):
"""AI model configuration"""
default_model: Optional[str] = Field(
None,
description="Default LLM model to use (e.g., 'llama3.2' for Ollama, 'gpt-4' for OpenAI)",
)
fallback_model: Optional[str] = Field(None, description="Fallback model if default fails")
temperature: float = Field(0.7, description="LLM temperature for responses")
max_tokens: Optional[int] = Field(None, description="Maximum tokens for LLM responses")
class GovernanceConfig(BaseModel):
"""Governance system configuration"""
constitution_path: str = Field(
"constitution.md", description="Path to constitution file"
)
db_path: str = Field("govbot.db", description="Path to SQLite database")
default_veto_threshold: float = Field(
0.67, description="Default supermajority veto threshold (e.g., 0.67 = 2/3)"
)
enable_auto_execution: bool = Field(
True, description="Allow bot to execute actions automatically"
)
require_confirmation_for: list[str] = Field(
default_factory=lambda: ["admin_action", "moderation"],
description="Action types requiring human confirmation",
)
class PlatformConfig(BaseModel):
"""Platform selection and configuration"""
type: str = Field(..., description="Platform type: mastodon, discord, telegram, mock")
mastodon: Optional[MastodonConfig] = Field(None, description="Mastodon configuration")
# Future platforms:
# discord: Optional[DiscordConfig] = None
# telegram: Optional[TelegramConfig] = None
class BotConfig(BaseSettings):
"""Main bot configuration"""
platform: PlatformConfig = Field(..., description="Platform configuration")
ai: AIConfig = Field(default_factory=AIConfig)
governance: GovernanceConfig = Field(default_factory=GovernanceConfig)
debug: bool = Field(False, description="Enable debug mode")
log_level: str = Field("INFO", description="Logging level")
class Config:
env_prefix = "GOVBOT_"
env_nested_delimiter = "__"
def load_config(config_path: str = "config/config.yaml") -> BotConfig:
"""
Load configuration from YAML file.
Args:
config_path: Path to YAML config file
Returns:
BotConfig instance
Raises:
FileNotFoundError: If config file doesn't exist
ValidationError: If config is invalid
"""
config_file = Path(config_path)
if not config_file.exists():
raise FileNotFoundError(
f"Config file not found: {config_path}\n"
f"Please create it based on config/config.example.yaml"
)
with open(config_file) as f:
config_data = yaml.safe_load(f)
return BotConfig(**config_data)
def create_example_config(output_path: str = "config/config.example.yaml"):
"""
Create an example configuration file.
Args:
output_path: Where to write the example config
"""
example_config = {
"platform": {
"type": "mastodon", # or "discord", "telegram", "mock"
"mastodon": {
"instance_url": "https://your-mastodon-instance.social",
"client_id": "your_client_id_here",
"client_secret": "your_client_secret_here",
"access_token": "your_access_token_here",
"bot_username": "govbot",
},
# Discord example (for future use):
# "discord": {
# "token": "your_discord_bot_token",
# "guild_id": "your_server_id",
# },
},
"ai": {
"default_model": "llama3.2", # Or 'gpt-4', 'claude-3', etc.
"fallback_model": None,
"temperature": 0.7,
"max_tokens": None,
},
"governance": {
"constitution_path": "constitution.md",
"db_path": "govbot.db",
"default_veto_threshold": 0.67,
"enable_auto_execution": True,
"require_confirmation_for": ["admin_action", "moderation"],
},
"debug": False,
"log_level": "INFO",
}
output_file = Path(output_path)
output_file.parent.mkdir(parents=True, exist_ok=True)
with open(output_file, "w") as f:
yaml.dump(example_config, f, default_flow_style=False, sort_keys=False)
print(f"Example config created at: {output_path}")
if __name__ == "__main__":
# Create example config when run directly
create_example_config()