Imported from KonghaYao/consensus-swarm (
AGENTS.md). Install upstream withnpx skills add KonghaYao/consensus-swarm. Copyright stays with the author.
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
Consensus is a multi-agent consensus system using LangGraph. Multiple AI agents participate in structured meetings to
discuss topics, vote, and reach consensus (100% agreement required). The system uses a "single agent function"
architecture where LangGraph has one node that routes to different handlers based on state.action.
Tech Stack
- Backend: Bun + Hono + LangGraph + Anthropic/OpenAI SDKs
- Frontend: React 19 + Vite + Tailwind CSS + Radix UI (ShadCN-style components)
- State Management: LangGraph State Annotation (backend), @nanostores (frontend)
- Testing: Vitest
Common Commands
# Development
pnpm dev:all # Start both frontend and backend
pnpm dev:server # Start backend only (Bun on port 8123)
pnpm dev:frontend # Start frontend only (Vite on port 5173)
# Building
pnpm build # Build both server and frontend
pnpm build:server # Build server (TypeScript compilation)
pnpm build:frontend # Build frontend (Vite build)
# Type checking
pnpm type-check # Type check all packages
pnpm type-check:server # Type check server only
pnpm type-check:frontend # Type check frontend only
# Testing
pnpm test # Run Vitest tests
Architecture
Backend Structure
server/src/
├── agent/
│ ├── types.ts # Core type definitions (AgentConfig, ModelConfig, etc.)
│ ├── standard-agent.ts # Agent factory using langchain createAgent()
│ ├── consensus-state.ts # LangGraph state annotation (ConsensusAnnotation)
│ ├── consensus-graph.ts # Single-node LangGraph with action-based routing
│ └── tools/
│ ├── index.ts # Tool registry for loading tools from config
│ └── registry.ts # Tool definitions
├── config/
│ ├── master-agent.ts # Config for the moderator/summarizer agent
│ └── agents/
│ └── *.ts # Individual agent role configs (PM, Tech Lead, etc.)
├── utils/
│ ├── initChatModel.ts # Factory for Anthropic/OpenAI chat models
│ └── ask-agents.ts # Helper to create sub-agents as tools
└── index.ts # Hono server with LangGraph adapter
Key Backend Concepts
Single Agent Function Architecture: The LangGraph has only one node (consensusAgentFunction) that switches
behavior based on state.action:
DISCUSS: Agents share perspectives on the topicVOTE: All agents vote yes/no (requires 100% consensus)CHECK_CONSENSUS: If not unanimous, dissenting agents speakSUMMARIZE: Master agent creates final summary
Agent Factory Pattern: createStandardAgent() in server/src/agent/standard-agent.ts creates LangChain agents from
AgentConfig objects. The config includes:
role: Name, description, perspective, system promptmodel: Provider (anthropic/openai), model name, thinking mode toggletools: Object mapping tool names to boolean enables
Tool System: Tools are loaded dynamically from config via toolRegistry.loadFromConfig(). Custom tools can be added
to server/src/agent/tools/registry.ts.
Sub-agents as Tools: Participants are exposed as tools to the master agent via ask_subagents() helper from
utils/ask-agents.ts.
Frontend Structure
frontend/src/
├── components/
│ ├── chat/ # Chat interface components
│ │ ├── ChatPage.tsx # Main chat page with sidebar
│ │ ├── ChatInput.tsx # Message input
│ │ ├── MessageList.tsx # Message display
│ │ ├── HistorySidebar.tsx # Chat history sidebar
│ │ └── [message types]
│ ├── agent-config/ # Agent configuration UI
│ ├── ai-elements/ # Markdown rendering (Streamdown)
│ └── ui/ # Radix UI components
├── pages/
│ ├── ChatPage.tsx # Chat route
│ └── AgentConfigPage.tsx # Agent config route
├── layouts/
│ ├── Main.tsx # Main layout with header
│ └── Header.tsx
└── main.tsx # App entry point
Frontend Details
- Streaming: Uses Vercel AI SDK (
aipackage) for streaming responses - Markdown: Streamdown with plugins for code, math, mermaid, CJK support
- State: @nanostores for lightweight state management
- Routing: React Router v7
Configuration
Environment Variables
Required in .env:
OPENAI_API_KEY= # Required (even if using Anthropic)
OPENAI_BASE_URL= # Optional custom base URL
# For PostgreSQL persistence (optional, defaults to SQLite):
# DATABASE_URL=postgresql://...
# DATABASE_NAME=langgraph_db
The project uses SQLite by default for state persistence (.langgraph_api/langgraph.db).
Agent Configuration
Agent roles are defined in server/src/config/agents/*.ts. Each config exports an AgentConfig object:
export const exampleAgentConfig: AgentConfig = {
id: 'example-agent',
role: {
id: 'example',
name: 'Example Agent',
description: 'Brief description',
perspective: 'How they view problems',
systemPrompt: 'Additional context...', // optional
},
model: {
provider: 'anthropic',
model: 'claude-3-5-sonnet-20241022',
enableThinking: true,
},
tools: {
search: true, // Enable search tool
code: false, // Disable code execution
},
};
Important Implementation Notes
-
LangGraph State: All state changes must use
ConsensusAnnotationfromserver/src/agent/consensus-state.ts. Do not modify state directly - return partial state updates from the agent function. -
Tool Creation: When adding new tools, register them in
server/src/agent/tools/registry.tsand expose a boolean flag inAgentConfig.tools. -
Model Initialization: Use
initChatModel()fromserver/src/utils/initChatModel.tsfor consistent model initialization across the codebase. -
Message Filtering: The system filters messages before passing to sub-agents to avoid exposing tool calls. This is done via
messageFilterparameter inask_subagents(). -
Consensus Check: The consensus logic checks for
<vote>yes</vote>tags in agent responses. All agents must vote yes to reach consensus. -
Frontend Streaming: The backend LangGraph is exposed via
@langgraph-js/pure-graphHono adapter at/api/langgraph. Frontend uses@langgraph-js/sdkfor streaming.
Development Patterns
- Adding a New Agent: Create a new config file in
server/src/config/agents/and import it where needed. - Modifying the Flow: Edit
consensusAgentFunctioninserver/src/agent/consensus-graph.tsand updateMeetingActionenum inconsensus-state.ts. - Custom Voting Logic: Modify the vote parsing logic in
ask_everyone_to_votetool withinconsensus-graph.ts. - Frontend Components: Use Radix UI primitives from
components/ui/and compose them with Tailwind utility classes.