Skip to main content

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",
    "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 is the gateway origin with no path, such as https://api.otari.ai, because the client adds the API path itself. Every command rejects a base that ends in an API path, such as /v1, before it calls any provider. The error names the setting that supplied the base, whether the config or OTARI_API_BASE/GATEWAY_API_BASE, and the corrected value to set.

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.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for star-chamber 0.4.3
File Size Uploaded
star_chamber-0.4.3.tar.gz 101.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for star-chamber 0.4.3
File Interpreter ABI Platform
star_chamber-0.4.3-py3-none-any.whl Python 3 none any Details

Total release size: 154.7 kB

Release files / star_chamber-0.4.3.tar.gz

Download URL star_chamber-0.4.3.tar.gz
Size 101.6 kB
Tags Source
SHA-256 checksum
How to use checksums
f39d4a0d5749ac03bff355dfb38fb957c52fc23a6391648160d46c5e927cef3d
BLAKE2b-256 checksum
How to use checksums
2cc56384d9f7703eeea72f580f85c32ad0ef4e8bc335ff49367a82ba67cc5d5d
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 17, 2026.

Transparency log

Release files / star_chamber-0.4.3-py3-none-any.whl

Download URL star_chamber-0.4.3-py3-none-any.whl
Size 53.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c80bd688f1a5affdfb3af1af80065ad7e049025a7839eff8da10606a5942e7f4
BLAKE2b-256 checksum
How to use checksums
2cc6ac0a77d5546c457d80320f21f5323fb271149195f3a7a57bb49fede8a473
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 17, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.4.3 This release

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page