star-chamber
Multi-LLM council protocol SDK. Fan out code reviews and design questions to multiple LLM providers, then classify findings by consensus.
Installation
pip install star-chamber
Or with uv:
uv add star-chamber
Otari extra
Routing through an Otari gateway needs the otari extra, because the gateway client ships outside the base install:
pip install 'star-chamber[otari]'
uv add 'star-chamber[otari]'
uvx --from 'star-chamber[otari]' star-chamber list-providers
Without the extra, an Otari-mode council still starts, but every non-local provider fails on its first call reporting that the Otari packages are missing. Direct-key councils never need the extra.
Configuration
Create ~/.config/star-chamber/providers.json:
{
"providers": [
{"provider": "openai", "model": "gpt-4o", "api_key": "${OPENAI_API_KEY}"},
{"provider": "anthropic", "model": "claude-sonnet-4-20250514", "api_key": "${ANTHROPIC_API_KEY}"}
],
"timeout_seconds": 90,
"consensus_threshold": 2
}
API keys can be literal values or ${ENV_VAR} references that are resolved at runtime.
Provider display names
When several council members share one provider — for example, multiple models behind an OpenAI-compatible gateway such as OpenRouter — give each entry a unique display_name. It becomes that member's identity in council output (consensus classification, flagged_by, quality ratings, individual issues) and is matched by --provider filters. Without it, same-provider members collapse into a single vote and unanimous consensus becomes unreachable:
{
"providers": [
{"provider": "openrouter", "display_name": "gpt-5.2", "model": "openai/gpt-5.2", "api_key": "${OPENROUTER_API_KEY}"},
{"provider": "openrouter", "display_name": "gemini-3.1-pro", "model": "google/gemini-3.1-pro-preview", "api_key": "${OPENROUTER_API_KEY}"},
{"provider": "openrouter", "display_name": "grok-4.3", "model": "x-ai/grok-4.3", "api_key": "${OPENROUTER_API_KEY}"}
],
"consensus_threshold": 2
}
In the JSON output, each provider response carries both the underlying provider (the routing target) and this display_name, and the display name is the key used throughout the aggregated result — providers_used, quality_ratings, individual_issues, flagged_by, and failed_providers. A member with no display_name falls back to the provider name.
Otari gateway
Instead of managing API keys per provider, you can route all non-local providers through Otari, Mozilla AI's OpenAI-compatible LLM gateway, by adding a top-level otari object. This mode requires the otari extra:
{
"providers": [
{"provider": "openai", "model": "openai:gpt-4o"},
{"provider": "anthropic", "model": "anthropic:claude-sonnet-4-20250514"}
],
"otari": {
"api_base": "https://your-gateway.example/v1",
"api_key": "${OTARI_API_KEY}"
},
"timeout_seconds": 90,
"consensus_threshold": 2
}
In Otari mode, Otari — not the SDK — picks the upstream provider, so the per-provider provider field becomes a label. Otari expects the model field to use a provider:model prefix such as "openai:gpt-4o"; consult Otari's documentation for its model-naming convention.
api_base and api_key may be omitted from the config; when omitted, the SDK's OtariProvider auto-detects credentials from its own env vars: OTARI_API_KEY for the hosted otari.ai platform (Authorization: Bearer, matching otari.ai's docs), or GATEWAY_API_KEY for a self-hosted gateway (Otari-Key header). OTARI_AI_TOKEN is also accepted as a platform-token alias. Both fields also support ${ENV_VAR} references.
Providers marked "local": true always bypass Otari and continue to use their own api_base.
Override the config path with the STAR_CHAMBER_CONFIG environment variable.
CLI
Code review
star-chamber review src/auth.py src/db.py
Design question
star-chamber ask "Should we use Redis or Memcached for session storage?"
Options
--provider, -p Provider to include (repeatable)
--config Path to providers.json
--timeout Per-provider timeout in seconds
--context-file File containing project context to include in the prompt
--council-context File containing prior council round feedback (debate mode)
--format Output format: text or json
--output Write JSON result to file
List providers
star-chamber list-providers
Protocol schemas
The SDK ships the council protocol specification as package data.
# List available schemas.
star-chamber schema list
# Print a specific schema.
star-chamber schema code-review-result
Python API
from star_chamber import run_council_sync, CouncilConfig, ProviderConfig
config = CouncilConfig(
providers=(
ProviderConfig(provider="openai", model="gpt-4o"),
ProviderConfig(provider="anthropic", model="claude-sonnet-4-20250514"),
),
timeout_seconds=90,
consensus_threshold=2,
)
# Code review.
result = run_council_sync(
files={"auth.py": open("auth.py").read()},
config=config,
mode="code-review",
)
print(result.summary)
for issue in result.consensus_issues:
print(f" [{issue.severity}] {issue.location}: {issue.description}")
# Design question.
result = run_council_sync(
prompt="Should we use a monorepo or polyrepo?",
config=config,
mode="design-question",
)
print(result.consensus_recommendation)
Async
import asyncio
from star_chamber import run_council
result = asyncio.run(run_council(
files={"auth.py": open("auth.py").read()},
mode="code-review",
))
Schema access
from star_chamber import get_schema, list_schemas
# List available schema names.
names = list_schemas()
# Get a specific schema as a JSON string.
schema_json = get_schema("code-review-result")
Consensus classification
Issues from multiple providers are grouped by file, line proximity (within 5 lines), and category, then classified as:
- Consensus -- all providers agree.
- Majority -- two or more providers agree, but not all.
- Individual -- flagged by a single provider.
Results are sorted by severity within each bucket.
License
Apache-2.0
Metadata
Release files for star-chamber 0.4.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| star_chamber-0.4.2.tar.gz | 98.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| star_chamber-0.4.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 150.5 kB
Release files / star_chamber-0.4.2.tar.gz
| Download URL | star_chamber-0.4.2.tar.gz |
|---|---|
| Size | 98.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
39e808a6d2b3767efda6b2365d1594dc9e50136530f6694f77ab9f4ec11b17ec
|
|
BLAKE2b-256 checksum How to use checksums |
0c5b13f147c95f035af1ceb2c1f20a586d10cf8897fb610ce8c8859921c2420b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 8, 2026.
Transparency logRelease files / star_chamber-0.4.2-py3-none-any.whl
| Download URL | star_chamber-0.4.2-py3-none-any.whl |
|---|---|
| Size | 51.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c0f5a693fa02c10814840c0281d503b7361309528f7e81af3aca9321383a6cd4
|
|
BLAKE2b-256 checksum How to use checksums |
f8d19cfd53e796230f053f07e6abfe7e8c50cb9c3b10bc2bea1161c6b9b08ca2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 8, 2026.
Transparency log