agentleFS
blueman82blueman82/ai-counsel/CLAUDE.md

ai-counsel

CLAUDE.md1 starsChanged 12 months agoMITView on GitHub

  • Installs packages

We split this CLAUDE.md into the rules it gives an agent

15 rules. About 0 are common, 9 are distinctive, and 6 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈9

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 6

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Working Directory Isolation: All adapters run subprocesses from working_directory parameter (client's current directory), preventing models …

    line 45
  2. Distinctive:

    Not recommended: <3B parameters (struggle with vote formatting, echo prompts)

    line 49
  3. Very specific:

    All CLI adapters run subprocesses from the working_directory passed by MCP clients

    line 64
  4. Distinctive:

    Claude: Default isolation via subprocess cwd - models only see files in working directory

    line 66
  5. Distinctive:

    Check early stopping: if ≥66% want to stop → break

    line 131
  6. Distinctive:

    After round 2+: convergence detection compares current vs previous round

    line 132
  7. Very specific:

    If converged/impasse/early-stop: stop early.

    line 133
  8. Distinctive:

    Default: 60s per invocation

    line 248
  9. Distinctive:

    Use cases: cost control, testing, staged rollout, performance tuning, compliance restrictions

    line 257
  10. Very specific:

    Important: Must be <= rounds - 1 for convergence info.

    line 264
  11. Very specific:

    Empty string: No default, no per-participant → {reasoning_effort} becomes ""

    line 293
  12. Distinctive:

    Write test first (TDD)

    line 492
  13. Very specific:

    Run unit tests: pytest tests/unit -v

    line 494
  14. Distinctive:

    Update CLAUDE.md if architecture changes

    line 497
  15. Distinctive:

    Commit with clear message

    line 498

≈ “Common” is an estimate: at least 1 in 5 of the 25,680 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
CLAUDE.md

CLAUDE.md

  • Last updated: 2026-02-15
  • This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

  • AI Counsel: MCP server; multi-model debate; shared prior responses; iterative consensus.
  • Key differentiation: Models engage in actual debate with cross-pollination (not just parallel aggregation).
  • Production Ready: 113+ passing tests, type-safe validation, graceful error handling, structured logging, convergence detection, AI-powered summaries, evidence-based deliberation with secure tool execution.

Architecture

Core Components

  • MCP Server Layer (server.py)
  • Entry point for MCP protocol communication via stdio
  • Exposes 2 MCP tools: deliberate and query_decisions (when decision graph enabled)
  • Handles JSON serialization and response truncation for token limits
  • Logs to mcp_server.log (not stdout/stderr to avoid stdio interference)
  • Deliberation Engine (deliberation/engine.py)
  • Orchestrates multi-round debates between models
  • Manages context building from previous responses
  • Coordinates convergence detection and early stopping
  • Initializes AI summarizer with fallback chain: Claude Sonnet → gpt-6.1-sol → Droid → Gemini
  • Integrates tool execution system for evidence-based deliberation
  • Tool Execution System (deliberation/tools.py, models/tool_schema.py)
  • Base: BaseTool with execute() method and security controls
  • Tools: ReadFileTool (configurable size limit), SearchCodeTool, ListFilesTool, RunCommandTool (whitelist: ls, grep, find, cat, head, tail), GetFileTreeTool (ASCII output for clean JSON)
  • Orchestrator: ToolExecutor parses TOOL_REQUEST markers, validates, routes to tools
  • Security: Whitelisted commands, file size limits, timeout protection (10s default), path exclusion patterns (prevents context contamination)
  • Path Exclusions: Configurable patterns to block access to sensitive directories (e.g., transcripts/, .git/, node_modules/)
  • File Tree Rendering: Uses ASCII characters (|--) in tool responses for clean JSON serialization; Unicode box-drawing (├──) in Round 1 prompts for better readability
  • Context injection: Tool results visible to all participants in subsequent rounds
  • CLI Adapters (adapters/base.py, adapters/claude.py, etc.)
  • Base: BaseCLIAdapter handles subprocess execution, timeout, error handling
  • Concrete: ClaudeAdapter, CodexAdapter, DroidAdapter, GeminiAdapter, LlamaCppAdapter
  • Factory pattern in adapters/__init__.py creates adapters from config
  • Working Directory Isolation: All adapters run subprocesses from working_directory parameter (client's current directory), preventing models from analyzing the wrong repository
  • LlamaCpp Auto-Discovery: Resolves model names to file paths automatically, searches default paths, supports fuzzy matching
  • Model Size Recommendations:
    • Minimum: 7B-8B parameters (Llama-3-8B, Mistral-7B, Qwen-2.5-7B)
    • Not recommended: <3B parameters (struggle with vote formatting, echo prompts)
    • Token limits: Use 2048+ tokens for complete responses
  • Reasoning Effort (config-based defaults with per-participant override):
    • Controls reasoning depth per model via {reasoning_effort} placeholder in CLI args
    • Codex: low, medium, high, xhigh, max, ultra (Ultra requires GPT-6 Astra/Sol) (via -c model_reasoning_effort="{reasoning_effort}")
    • Droid: off, low, medium, high (via -r {reasoning_effort} flag)
    • Claude: low, medium, high, xhigh, max (current Fable 5.1 and Opus/Sonnet/Haiku 5.5)
    • Claude validation: _supports_effort() checks current aliases and supported full IDs
    • Other adapters: N/A (reasoning_effort ignored)
    • Priority chain: Per-participant → Config default_reasoning_effort → Empty string
    • Placeholder mechanism: {reasoning_effort} in args is substituted at runtime
    • Config default: Set default_reasoning_effort field on adapter in config.yaml
    • Runtime override: Pass reasoning_effort on Participant object
  • Working Directory Isolation (adapters/base.py)
  • All CLI adapters run subprocesses from the working_directory passed by MCP clients
  • Prevents models from analyzing the AI Counsel codebase when deliberating about user projects
  • Claude: Default isolation via subprocess cwd - models only see files in working directory
  • Gemini: Workspace boundaries via --include-directories flag + subprocess cwd - strict isolation
  • Codex: Known limitation - can access any file regardless of working_directory (no true isolation)
  • Droid: Subprocess cwd provides basic isolation (no additional flags needed)
  • Flow: MCP client's cwd → deliberate tool's working_directory → adapter subprocess cwd → model sees correct repository
  • Important: Without working_directory, adapters default to current directory (usually the AI Counsel directory)
  • HTTP Adapter Layer (adapters/base_http.py, adapters/ollama.py, etc.)
  • Base: BaseHTTPAdapter handles HTTP mechanics, retry logic, error handling
  • Concrete: OllamaAdapter, LMStudioAdapter
  • Retry: exponential backoff on 5xx/429/network errors, fail-fast on 4xx
  • Authentication: environment variable substitution ${VAR_NAME} in config
  • Uses httpx for async HTTP, tenacity for retry
  • Config Schema (models/config.py, scripts/migrate_config.py)
  • adapters section with explicit type field: cli or http
  • Type discrimination: CLIAdapterConfig vs HTTPAdapterConfig
  • Backward compatible with legacy cli_tools section
  • Migration: python scripts/migrate_config.py config.yaml
  • Convergence Detection (deliberation/convergence.py)
  • Semantic similarity between consecutive rounds
  • Backends: SentenceTransformer (best) → TF-IDF → Jaccard (zero deps)
  • Statuses: converged (≥85%), refining (40-85%), diverging (<40%), impasse
  • Voting-aware: overrides semantic status with voting outcomes
  • Structured Voting (models/schema.py)
  • Vote: option, confidence (0.0-1.0), rationale, continue_debate flag
  • Aggregates into VotingResult with tally and winning option
  • Voting overrides semantic similarity: 2-1 vote → "majority_decision", 3-0 → "unanimous_consensus"
  • Model-Controlled Early Stopping (deliberation/engine.py)
  • Models signal readiness via continue_debate: false in votes
  • Engine checks threshold (default: 66%) after each round
  • Respects min_rounds before allowing early stop
  • Config: deliberation.early_stopping.enabled, threshold, respect_min_rounds
  • Transcript Management (deliberation/transcript.py)
  • Generates markdown in transcripts/ directory
  • Format: YYYYMMDD_HHMMSS_Question_truncated.md
  • Includes AI summary, full debate, voting section, tool executions
  • Data Models (models/schema.py)
  • Pydantic validation: Participant, DeliberateRequest, RoundResponse, Summary, ConvergenceInfo, DeliberationResult
  • Voting: Vote, RoundVote, VotingResult
  • Type-safe throughout system
  • Configuration (config.yaml)
  • See config.yaml for adapter configs, timeouts, convergence thresholds
  • Per-CLI command templates with {model} and {prompt} placeholders
  • Hook disabling for Claude: --settings '{"disableAllHooks": true}'

Data Flow

  1. MCP client invokes deliberate tool → server.py::call_tool() with working_directory set to client's current directory
  2. Request validated against DeliberateRequest schema
  3. DeliberationEngine.execute() orchestrates rounds
  4. For each round:
    • execute_round() → prompts enhanced with voting instructions → adapters invoke CLIs with working_directory
    • Adapter isolation: Subprocess runs from working_directory (client's cwd), models analyze correct repository
    • Responses collected and votes parsed from "VOTE: {json}" markers
    • Tool request parsing: Extract TOOL_REQUEST markers from responses
    • Tool execution: Change to working_directory, validate, execute with timeout/error handling, restore original directory
    • Context injection: Tool results visible to all participants in next round
    • Recording: Track in ToolExecutionRecord for transcript
    • Check early stopping: if ≥66% want to stop → break
  5. After round 2+: convergence detection compares current vs previous round
  6. If converged/impasse/early-stop: stop early; else continue to max rounds
  7. Aggregate voting results: determine winner, consensus status
  8. AI summarizer generates structured summary
  9. Override convergence status with voting outcome if available
  10. TranscriptManager saves markdown with "Tool Executions" section
  11. Result serialized and returned to MCP client

MCP Tool Architecture

  • MCP-Exposed Tools (callable by MCP clients):
  • deliberate: Orchestrate multi-round AI deliberation (requires working_directory parameter)
  • query_decisions: Search decision graph memory (when enabled)
    • Supports threshold parameter (0.0-1.0, default 0.6) for adjustable similarity
    • Empty results include diagnostics: best_match_score, near_misses, suggested_threshold
  • Internal Tools (callable by AI models via TOOL_REQUEST):
  • read_file: Read file contents (max 1MB)
  • search_code: Search codebase with regex patterns
  • list_files: List files matching glob patterns
  • run_command: Execute safe read-only commands
  • Internal tools: TOOL_REQUEST response markers → engine parsing/execution → shared results; no direct MCP exposure.
  • Example: TOOL_REQUEST: {"name": "read_file", "arguments": {"path": "/path/to/file.py"}}
  • Why Two Tool Types?
  • MCP tools: Clients start deliberations and query results
  • Internal tools: AI models gather evidence during deliberation
  • Separation keeps MCP interface clean while empowering models with research capabilities

Decision Graph Memory

  • The decision graph module (decision_graph/) enables persistent learning from deliberations.
  • Module Structure: schema.py, storage.py, similarity.py, retrieval.py, integration.py, cache.py, workers.py, maintenance.py, query_engine.py, exporters.py
  • Core Components:
  • Schema: DecisionNode, ParticipantStance, DecisionSimilarity
  • Storage: SQLite3 with CRUD operations, indexed by timestamp/question_hash/decision_id
  • Retrieval: Uses convergence backend, configurable threshold (default: 0.7), max results (default: 3)
  • Integration: store_deliberation(), get_context_for_deliberation(), async background workers
  • Performance: LRU cache (200 query + 500 embedding entries), 10 jobs/sec, p95 <450ms latency
  • Query Engine: Unified interface for search_similar(), find_contradictions(), trace_evolution()
  • Export: JSON, GraphML, DOT, Markdown formats
  • Data Flow:
  • Write: Extract from DeliberationResult → save to SQLite → queue async similarity computation
  • Read: Query recent decisions → compute similarity → format as markdown → prepend to Round 1 prompt
  • Background: Async worker computes similarities vs recent decisions, stores top-20
  • Performance:
  • Store: <100ms (async background similarity)
  • Query (cache hit): <2μs
  • Query (cache miss): <100ms
  • Background similarity: <10s per decision
  • Memory: ~5KB per decision
  • Configuration: See config.yaml for decision_graph.enabled, db_path, similarity_threshold, max_context_decisions

Evidence-Based Deliberation

  • Enables AI models to gather concrete evidence during debates by executing tools. Tool results visible to ALL participants in subsequent rounds.
  • Tool Interface: BaseTool with async execute(**kwargs) -> ToolResult, timeout protection, error isolation
  • Available Tools:
  1. ReadFileTool: Max 1MB, path validation, descriptive errors
  2. SearchCodeTool: Uses ripgrep (falls back to grep), output truncation
  3. ListFilesTool: Glob patterns, recursive search, directory validation
  4. RunCommandTool: Whitelist (ls, grep, find, cat, head, tail), no shell injection
  • Security:
  • Input validation: Pydantic schema prevents malformed requests
  • Resource limits: Configurable file size (default 1MB), 10s timeout, output truncation
  • Path exclusions: Blocks access to configured patterns (transcripts/, .git/, node_modules/, etc.) to prevent context contamination
  • Isolation: Tool failures don't halt deliberation
  • Audit trail: All executions recorded with timestamps
  • Known limitations: No sandboxing beyond path exclusions, no rate limiting
  • Performance:
  • Parse: <1ms, Validate: <1ms
  • read_file: <10ms, search_code: 50-200ms, list_files: <20ms, run_command: 10-100ms

Development Commands

Virtual Environment Setup

python3 -m venv .venv
source .venv/bin/activate  # macOS/Linux
pip install -r requirements.txt
pip install -r requirements-optional.txt  # Optional: Enhanced convergence backends

Testing

pytest tests/unit -v                      # Unit tests
pytest tests/integration -v -m integration # Integration tests
pytest tests/e2e -v -m e2e                # E2E tests
pytest --cov=. --cov-report=html          # Coverage report

Code Quality

black .           # Format
ruff check .      # Lint
mypy .            # Type check (optional)

Running the Server

  • Development: python server.py (logs to mcp_server.log and stderr)
  • Production: Configure in ~/.claude/config/mcp.json, check mcp_server.log for debugging

Configuration Notes

Timeouts

  • Default: 60s per invocation
  • Reasoning models (Claude Opus 5.5, gpt-6.1-sol, o3-pro): 180-300s recommended
  • Configure per-CLI in config.yaml::adapters::<name>::timeout

Model Registry Enabled Field

  • Each ModelDefinition has an enabled: bool field (default: true)
  • Controls whether models are active and available for deliberations
  • Filtering applied automatically in ModelRegistry.list(), list_for_adapter(), allowed_ids(), and get_default()
  • Disabled models (enabled: false) are hidden from MCP clients but definition retained in config
  • Use cases: cost control, testing, staged rollout, performance tuning, compliance restrictions
  • Pattern: Toggle models on/off without deleting configuration, preserving IDs and metadata

Convergence Detection

  • Enabled by default: deliberation.convergence_detection.enabled: true
  • Threshold: 0.85 (85% similarity = converged)
  • Min rounds before checking: min_rounds_before_check: 1 (checks from round 2)
  • Important: Must be <= rounds - 1 for convergence info. For 2-round deliberations, use min_rounds_before_check: 1
  • Voting override: Voting outcomes override semantic similarity

Model-Controlled Early Stopping

  • Enabled: deliberation.early_stopping.enabled: true
  • Threshold: 0.66 (66% must want to stop)
  • Respects min rounds: respect_min_rounds: true
  • Example: 3 models, 2 say continue_debate: false → stops (2/3 = 66%)

Reasoning Effort Defaults

  • Configure per-adapter reasoning effort defaults in config.yaml:
cli_tools:
  codex:
    command: "codex"
    args: ["exec", "--model", "{model}", "-c", 'model_reasoning_effort="{reasoning_effort}"', "{prompt}"]
    timeout: 180
    default_reasoning_effort: "medium"  # Config default

  droid:
    command: "droid"
    args: ["exec", "-m", "{model}", "-r", "{reasoning_effort}", "{prompt}"]
    timeout: 180
    default_reasoning_effort: "medium"  # Config default
  • Priority Chain (highest to lowest):
  1. Per-participant: Participant(cli="codex", reasoning_effort="high") → uses "high"
  2. Config default: default_reasoning_effort: "medium" → uses "medium"
  3. Empty string: No default, no per-participant → {reasoning_effort} becomes ""
  • Placeholder Mechanism:
  • {reasoning_effort} placeholder in args substituted at runtime
  • Codex: -c model_reasoning_effort="" (empty = default reasoning)
  • Droid: -r "" (empty = adapter handles gracefully)
  • Claude: No placeholder — --effort flag dynamically injected for supported models (validated via _supports_effort())
  • Validation: Invalid values raise ValueError before subprocess call

Hook Management

  • Claude CLI: --settings '{"disableAllHooks": true}' prevents hooks from interfering. Critical for reliable execution.

MCP Response Truncation

  • mcp.max_rounds_in_response: 3 limits rounds in MCP response (avoids token limits)
  • Tool executions are summarized (count by round/type) in MCP response, not full output
  • Full transcript with complete tool outputs always saved to file

Extension Guides

  • For detailed step-by-step guides on extending the system, see:
  • Adding a New CLI Adapter: Subclass BaseCLIAdapter, implement parse_output(), register in factory
  • Adding a New HTTP Adapter: Subclass BaseHTTPAdapter, implement build_request() and parse_response(), configure retry logic
  • Adding a New Tool: Subclass BaseTool, implement execute(), register in ToolExecutor, update schema, write tests

Design Principles

  • DRY: Common logic in base classes, specific parsing in subclasses
  • YAGNI: Build only what's needed, no premature optimization
  • TDD: Red-green-refactor cycle for all features
  • Simple: Straightforward solutions over clever abstractions
  • Type Safety: Pydantic validation throughout
  • Error Isolation: Adapter failures don't halt entire deliberation
  • Configuration: config.yaml plus models/config.py schemas; no committed TODOs or hardcoded configuration.

Common Gotchas

  1. Stdio Contamination: Server uses stdio for MCP protocol. All logging MUST go to file or stderr, never stdout.
  2. Timeout Tuning: Reasoning models can take 60-120+ seconds. Undersized timeouts cause spurious failures.
  3. Convergence Backend: Optional backends (TF-IDF, SentenceTransformer) improve quality but add dependencies. Zero-dep Jaccard backend always available.
  4. Model ID Format: Claude CLI uses aliases (opus, sonnet, haiku), while Droid requires full date-based model IDs (e.g., claude-opus-4-5-20251101).
  5. Context Building: Previous responses passed as context to subsequent rounds. Large debates = large context. Monitor token usage.
  6. Async Execution: Engine uses asyncio for subprocess management. All adapter invocations are async.
  7. Hook Interference: Claude CLI hooks can break CLI invocations during deliberation. Always disable with --settings flag.
  8. Prompt Length Limits: Gemini adapter validates prompts ≤100k chars (prevents "invalid argument" API errors). BaseCLIAdapter.invoke() checks validate_prompt_length() if adapter implements it and raises ValueError with helpful message before making API call. Other adapters can implement similar validation.
  9. Tool Execution Errors: Tool failures are isolated - they don't halt deliberation. Models receive error messages in tool results and can adapt their reasoning. Always check ToolResult.success before using output.
  10. Working Directory Requirement: The deliberate tool requires a working_directory parameter (client's current directory). Tools resolve relative paths from this directory. Without it, the request will fail validation. MCP clients should always pass their current working directory.
  11. Database Directory Creation: DecisionGraphStorage automatically creates parent directories for the database file if they don't exist. This prevents "readonly database" errors for first-time users. If you get SQLite errors, check file/directory permissions, not just existence.
  12. Tool Path Exclusions: Tools automatically exclude configured patterns (transcripts/, .git/, etc.) to prevent context contamination. When models read transcript files from previous deliberations about different codebases, they get confused and describe the wrong repository. File tree generation also excludes these directories.
  13. Nested Claude Code Sessions: Base adapter automatically strips the CLAUDECODE environment variable from subprocesses to prevent "nested session" errors when invoking Claude CLI as a deliberation participant from within Claude Code. This is handled transparently in BaseCLIAdapter.invoke().
  14. NO TODOs - Configuration Pattern Violation: Never commit TODO comments or hardcoded configuration values. This violates the project's configuration architecture where ALL settings live in config.yaml and are validated via Pydantic schemas in models/config.py. If you find yourself writing # TODO: Make configurable, STOP immediately and implement proper configuration first. Example violation: max_depth=3 # TODO: Make configurable. Correct approach: Add FileTreeConfig to models/config.py, add section to config.yaml, read from self.config.deliberation.file_tree.max_depth. This pattern applies to ALL configurable values across the entire codebase.

Common Development Patterns

Working with Model Registry Enabled Field

# Filter enabled models for an adapter
from models.model_registry import ModelRegistry

registry = ModelRegistry(config)

# Get only enabled models (default behavior)
enabled_models = registry.list_for_adapter("claude")
# Returns: [RegistryEntry(enabled=True), ...]

# Check if model is allowed (respects enabled field)
# Claude CLI: use aliases (opus, sonnet, haiku)
is_allowed = registry.is_allowed("claude", "opus")
# Droid: use full date-based IDs
is_allowed = registry.is_allowed("droid", "claude-opus-4-5-20251101")
# Returns: True only if model exists AND enabled=true

# Get default model (skips disabled models)
default_model_id = registry.get_default("claude")
# Returns: First enabled model marked as default, or first enabled model

# Get all models including disabled (for admin interfaces)
all_models = registry.get_all_models("claude")
# Returns: [RegistryEntry(enabled=True/False), ...]

Accessing Decision Graph

# From integration layer
integration = DecisionGraphIntegration()
context = await integration.get_context_for_deliberation(question)
await integration.store_deliberation(question, result)

# From query engine
engine = QueryEngine()
results = await engine.search_similar("question", limit=5)

Tool Usage in Deliberations

# Evidence gathering
"Let me check: TOOL_REQUEST: {\"name\": \"read_file\", \"arguments\": {\"path\": \"/file.py\"}}"

# Code search
"I'll search: TOOL_REQUEST: {\"name\": \"search_code\", \"arguments\": {\"pattern\": \"regex\", \"path\": \"/path\"}}"

# Evidence-based voting
"TOOL_REQUEST: {...}\nBased on evidence: VOTE: {\"option\": \"A\", \"confidence\": 0.9, ...}"

File System Tool Validation

# Validate paths
if not os.path.exists(path):
    return ToolResult(success=False, error=f"Path not found: {path}")

# Check file size
if os.path.getsize(path) > MAX_SIZE:
    return ToolResult(success=False, error=f"File too large (max {MAX_SIZE} bytes)")

Command Whitelisting

ALLOWED_COMMANDS = {"ls", "grep", "find", "cat", "head", "tail"}
command_name = command.split()[0]
if command_name not in ALLOWED_COMMANDS:
    return ToolResult(success=False, error=f"Command not allowed: {command_name}")

Async Operations with Timeout

try:
    result = await asyncio.wait_for(slow_operation(), timeout=self.timeout)
except asyncio.TimeoutError:
    return ToolResult(success=False, error="Operation timed out")

Per-Participant Reasoning Effort

from models.schema import Participant, DeliberateRequest

# Override reasoning effort per-participant (config.yaml sets default)
request = DeliberateRequest(
    question="Complex architecture question",
    participants=[
        Participant(cli="codex", model="gpt-6.1-sol", reasoning_effort="high"),  # Overrides config default
        Participant(cli="claude", model="claude-opus-5-5", reasoning_effort="high"),  # Opus supports effort
        Participant(cli="claude", model="claude-sonnet-5-5", reasoning_effort="medium"),  # Sonnet supports effort
        Participant(cli="droid", model="claude-opus-4-5-20251101", reasoning_effort="medium"),
    ],
    rounds=2,
    working_directory="/path/to/project",
)

# Adapter support matrix:
# - codex: low, medium, high, xhigh, max, ultra (Astra/Sol only for ultra; injected as -c model_reasoning_effort="...")
# - droid: off, low, medium, high (injected as -r flag)
# - claude: low, medium, high, xhigh, max (current Fable, Opus, Sonnet, and Haiku models)
# - gemini/llamacpp: N/A (reasoning_effort ignored)

# Priority chain (Per-participant > Config default > Empty string):
# 1. Participant(reasoning_effort="high") → uses "high"
# 2. No per-participant + config default_reasoning_effort="medium" → uses "medium"
# 3. No per-participant + no config default → empty string (or None for Claude)

Proper Configuration Pattern (NO TODOs)

# WRONG - NEVER DO THIS
def my_function(self):
    max_depth = 3  # TODO: Make configurable
    max_files = 100  # TODO: Make configurable

# RIGHT - Configuration-First Approach
# 1. Add to models/config.py
class MyFeatureConfig(BaseModel):
    max_depth: int = Field(default=3, ge=1, le=10)
    max_files: int = Field(default=100, ge=10, le=1000)

class DeliberationConfig(BaseModel):
    my_feature: MyFeatureConfig = Field(default_factory=MyFeatureConfig)

# 2. Add to config.yaml
deliberation:
  my_feature:
    max_depth: 3
    max_files: 100

# 3. Use in code
def my_function(self):
    config = self.config.deliberation.my_feature
    max_depth = config.max_depth
    max_files = config.max_files

Testing Strategy

  • Unit Tests: Mock adapters, test engine logic, convergence detection, transcript generation, tool execution, schema validation
  • Integration Tests: Real CLI invocations (requires tools installed), convergence with real adapters, context injection, concurrent writes, performance benchmarks
  • E2E Tests: Full workflow with real API calls (slow, expensive, use sparingly)
  • Fixtures: tests/conftest.py provides shared fixtures for adapter mocking
  • Coverage: 113+ tests, comprehensive coverage across all modules

Development Workflow

  1. Write test first (TDD)
  2. Implement feature
  3. Run unit tests: pytest tests/unit -v
  4. Format/lint: black . && ruff check .
  5. Integration test if needed: pytest tests/integration -v
  6. Update CLAUDE.md if architecture changes
  7. Commit with clear message

MCP Integration

  • This server implements MCP protocol for Claude Code integration:
  • Transport: stdio (stdin/stdout)
  • Tools: deliberate and query_decisions with structured JSON I/O
  • Initialization: mcp.server.stdio.stdio_server()
  • Error Handling: Errors serialized to JSON with error_type and status fields

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

Reviews can't be read right now.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.