Your AI Werewolf agent workbench.
Run games, inspect decisions, benchmark agents, and evolve role skills.
NightCouncil is a 12-player Werewolf system for building and evaluating LLM-driven agents. It combines a deterministic rules engine, role-specific skill prompts, PostgreSQL-backed persistence, a FastAPI backend, and a Vue workbench for live play, replay, benchmark, review, and self-evolution workflows.
PostgreSQL is the only supported runtime source of truth. Local runs/ and
data/ artifacts are auxiliary outputs and should not be treated as durable
state.
| You want to... | Go to |
|---|---|
| Install the project and open the workbench | Quick Start |
| Run a local demo without real model calls | Fake LLM demo mode |
| Configure a real model, database, TTS, or tracing | Configuration |
| Understand what the system can do | Feature Surface |
| Find the major code areas | Architecture Map |
| Run tests and production build checks | Verification |
| Understand what data may be committed | Runtime Data Boundaries |
| Area | What it provides |
|---|---|
| Rules engine | Standard 12-player White Wolf King flow, including night actions, sheriff election, speeches, PK/exile votes, death handling, and win detection. |
| Roles | Villager, werewolf, white wolf king, seer, witch, hunter, and guard. |
| Agent runtime | Role skills, LLM calls, policy constraints, retries, timeouts, decision records, and player-view information isolation. |
| Workbench UI | Lobby, live match, history archive, benchmark lab, self-evolution, task queue, and settings pages. |
| Benchmarking | Batch runs, leaderboards, snapshots, diagnostics, reports, and saved views backed by PostgreSQL. |
| Self-evolution | Candidate skill generation, proposal review, dry-run/preflight checks, and promotion flows. |
| Observability | Health gates, startup diagnostics, optional self-hosted Langfuse tracing, and runtime notices. |
| Path | Purpose |
|---|---|
engine/ |
Deterministic Werewolf rules, phases, actions, and player-facing requests. |
app/ |
Agent orchestration, LLM services, role skill loading, observability helpers, and CLI tools. |
storage/ |
PostgreSQL repositories for games, decisions, benchmarks, evolution, registry, tasks, and artifacts. |
ui/backend/ |
FastAPI API layer that adapts the engine, storage, health checks, settings, and background tasks for the frontend. |
ui/frontend/ |
Vue/Vite workbench application. |
skills/default_baseline/ |
Default role skill baselines. |
migrations/ |
Alembic schema migrations. |
docs/ |
Design notes, audits, execution plans, and runtime policies. |
- Python 3.11+
uv- Node.js 20+ and npm
- PostgreSQL 16+ recommended
Install Python dependencies:
uv syncInstall frontend dependencies:
npm install --prefix ui/frontendCreate a local environment file:
Copy-Item .env.example .envEdit .env and set at least:
POSTGRES_DATABASE_URL=postgresql://wolf_app:password@127.0.0.1:5432/wolf_app
DATABASE_URL=${POSTGRES_DATABASE_URL}
WEREWOLF_LLM_API_KEY=your-api-key
WEREWOLF_LLM_BASE_URL=https://your-provider.example/v1
WEREWOLF_LLM_MODEL=your-modelApply the database schema:
uv run alembic upgrade headValidate and publish default role baselines:
uv run python -m app.tools.seed_default_baseline --dry-run
uv run python -m app.tools.seed_default_baselineStart the backend:
uv run uvicorn ui.backend.main:app --reload --host 127.0.0.1 --port 8000Start the frontend:
npm run dev --prefix ui/frontendOpen the Vite URL printed by the frontend command, usually
http://127.0.0.1:5173. The frontend proxies /api to
http://127.0.0.1:8000 by default.
For a containerized single-node setup, use Docker Compose:
Copy-Item .env.example .env
docker compose up -d --buildCompose starts PostgreSQL, runs Alembic migrations, seeds default role baselines,
starts the API, starts the task worker, and serves the built frontend at
http://127.0.0.1:8080.
For UI and workflow demos that should not call a real model, enable the fake LLM runtime before starting the backend:
$env:UI_BACKEND_USE_FAKE_LLM = "true"
uv run uvicorn ui.backend.main:app --reload --host 127.0.0.1 --port 8000Use real model credentials for benchmark or evolution results that must be meaningful.
| Setting | Notes |
|---|---|
POSTGRES_DATABASE_URL / DATABASE_URL |
Required. PostgreSQL is the authoritative runtime store. |
WEREWOLF_LLM_API_KEY |
Required for real LLM runs. Keep it server-side only. |
WEREWOLF_LLM_BASE_URL |
OpenAI-compatible model endpoint. |
WEREWOLF_LLM_MODEL |
Default model used by runtime agents unless overridden by settings. |
WEREWOLF_LLM_* runtime settings |
Optional timeout, retry, circuit-breaker, and global concurrency tuning. See .env.example. |
UI_BACKEND_USE_FAKE_LLM |
Optional local/demo switch. Do not enable for real evaluation. |
SETTINGS_ADMIN_ENABLED / SETTINGS_ADMIN_TOKEN |
Required for Settings page writes. |
SETTINGS_SECRET_ENCRYPTION_KEY |
Required to store model Profile API keys. Keep stable; rotating it invalidates saved secrets. |
WOLF_USE_PG_TASK_QUEUE / TASK_WORKER_REQUIRED |
Optional durable task queue and worker health gate controls. |
WEREWOLF_GAME_CONCURRENCY |
Optional shared concurrency cap for benchmark, evolution training, and evolution battle games. |
BENCHMARK_ROLE_CONCURRENCY / WEREWOLF_EVOLUTION_ROLE_CONCURRENCY |
Per-batch role concurrency caps, still bounded by game, Judge, and global task-kind budgets. |
UI_TASK_KIND_CONCURRENCY_LIMITS |
Global per-kind concurrency quotas shared by all PostgreSQL workers, encoded as a JSON object. |
UI_BACKGROUND_PERSIST_INTERVAL_SECONDS |
Incremental running-task snapshot throttle in seconds; terminal states always flush immediately. |
WEREWOLF_JUDGE_CONCURRENCY |
Judge concurrency used when a workflow does not provide an explicit policy. |
WEREWOLF_LLM_MAX_CONCURRENCY |
Total LLM request cap within one event loop across games, Judge, and related calls. |
WEREWOLF_GAME_TIMEOUT / WEREWOLF_BATCH_GAME_TIMEOUT |
Optional game and batch execution timeouts. |
PG_POOL_MIN_SIZE / PG_POOL_MAX_SIZE |
Optional PostgreSQL connection-pool sizing fallback. |
PG_API_POOL_MAX_SIZE / PG_WORKER_POOL_MAX_SIZE |
Optional role-specific pool caps so long-running workers do not consume API connections. |
WEREWOLF_TTS_* |
Optional DashScope realtime TTS settings for spoken player lines. |
VITE_API_BASE / UI_FRONTEND_API_PROXY_TARGET |
Optional frontend API base and Vite dev proxy target. |
WOLF_APP_RELEASE / WOLF_GIT_SHA / WOLF_APP_ENVIRONMENT |
Optional release metadata shown in health/ops payloads. |
LANGFUSE_* |
Optional self-hosted Langfuse tracing. For enabled, non-degraded tracing set public/secret keys, base URL, environment, release, sample rate, and input/output capture. |
For a single 2-core/4-thread host, use one Uvicorn process and one task worker, then start with:
WEREWOLF_GAME_CONCURRENCY=4
WEREWOLF_JUDGE_CONCURRENCY=6
WEREWOLF_LLM_MAX_CONCURRENCY=8If PostgreSQL is only reachable through a remote host, keep an SSH tunnel open
and point POSTGRES_DATABASE_URL at the local forwarded port.
The backend exposes:
GET /api/health
Startup diagnostics cover PostgreSQL connectivity, Alembic head status, role
registry baselines, model configuration, fake-model mode, and tracing readiness.
status=degraded can still be usable for fake LLM demos; status=error means a
required dependency such as PostgreSQL or the schema migration is missing.
Missing-table errors such as ui_task_queue mean alembic upgrade head has not
completed against the active database.
Backend and engine tests:
uv run pytest -qFrontend tests:
npm test --prefix ui/frontendFrontend production build:
npm run build --prefix ui/frontendUseful focused checks:
uv run python -m app.tools.seed_default_baseline --dry-run
uv run pytest tests/test_api_contracts.py tests/test_ui_backend_app.py -qPostgreSQL owns games, decisions, UI task events, benchmark/evolution state,
leaderboards, role registry baselines, and artifact metadata. Local generated
files under folders such as runs/, data/, screenshots/, test-results/,
and playwright-report/ are workspace artifacts and should stay out of source
control.
Use PostgreSQL dump/restore or explicit one-shot import scripts for data migration. Do not migrate by committing local JSON, SQLite, pid, log, screenshot, or generated report files.
See docs/runtime-data-boundaries.md for the
full policy.
- Keep secrets in
.env; do not put API keys in frontendVITE_*variables. - When
LANGFUSE_TRACING_ENABLED=true, non-degraded health requiresLANGFUSE_PUBLIC_KEY,LANGFUSE_SECRET_KEY,LANGFUSE_BASE_URL,LANGFUSE_ENVIRONMENT,LANGFUSE_RELEASE,LANGFUSE_SAMPLE_RATE>0, andLANGFUSE_CAPTURE_INPUT_OUTPUT=true. Only enable input/output capture after prompt/response data has been reviewed and redacted. POSTGRES_DISABLE_DOTENV=1is useful for tests that must prove connection information is not implicitly loaded from.env.- Self-evolution can promote candidate skill versions. Use dry-run/review workflows and inspect diffs before relying on automatic promotion for real baselines.