An open API service indexing awesome lists of open source software.

https://github.com/blanzy-labs/ai-council

A local-first app for collecting and comparing responses from an AI council. Part of the Blanzy Labs AI app family.
https://github.com/blanzy-labs/ai-council

ai blanzy-labs council docker fastapi llm local-first openai react sse vite

Last synced: about 23 hours ago
JSON representation

A local-first app for collecting and comparing responses from an AI council. Part of the Blanzy Labs AI app family.

Awesome Lists containing this project

README

          

# AI Council

A local-first, text-based multi-persona AI council room for structured discussion, critique, follow-up chat, live activity events, and transcript export.

Part of the Blanzy Labs AI app family.

**Current release:** v0.1.2 - Blanzy Labs Standardization Patch

AI Council v0.1.x is intended for local testing, demos, and iteration. It runs with a deterministic mock provider by default for safe local workflows, and can call OpenAI only when explicitly configured and selected.

See the [disclaimer](docs/disclaimer.md) before using AI Council. You are responsible for your own usage, costs, data, decisions, and outcomes.

## Current Scope

- OpenAI provider support
- Mock provider for local testing without `OPENAI_API_KEY`
- Multi-persona council sessions
- Default personas
- Structured council run
- Follow-up chat
- Ask whole council
- Ask one persona
- Server-Sent Events live activity events
- Markdown export
- JSON export
- In-memory sessions/transcripts/events only
- Docker Compose local run

## Out Of Scope For v0.1.x

- Voice
- Gemini
- Database persistence
- User accounts
- Telemetry
- Hosted deployment
- Long-term session history
- Token-by-token model streaming
- Autonomous/open-ended agent loops

## Roadmap

- v0.2.0: voice experiments using OpenAI only
- v0.3.0: Gemini provider adapter exploration

## Architecture Overview

- FastAPI backend exposes personas, sessions, council runs, chat, events, exports, health, and version metadata.
- React/Vite frontend provides the local app UI.
- Provider adapter layer normalizes mock and OpenAI responses behind one interface.
- Persona registry provides the default council personas.
- In-memory session, transcript, and event stores hold runtime state only.
- SSE event stream powers live activity updates.
- Export service generates Markdown and JSON from the current in-memory session state.
- Docker Compose runs backend and frontend together for local validation.

There is no database in v0.1.x. Restarting the backend loses sessions, transcripts, events, and exportable state.

## Local Setup

For the standalone setup guide, see [Local Install](docs/local-install.md).

Prerequisites:

- Git
- Python 3.13
- `uv`
- Node.js and `pnpm`
- Docker Desktop or Docker daemon, if using Docker Compose

Copy the example environment file:

```sh
cp .env.example .env
```

Only set `OPENAI_API_KEY` if you are manually testing OpenAI. Mock mode and normal tests do not require an API key.

Backend:

```sh
cd backend
uv sync
uv run uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
```

Frontend:

```sh
cd frontend
pnpm install
pnpm dev
```

Local URLs:

- Frontend: http://localhost:5173
- Backend: http://localhost:8000
- API docs: http://localhost:8000/docs
- Health: http://localhost:8000/health
- Version: http://localhost:8000/version

## Docker Setup

Build and start both services:

```sh
docker compose up --build
```

Expected URLs:

- Frontend: http://localhost:5173
- Backend: http://localhost:8000
- Health: http://localhost:8000/health

Stop services:

```sh
docker compose down
```

## Testing

Backend tests:

```sh
cd backend
uv run pytest
```

Frontend build:

```sh
cd frontend
pnpm build
```

Docker build:

```sh
docker compose build
```

Optional real OpenAI smoke test:

```sh
cd backend
# Set OPENAI_API_KEY in your shell first.
RUN_OPENAI_INTEGRATION_TESTS=1 uv run pytest tests/test_openai_integration.py -m integration
```

Normal tests skip real OpenAI calls.

## Usage Workflow

1. Create session.
2. Select personas.
3. Run council.
4. Continue chat.
5. Watch live activity.
6. Export transcript.

Recommended local testing path: use `provider_override: "mock"` in run/chat requests, or select `mock` in the frontend.

## API Summary

- `GET /`
- `GET /health`
- `GET /version`
- `GET /personas`
- `GET /personas/{persona_id}`
- `POST /providers/test-generate`
- `POST /sessions`
- `GET /sessions`
- `GET /sessions/{session_id}`
- `POST /sessions/{session_id}/run`
- `POST /sessions/{session_id}/chat`
- `GET /sessions/{session_id}/messages`
- `DELETE /sessions/{session_id}/messages`
- `GET /sessions/{session_id}/events`
- `GET /sessions/{session_id}/events/recent`
- `DELETE /sessions/{session_id}/events`
- `GET /sessions/{session_id}/result`
- `POST /sessions/{session_id}/export`
- `GET /sessions/{session_id}/export/markdown`
- `GET /sessions/{session_id}/export/json`

