LLM Council Threaded

April 7, 2026 ยท View on GitHub

llmcouncil

A threaded, follow-up-friendly version of Karpathy's llm-council.

This app lets you ask multiple frontier models the same question, have them review each other's answers, and then produce a final synthesis. Unlike the original weekend hack, this version supports persistent conversations, follow-up questions, and full session context.

What changed in this version

  • Persistent threaded conversations stored locally as JSON
  • Follow-up questions inside the same conversation
  • Context-aware replies that reuse prior user and chairman turns
  • More reliable streaming UI so the app does not hang waiting on final stage events
  • Working default model config for current OpenRouter model IDs

How it works

When you submit a prompt, the app runs a 3-stage council flow:

  1. Stage 1, first opinions
    Each model answers the prompt independently.
  2. Stage 2, peer review
    The model identities are anonymized and each model ranks the responses.
  3. Stage 3, chairman synthesis
    A chairman model produces the final answer using the responses and rankings.

Why use this

Single-model answers are fast, but they can be shallow or confidently wrong.

A council is useful when you want:

  • strategy debates
  • pricing or offer decisions
  • product tradeoff analysis
  • content or positioning reviews
  • a stronger final answer than one model alone

Upstream credit

This repo is based on Andrej Karpathy's original llm-council idea and implementation:

This version extends the original with conversation memory and follow-up support.

Quick start

1. Install dependencies

Backend:

uv sync

Frontend:

cd frontend
npm install
cd ..

2. Configure environment

Copy .env.example to .env:

cp .env.example .env

Then add your OpenRouter API key:

OPENROUTER_API_KEY=sk-or-v1-...

3. Run the app

Option 1:

./start.sh

Option 2:

Backend:

uv run python -m backend.main

Frontend:

cd frontend
npm run dev

Open:

Default model setup

The default council is:

COUNCIL_MODELS = [
    "openai/gpt-5.1",
    "google/gemini-3.1-pro-preview",
    "anthropic/claude-sonnet-4.5",
    "x-ai/grok-4",
]

CHAIRMAN_MODEL = "anthropic/claude-sonnet-4.6"

You can change these in backend/config.py.

Storage

Conversations are stored locally in:

data/conversations/

Each thread is saved as a JSON file, which makes the app simple to inspect, back up, or extend.

Tested flow

This version has been tested with:

  • new conversation creation
  • first message + follow-up message in the same thread
  • stored conversation history across replies
  • frontend streaming completion without hanging on the final stage

Stack

  • Backend: FastAPI, httpx, OpenRouter
  • Frontend: React, Vite, react-markdown
  • Storage: local JSON conversation files
  • Python package manager: uv

Next useful improvements

  • export conversation to Markdown
  • preset modes for strategy, content, product, and trading
  • file/context injection for project-specific debates
  • model health checks and automatic fallbacks

If you build on this repo, credit the upstream and ship your own version.