AI Control Tower is a platform that gives an organization a single control plane for its AI estate. It keeps a registry of every provider, model, agent, application and MCP server; watches every run; and — when you put it in the request path — enforces policy, budgets, routing and tool access on live model and tool calls, while holding the upstream credentials so applications never do.
- What's inside
- Architecture
- Quick start (local)
- Running with Docker Compose
- Configuration
- Demo data, accounts and roles
- Product tour
- Onboarding your AI estate
- Using the gateways from your applications
- API at a glance
- Background jobs
- Management commands
- Running the tests
- Project structure
- Security model
- Troubleshooting
- License
| Module | What it gives you | Where |
|---|---|---|
| Dashboard & Control Tower | Executive KPIs for a chosen period, and an end-to-end map of the estate with everything that needs attention | /, /control-tower/ |
| AI Landscape | Registries for applications, agents, models and platform providers — owners, risk, environments, pricing, health | /inventory/ |
| Onboarding | A guided hub and in-app create and edit pages for providers, models, agents, applications, routing, MCP servers, control policies, approval rules, risks and budgets — permission-checked and audited, with no trip to the admin | /onboarding/ |
| Observability | Every run with its timeline, tokens, cost and latency; a live monitor pushed over WebSockets | /executions/ |
| AI Gateway | In-path model calls: policy and budget enforcement, cost-aware routing, fallback chains, circuit breakers, streaming | /gateway/, /routing/ |
| MCP Gateway | One registry for every MCP server, tool review and re-review, per-agent access grants, and a single governed MCP endpoint for all of them | /mcp-gateway/ |
| A2A Gateway | Agent-to-agent communication, governed: a registry of the agents that take work from others, inside the organization or out, skills reviewed before any agent may ask for them, contracts saying which agent may hand work to which and with how sensitive a payload, hop limits, and one Agent2Agent (A2A) endpoint per agent | /a2a-gateway/ |
| AI FinOps | A drill-down cost explorer (department → team → agent → model → provider, or by individual); GitHub Copilot licence and premium-request spend by team and by individual; budgets by department, team, individual or asset with threshold and forecast alerts, chosen recipients and optional hard stops; cost alert rules for spikes and runaway spend; costed optimization recommendations | /costs/ |
| Use-Case Intake · G1 | AI ideas recorded as use cases (IRGF S0–S1) with provisional D1–D5, decided at Gate G1 by tier with IRGF's five outcomes, then registered as draft applications | /intake/ |
| Compliance & Evidence | EU AI Act, ISO/IEC 42001 and NIST AI RMF requirements per system, answered from live platform evidence, with scope decisions, attestations and exportable evidence packs (print to PDF, or a ZIP with JSON and the audit trail) | /compliance/ |
| Runtime Guardrails | Prompt-injection, personal-data, secrets and restricted-topic checks on prompts and completions in the AI and A2A gateways: block, redact or warn by tier, with every hit recorded and masked | admin |
| Solution Advisor | Describe an AI use case and get a blueprint: approach, technology stack, build plan mapped to IRGF stages and gates, team, risks, cost estimate and tier controls, written by ChatGPT or the built-in advisor, and proposed at Gate G1 in one click | /studio/ |
| AI Sandbox | Try prompts against up to three registered models side by side, through the AI Gateway in the sandbox environment, so policies, guardrails and budgets apply | /studio/sandbox/ |
| IRGF Agent | A chat icon on every page. Guided questions by topic, or your own: the IRGF framework (irgframework.org) — stages, gates, tiers, modules, the agent chain — and how the Control Tower applies it, answered from the framework reference, this documentation and the rules the platform enforces, with links to the sources and to the right page | every page |
| AI Governance | IRGF risk classification (Tier 1–4, independently countersigned), deployment authorization of agents and applications with their composite authority (Gate G3), change control (Gate G4) and time-boxed exceptions (M17), the Control Plane comparing what runs with what was authorized (M12), drift records with response windows by tier (M13), action limits enforced before each tool call and every action verified after it (links 06–07), risk register and heat map, human approvals, typed control policies, evaluation suites and red-team runs | /classification/, /lifecycle/, /control-plane/, /risks/, /approvals/, /policies/, /evaluations/ |
| Control & Settings | Tamper-evident audit trail, users, teams, service accounts and API keys | Profile menu |
| Integration Handbook | The developer guide: onboarding, API reference, both gateways, sample code | /docs/integration/ |
flowchart LR
subgraph callers["Callers"]
app["Applications and agents"]
ide["IDEs and MCP clients"]
engine["External AI engines"]
end
subgraph tower["AI Control Tower"]
aigw["AI Gateway<br/>/api/v1/gateway/chat/"]
mcpgw["MCP Gateway<br/>/api/v1/mcp/"]
a2agw["A2A Gateway<br/>/api/v1/a2a/"]
telemetry["Telemetry API<br/>/api/v1/executions/"]
governance["Policies, budgets,<br/>approvals, audit"]
registry["Registries"]
ui["Web UI"]
end
app --> aigw
app --> mcpgw
app --> a2agw
ide --> mcpgw
engine --> telemetry
aigw --> providers["Model providers"]
mcpgw --> servers["MCP servers"]
a2agw --> peers["Other agents:<br/>mailboxes and A2A endpoints"]
aigw -. checks .-> governance
mcpgw -. checks .-> governance
a2agw -. checks .-> governance
registry --- db[("PostgreSQL")]
governance --- db
ui --- db
tower --- redis[("Redis: Celery, Channels, cache")]
The platform runs in two modes, side by side:
- Reporting mode — your engines keep calling their providers directly and report what they did to the telemetry API. The Tower observes and advises; it is never in the request path.
- Gateway mode — applications send model calls to the AI Gateway, tool calls to the MCP Gateway and work for other agents to the A2A Gateway. Policy verdicts become real refusals, budgets become real stops, and every call is recorded.
Everything vendor-specific sits behind an adapter registry in integrations/:
providers (openai, generic_rest, mock), agent engines, webhook normalizers, MCP transports
(streamable_http, mock) and A2A transports (jsonrpc, mock). Adding a vendor means registering
one class, not editing call sites.
Stack: Python 3.12 · Django 6.1 · Django REST Framework 3.18 · Channels 4.3 + Daphne (ASGI and WebSockets) · Celery 5.6 + Redis · PostgreSQL 16 (SQLite for local use) · Bootstrap 5, jQuery and Chart.js · WhiteNoise.
This runs the whole platform on your machine with SQLite, no Docker and no Redis. For every other setup — PostgreSQL and Redis without Docker, a clean install without demo data, connecting real providers and MCP servers, and production deployment — see SETUP.md. For the full technical reference — every setting, the integration contracts of the API and both gateways, operations, troubleshooting and FAQs — see the Technical Guide. How the platform applies the IRGF governance framework — risk tiers, the deployment and change gates, the Control Plane and applications as systems of agents — is in IRGF alignment.
Prerequisites: Python 3.12 and Git.
git clone <your-repository-url> aig-tower
cd aig-tower
python -m venv .venvActivate the virtual environment:
# Windows (PowerShell)
.venv\Scripts\Activate.ps1
# macOS / Linux
source .venv/bin/activatepip install -r requirements.txtCreate a file named .env in the project root:
DJANGO_DEBUG=1
USE_SQLITE=1
# No Redis locally: run background tasks in-process instead of queueing them.
CELERY_TASK_ALWAYS_EAGER=1
.env.exampleis written for Docker Compose (PostgreSQL and Redis on their service hostnames). For a plain local run, the three lines above are all you need; every other setting has a safe development default. See Configuration for the full list.
python manage.py migrate
python manage.py seed_demoseed_demo builds a realistic organization — Northwind Financial Group — with users, teams,
providers, models, agents, applications, 500 executions, budgets, risks, policies, approvals, a
governed MCP estate with real gateway traffic, and an A2A estate: published agents, an external
reinsurer's agent, contracts between them and real hand-offs, refusals included. It also puts the
IRGF lifecycle to work: risk
classifications, deployment authorizations for agents and one application, changes waiting at
Gate G4, an exception, and the drift the Control Plane finds. It is idempotent; run it again
whenever you like.
On its first run it also prints a service-account API key — the only time that key is shown.
Copy it: it is how external code talks to the API and the gateways. (Lost it? Open the profile
menu → Integrations, open the langgraph-runtime service account and issue a new key there.)
python manage.py runserver 8000Open http://localhost:8000 and sign in:
| Password | Role | |
|---|---|---|
ava.mitchell@northwind.example |
ControlTower!2026 |
Organization Administrator (sees everything) |
admin@northwind.example |
ControlTower!2026 |
Superuser: the site administrator, who creates organizations |
runserveralready serves ASGI through Daphne, so the live monitor's WebSockets work in development without a separate process.
The Compose file runs the production-shaped stack: PostgreSQL, Redis, the ASGI web server, a Celery worker and Celery beat.
cp .env.example .env
# Edit .env: set DJANGO_SECRET_KEY, and any provider keys you want to use.
docker compose up --buildIn a second terminal, load the demo estate and create your own superuser if you want one:
docker compose exec web python manage.py seed_demo
docker compose exec web python manage.py createsuperuserThen open http://localhost:8000.
| Service | What it runs | Port |
|---|---|---|
postgres |
PostgreSQL 16 | 5432 |
redis |
Redis 7 — Celery broker and results, cache, Channels layer | 6379 |
web |
migrate, collectstatic, then Daphne serving aig_tower.asgi |
8000 |
celery_worker |
Background tasks | — |
celery_beat |
The periodic schedule (see Background jobs) | — |
The web container sets USE_MANIFEST_STATIC=1, so static files are served compressed and
fingerprinted by WhiteNoise.
All configuration is read from environment variables (a .env file in the project root is loaded
automatically).
| Variable | Default | Purpose |
|---|---|---|
DJANGO_SECRET_KEY |
development-only value | Set a long random value in production. |
DJANGO_DEBUG |
1 |
0 in production. Turning it off also enables secure cookies, HSTS and X-Frame-Options: DENY. |
DJANGO_ALLOWED_HOSTS |
localhost,127.0.0.1,[::1] |
Comma-separated host names. |
DJANGO_CSRF_TRUSTED_ORIGINS |
http://localhost:8000,http://127.0.0.1:8000 |
Origins allowed to post forms. |
SITE_URL |
empty | Absolute base URL used in notification emails. |
USE_MANIFEST_STATIC |
0 |
1 to serve fingerprinted static files (requires collectstatic). |
| Variable | Default | Purpose |
|---|---|---|
USE_SQLITE |
1 |
1 uses db.sqlite3, an in-memory channel layer and a local-memory cache. 0 uses PostgreSQL and Redis. |
POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD |
aig_tower |
PostgreSQL credentials. |
POSTGRES_HOST, POSTGRES_PORT |
localhost, 5432 |
PostgreSQL location. |
REDIS_URL |
redis://localhost:6379/0 |
Cache. |
CELERY_BROKER_URL |
redis://localhost:6379/1 |
Celery broker. |
CELERY_RESULT_BACKEND |
redis://localhost:6379/2 |
Celery results. |
CELERY_TASK_ALWAYS_EAGER |
0 |
1 runs tasks inline — use it when there is no Redis. |
CHANNEL_LAYER_URL |
REDIS_URL |
Redis database for live-monitor broadcasts. |
| Variable | Default | Purpose |
|---|---|---|
DJANGO_EMAIL_BACKEND |
console backend | Notification emails are printed, never sent, until you point this at a real backend. |
DJANGO_FROM_EMAIL |
ai-control-tower@localhost |
Sender address. |
| Variable | Default | Purpose |
|---|---|---|
GATEWAY_ATTEMPT_TIMEOUT |
30 |
Seconds before one provider call is abandoned. |
GATEWAY_DEADLINE |
60 |
Seconds for a whole request, fallbacks included. |
GATEWAY_CIRCUIT_THRESHOLD |
5 |
Consecutive failures before a provider is taken out of rotation. |
GATEWAY_CIRCUIT_COOL_OFF |
30 |
Seconds before an open breaker lets a probe through. |
GATEWAY_ENFORCE_BUDGETS |
1 |
0 makes every hard-stop budget advisory again. |
| Variable | Default | Purpose |
|---|---|---|
MCP_GATEWAY_CALL_TIMEOUT |
30 |
Seconds before one upstream tool call is abandoned. |
MCP_GATEWAY_CIRCUIT_THRESHOLD |
5 |
Consecutive failures before a server is taken out of rotation. |
MCP_GATEWAY_CIRCUIT_COOL_OFF |
30 |
Seconds before an open breaker lets a probe through. |
MCP_GATEWAY_REVIEW_NEW_TOOLS |
1 |
New tools, and tools whose definition changes, wait for review. 0 trusts every upstream. |
MCP_GATEWAY_RECORD_ARGUMENTS |
1 |
Keep tool arguments and result previews in the call log (shown only to prompt.view holders). |
MCP_GATEWAY_ALLOWED_ORIGINS |
empty | Extra browser origins allowed to call the MCP endpoint. |
| Variable | Default | Purpose |
|---|---|---|
A2A_GATEWAY_CALL_TIMEOUT |
30 |
Seconds before one delivery to an agent reached over HTTP is abandoned. |
A2A_GATEWAY_CIRCUIT_THRESHOLD |
5 |
Consecutive failures before an agent is taken out of rotation. |
A2A_GATEWAY_CIRCUIT_COOL_OFF |
30 |
Seconds before an open breaker lets a probe through. |
A2A_GATEWAY_REVIEW_NEW_SKILLS |
1 |
New skills, and skills whose definition changes, wait for review. 0 trusts every agent's card. |
A2A_GATEWAY_RECORD_CONTENT |
1 |
Keep message and answer text in the log of exchanges with agents reached over HTTP (shown only to prompt.view holders). A mailbox message is the delivery itself, so it is kept either way. |
A2A_GATEWAY_MAX_HOPS |
4 |
How many times work may be handed on: A asks B, B asks C, and so on. |
A2A_GATEWAY_MAX_MESSAGE_KB |
256 |
The largest message, or answer, the gateway takes. |
A2A_GATEWAY_ALLOWED_ORIGINS |
empty | Extra browser origins allowed to call the A2A endpoint. |
| Variable | Default | Purpose |
|---|---|---|
PROMPT_REDACT_CLASSIFICATIONS |
confidential,restricted |
Prompt and completion text for agents with these classifications is redacted on screen. |
| Variable | Default | Purpose |
|---|---|---|
ASSISTANT_PROVIDER |
openai |
openai: the IRGF Agent answers with ChatGPT and its skills. documentation: passages quoted from the documentation, no model. |
OPENAI_API_KEY |
(empty) | The key ChatGPT uses. Without it, the agent answers from the documentation. |
ASSISTANT_OPENAI_MODEL |
gpt-4o-mini |
The ChatGPT model. |
ASSISTANT_OPENAI_BASE_URL |
https://api.openai.com/v1 |
Any OpenAI-compatible endpoint. |
ASSISTANT_AGENT |
(empty) | Instead of calling ChatGPT directly, the agent_id of an agent whose model phrases answers through the AI Gateway, under its policy, budget and audit. |
The database never stores a credential. Each provider and MCP server record holds a
credential_ref — the name of an environment variable — and the platform resolves the secret at
call time. Set those variables in the platform's environment, for example:
OPENAI_API_KEY=sk-...
AZURE_OPENAI_API_KEY=...
GITHUB_MCP_TOKEN=...
GITHUB_COPILOT_TOKEN=... # reads Copilot seats and billing usage for Developer ToolsThe registries show each credential as Resolved or Missing, so you can see at a glance which ones the running platform can actually find.
seed_demo creates these users in Northwind Financial Group, all with the password
ControlTower!2026 (change it with --password):
| Name | Title | Role | |
|---|---|---|---|
ava.mitchell@northwind.example |
Ava Mitchell | Chief AI Officer | Organization Administrator |
daniel.okafor@northwind.example |
Daniel Okafor | AI Platform Lead | AI Platform Administrator |
priya.raman@northwind.example |
Priya Raman | Senior AI Engineer | AI Developer |
marcus.lee@northwind.example |
Marcus Lee | AI Engineer | AI Developer |
sofia.hernandez@northwind.example |
Sofia Hernandez | AI Governance Manager | AI Governance Manager |
tom.becker@northwind.example |
Tom Becker | Operational Risk Manager | Risk Manager |
chen.wei@northwind.example |
Chen Wei | Head of Customer Operations | Approver |
nadia.faris@northwind.example |
Nadia Faris | Internal Auditor | Auditor |
admin@northwind.example |
Platform Admin | — | Superuser (site administrator) |
Signing in as different people is the quickest way to see role-based access at work.
Permissions are organization-scoped: the same person can be an Approver in one organization and a Viewer in another.
| Role | Beyond read access, may… |
|---|---|
| Superuser (site administrator) | Not a role but an account flag, set by createsuperuser. Everything in every organization, plus creating organizations and managing anyone's membership in any of them. |
| Organization Administrator / Super Administrator | Everything: people, teams and service accounts, and the second signature on Tier 4 gate decisions, as the Enterprise Governance Sponsor. |
| AI Platform Administrator | Manage the inventory, providers, models, agents and applications; score their risk classification; rScan report · 2026-10-18
From the balcony · 0 of 4 clappedPrincess, Crusoe, Schnitzel and Cap'm Slop read it and passed. Their reasons are on the balcony, with every other verdict. Critics are accounts on this site with no GitHub account behind them. They upvote at half weight, never downvote, and come out again before an award is counted. Who they are. report this listing— log in to report |


0 comments
log in to comment.