## Curl Examples

Metadata:

```sh
curl http://localhost:8000/
curl http://localhost:8000/health
curl http://localhost:8000/version
```

Create a session:

```sh
curl -X POST http://localhost:8000/sessions \
-H "Content-Type: application/json" \
-d '{
"title": "Local-first AI Council",
"topic": "Should AI Council be built as a local-first multi-persona app?",
"mode": "ask_council",
"selected_persona_ids": [
"moderator",
"strategist",
"skeptic",
"builder",
"customer_advocate"
]
}'
```

Run council with mock:

```sh
curl -X POST http://localhost:8000/sessions//run \
-H "Content-Type: application/json" \
-d '{
"provider_override": "mock",
"max_rounds": 1,
"include_moderator_summary": true
}'
```

Ask the whole council:

```sh
curl -X POST http://localhost:8000/sessions//chat \
-H "Content-Type: application/json" \
-d '{
"message": "What is the riskiest assumption in this plan?",
"target": {
"type": "council"
},
"provider_override": "mock",
"include_moderator_summary": false
}'
```

Ask one persona:

```sh
curl -X POST http://localhost:8000/sessions//chat \
-H "Content-Type: application/json" \
-d '{
"message": "What is the smallest useful MVP?",
"target": {
"type": "persona",
"persona_id": "builder"
},
"provider_override": "mock",
"include_moderator_summary": false
}'
```

Recent events:

```sh
curl http://localhost:8000/sessions//events/recent
```

Live SSE stream:

```sh
curl -N http://localhost:8000/sessions//events
```

Inline Markdown export:

```sh
curl -X POST http://localhost:8000/sessions//export \
-H "Content-Type: application/json" \
-d '{
"format": "markdown",
"include_events": false,
"include_metadata": true
}'
```

Inline JSON export:

```sh
curl -X POST http://localhost:8000/sessions//export \
-H "Content-Type: application/json" \
-d '{
"format": "json",
"include_events": true,
"include_metadata": true
}'
```

Direct downloads:

```sh
curl -OJ http://localhost:8000/sessions//export/markdown
curl -OJ http://localhost:8000/sessions//export/json
```

Clear runtime state:

```sh
curl -X DELETE http://localhost:8000/sessions//messages
curl -X DELETE http://localhost:8000/sessions//events
```

## Troubleshooting

For the standalone troubleshooting guide, see [Troubleshooting](docs/troubleshooting.md).

Docker Desktop not running:

- Start Docker Desktop or your Docker daemon.
- Rerun `docker compose up --build`.

Ports `8000` or `5173` already in use:

- Stop the process using the port, or adjust `BACKEND_PORT` / `FRONTEND_PORT` in `.env`.

Frontend cannot reach backend:

- Confirm backend health: `curl http://localhost:8000/health`.
- Confirm `VITE_API_BASE_URL=http://localhost:8000`.
- If using Docker, run `docker compose ps`.

OpenAI key missing:

- Mock mode works without a key.
- Real OpenAI calls require `OPENAI_API_KEY`.
- Missing keys return a clean API error and do not prevent app startup.

Mock works but OpenAI fails:

- Confirm `OPENAI_API_KEY` is set in `.env` or the backend environment.
- Confirm the selected provider is `openai`.
- Check backend logs for provider errors.

Sessions disappear after restart:

- Expected in v0.1.x. Runtime state is in memory only.

CORS/local URL issues:

- Default allowed frontend origins are `http://localhost:5173` and `http://127.0.0.1:5173`.
- Add comma-separated local origins with `CORS_ORIGINS` if needed.

## Documentation

- [v0.1.0 scope](docs/v0.1.0-scope.md)
- [release notes v0.1.0](docs/release-notes/v0.1.0.md)
- [release notes v0.1.1](docs/release-notes/v0.1.1.md)
- [release notes v0.1.2](docs/release-notes/v0.1.2.md)
- [GitHub release notes](docs/github-release-notes.md)
- [demo guide](docs/demo.md)
- [local install](docs/local-install.md)
- [troubleshooting](docs/troubleshooting.md)
- [disclaimer](docs/disclaimer.md)
- [validation checklist](docs/validation/v0.1.0-validation.md)
- [validation v0.1.2](docs/validation/v0.1.2-validation.md)
- [architecture notes](docs/architecture.md)
- [security and privacy notes](docs/security-and-privacy.md)
- [sample scenarios](docs/sample-scenarios.md)
- [release checklist](docs/release-checklist.md)
- [license](LICENSE)