Content
# Iris — Integrated Runtime Intelligence Service
**I**ntegrated **R**untime **I**ntelligence **S**ervice — a multi-provider AI
router that picks the cheapest-acceptable model for each task, persists
provider stats and conversations across CLI invocations, and learns
provider preferences over time via a **localmem** memory backend.
Unlike LiteLLM (a library you import) and Portkey (a hosted gateway),
IRIS is a **self-hosted service that learns**. Run `iris serve` once,
it remembers which provider worked best for each task type and biases
future routing accordingly. MCP-aware clients connect to it like any
other tool — no external telemetry, no data leaving your machine,
SQLite under the hood.
[](https://github.com/jordanaftermidnight/IRIS_project)
[](https://opensource.org/licenses/MIT)
[](https://nodejs.org/)
## What's there
- **16 providers, no code changes to add a 17th.** 5 native + 11 OpenAI-
compatible built-ins + drop-in config slot for anything else that
speaks the OpenAI Chat Completions protocol.
- **Persistent across invocations.** SQLite store at `~/.iris/iris.db`
keeps provider stats, request history, conversation sessions, and a
knowledge base. Routing decisions actually accumulate — the score
function's success-rate term reflects history, not just the current
process.
- **Learning loop, closed.** Optional connection to a **localmem** server.
The router reads back per-task provider preferences
every 5 minutes and biases scoring toward what's worked before.
- **Conversation continuity.** `iris session new`, then
`iris chat "..." --session=<id>` (or `IRIS_SESSION=<id>`) to keep
context across CLI invocations.
- **Local-first by default.** Ollama runs first; cloud providers fill
in only when needed. `--local` forces local-only.
- **Smart fallback.** A failed provider is excluded from the retry
selection and gets credited the failure (not the next-best one).
- **MCP server built in.** `iris serve` exposes IRIS as a Model Context
Protocol server on port 8782 with 13 tools (chat, council, providers,
health, session CRUD, recent requests, cost summary, breaker status,
batch submit/get), `/metrics` in Prometheus format, `/events` SSE feed,
optional bearer auth, optional mTLS, mDNS service advertisement.
Any MCP-aware client (or memory backend) can call IRIS as a tool.
- **Council fan-out.** `iris council "..."` broadcasts a prompt to N
providers in parallel and shows responses side-by-side with per-call
latency and cost. `--providers=a,b,c` whitelist, `--exclude=x` skip,
`--judge=claude` rank via an LLM judge, `--merge` concatenate with
`[provider]` attribution. Failed providers don't poison the call.
- **Per-provider circuit breakers.** A provider that fails 5x within
60s gets parked for 30s, then probed. The router skips parked
providers so a flapping API doesn't eat retry budgets.
- **Native tool/function calling** across every provider. Pass
OpenAI-spec `tools` to `chat()`; Claude's Anthropic shape is
converted automatically. Response surfaces structured `toolCalls`.
- **Anthropic prompt caching.** `promptCaching: true` wraps the system
prompt and the last tool with `cache_control: ephemeral` for ~90%
off cached input tokens.
- **Structured outputs.** `responseFormat: {type: 'json_schema',...}`
plumbs through to OpenAI / Compat providers.
- **Auto task classification.** Caller omits `taskType`? IRIS infers
it from the message content (deterministic regex + keyword scoring,
no extra LLM call).
- **Structured JSON logs.** pino-backed, pretty on TTY, JSON in serve
mode and pipes. Loki/Vector/Promtail-ready.
- **Live event stream.** `/events` SSE pushes routing decisions,
council results, and breaker transitions in real time.
- **Audit log.** Every MCP tool invocation appended to
`~/.iris/audit.jsonl` for cross-machine traceability.
- **Per-tool latency metrics** (p50/p95/p99) on `/metrics`.
- **mDNS service advertisement** (`_iris-mcp._tcp.local.`) so dashboard
dockviews and discoverers find IRIS on the LAN. Opt-in.
- **${VAR} interpolation** in `iris-config.json` so secrets stay in
env, never in JSON.
- **Cross-platform.** macOS, Linux, Windows — all three are supported
and tested. Single `npm install -g .` everywhere.
## Installation
```bash
git clone https://github.com/jordanaftermidnight/multi-ai-integration-CLI.git
cd multi-ai-integration-CLI
npm install
npm install -g . # for the `iris` global CLI
iris help
```
Requires Node.js >= 18. The SQLite native binding (better-sqlite3)
builds on darwin / linux / windows.
### Optional: Ollama (local, free)
```bash
curl -fsSL https://ollama.ai/install.sh | sh
ollama serve &
ollama pull mistral:7b # balanced default
ollama pull qwen2.5-coder:7b # code tasks
ollama pull llama3.2:latest # creative + vision
ollama pull qwen3:4b # fast / ultra_fast
```
Without Ollama, IRIS falls back to whichever cloud providers you have
keys for.
## Providers
### Native (priority 1–5)
Model IDs verified 2026-06-27. Pin specific versions in
`config/iris-config.json > providers.<name>.models` if you don't want
the defaults to roll forward.
| Name | Env var | Default model lineup |
|------|---------|----------------------|
| `ollama` | `OLLAMA_HOST` (default `http://localhost:11434`) | Local: mistral:7b, qwen2.5-coder:7b, llama3.2, qwen3:4b |
| `groq` | `GROQ_API_KEY` | Llama 4 Scout (multimodal MoE), GPT OSS 20B/120B |
| `openai` | `OPENAI_API_KEY` | GPT-5.5, GPT-5.4 / 5.4-mini / 5.4-nano, o4-mini |
| `gemini` | `GEMINI_API_KEY` | Gemini 3.1 Pro, 3.5 Flash, 3.1 Flash-Lite, 3.1 Flash-Image |
| `claude` | `ANTHROPIC_API_KEY` | Claude Opus 4.8, Sonnet 4.6, Haiku 4.5 |
### Built-in OpenAI-compatible (set the env var, that's it)
| Name | Env var | Description |
|------|---------|-------------|
| `kimi` | `MOONSHOT_API_KEY` | Moonshot Kimi |
| `minimax` | `MINIMAX_API_KEY` | MiniMax |
| `deepseek` | `DEEPSEEK_API_KEY` | DeepSeek (chat + reasoner) |
| `grok` | `XAI_API_KEY` | xAI Grok |
| `mistral` | `MISTRAL_API_KEY` | Mistral La Plateforme |
| `cerebras` | `CEREBRAS_API_KEY` | Cerebras (wafer-scale inference) |
| `together` | `TOGETHER_API_KEY` | Together AI (open-weight specialist) |
| `openrouter` | `OPENROUTER_API_KEY` | OpenRouter (300+ models, single endpoint) |
| `perplexity` | `PERPLEXITY_API_KEY` | Perplexity (search-augmented) |
| `cohere` | `COHERE_API_KEY` | Cohere (Command A+, R+, agentic) |
| `huggingface` | `HF_API_KEY` | HuggingFace Inference Providers (multi-backend router) |
Run `iris providers` for live status.
### Adding any other OpenAI-compatible service
Edit `config/iris-config.json`:
```json
{
"providers": {
"lmstudio": {
"type": "openai-compatible",
"baseURL": "http://localhost:1234/v1",
"allowNoAuth": true,
"models": { "balanced": "local-model" }
}
}
}
```
Works with LM Studio, Fireworks, llama.cpp, vLLM, SiliconFlow,
Anyscale, etc. See `_customProviderExamples` in the config file.
## Quick start
```bash
# Smart routing (picks the best provider for the task)
iris chat "Hello, world"
iris chat "Write a Python sort function" --task=code
iris chat "Compare React vs Solid" --task=complex
# Force a specific provider
iris chat "What's 2+2?" --provider=gemini
iris chat "Long context analysis" --provider=kimi
# Local-only (privacy, zero cost)
iris chat "Summarize this doc" --local
# Conversation continuity
iris session new my-debug-session
iris chat "Help me debug this stack trace:..." --session=my-debug-session
iris chat "What did I just ask you?" --session=my-debug-session
# File analysis
iris file ./src/foo.js --task=code
# System
iris providers # live status of all providers
iris health --verbose # detailed health check
iris status # comprehensive system status
iris models # list available models per provider
```
## Commands
```
iris chat <message> Chat with smart provider selection
iris chat ... --stream Stream tokens as they arrive
iris council <message> Fan-out to N providers, side-by-side
iris session list|new|show|delete Manage persistent sessions
iris file <path> Analyze a file
iris providers Provider status + statistics
iris models List models per provider
iris health Health check
iris status System status overview
iris serve [--port=8782] Run IRIS as an MCP server
iris config save|load [path] Configuration
iris clear Clear in-process context
iris help Show help
```
### Options
| Flag | Effect |
|---|---|
| `--task=<type>` | `code`, `creative`, `fast`, `complex`, `reasoning`, `vision`, `ultra_fast`, `balanced` (default) |
| `--provider=<name>` | Force a specific provider — see `iris providers` for the live list |
| `--session=<id>` | Continue a persistent conversation session |
| `--stream` | Stream the response (provider-dependent) |
| `--local` | Prefer local providers only |
| `--verbose, -v` | Verbose output |
## Configuration
### Environment variables
```bash
# Provider keys (set whichever you use; all optional)
export OLLAMA_HOST="http://localhost:11434"
export OPENAI_API_KEY="..."
export GROQ_API_KEY="..."
export GEMINI_API_KEY="..."
export ANTHROPIC_API_KEY="..."
export MOONSHOT_API_KEY="..." # Kimi
export DEEPSEEK_API_KEY="..."
# ...etc — see provider table above
# IRIS-specific
export IRIS_DB="$HOME/.iris/iris.db" # SQLite store path
export IRIS_SESSION="my-default" # default session id
```
Centralize keys in `~/.secrets` (sourced from your shell rc) and IRIS
picks them up at startup.
### Config file (`config/iris-config.json`)
- `providers.<name>` — override built-in defaults (models, rates,
priority) or define new OpenAI-compatible services.
- `routing` — `preferLocal`, `maxCost`, `costOptimization`.
- `memory.enabled = true` to connect to a local MCP memory backend (e.g., `localmem`)
for the learning loop.
- `server.*` — MCP server settings for `iris serve` (port, host,
agentId, authTokenEnv, metricsEnabled).
The config is schema-validated on load. Unknown keys produce warnings;
type mismatches log errors and fall back to defaults.
## Council (`iris council`)
Broadcast a prompt to every available provider in parallel, see the
answers side-by-side. No judge — you look at them and decide.
```bash
iris council "Best Python lib for date math?"
iris council "Explain quicksort" --providers=claude,openai,gemini
iris council "Quick yes/no" --exclude=ollama --timeout=10
iris council "Pick the cleanest" --judge=claude
```
Failed providers come back with their error tagged, the rest of the
panel still completes. Each call updates the router's `providerStats`,
so council usage feeds future routed-chat scoring.
`--judge=<provider>` calls a named provider after fan-out to rank the
panel. The judge sees every successful response and replies with a
JSON ranking. Hallucinated provider names are filtered; unparseable
output falls back to original order. Auto-skipped when fewer than 2
responses succeed.
## MCP server (`iris serve`)
`iris serve` exposes IRIS as a Model Context Protocol server on port
8782 (configurable). 13 tools registered:
- `iris_chat(message, taskType?, provider?, sessionId?, local?)`
- `iris_council(message, providers?, exclude?, timeoutSeconds?, judge?, merge?)`
- `iris_batch_submit(requests, provider, model?)` — Anthropic or OpenAI batch API (~50% off)
- `iris_batch_get(batchId, provider)` — poll batch status / retrieve results
- `iris_providers()`
- `iris_health()`
- `iris_recent_requests(limit?, sinceIso?)` — snapshot of recent routing decisions
- `iris_cost_summary(sinceIso?)` — cost broken down by provider
- `iris_breaker_status()` — circuit-breaker state per provider
- `iris_session_list(limit?)`
- `iris_session_new(id?)`
- `iris_session_show(id, limit?)`
- `iris_session_delete(id)`
HTTP surface on the same port:
- `GET /sse` — MCP SSE channel (bearer-authed when token configured).
- `POST /messages?sessionId=...` — JSON-RPC messages.
- `GET /events` — live SSE feed of `{type: routing|council|breaker,...}`
events. Bearer-authed. 15s heartbeat keeps the connection alive.
- `GET /metrics` — Prometheus text format (`iris_provider_available`,
`iris_provider_requests_total`, `iris_provider_response_ms_avg`,
`iris_provider_cost_usd_total`, `iris_provider_breaker_state`,...).
Bearer-authed.
- `GET /healthz` — unauthenticated liveness probe.
Set `IRIS_AUTH_TOKEN` to require bearer auth. Multiple IRIS instances on
the same memory backend instance can be disambiguated by setting different
`config.server.agentId` values.
## Cross-platform install (macOS / Linux / Windows)
IRIS is pure Node.js plus one native dep (`better-sqlite3`) which ships
prebuilt binaries for all three platforms.
### macOS / Linux
```bash
brew install node ollama # or apt / dnf / pacman etc.
ollama serve &
ollama pull mistral:7b
git clone https://github.com/jordanaftermidnight/multi-ai-integration-CLI.git
cd multi-ai-integration-CLI
npm install
npm install -g .
iris help
```
Set provider keys in your shell rc (`~/.zshrc` / `~/.bashrc`):
```bash
export OPENAI_API_KEY="..."
export ANTHROPIC_API_KEY="..."
```
### Windows (PowerShell)
```powershell
# Prereqs: install Node.js LTS and Ollama
winget install OpenJS.NodeJS.LTS
winget install Ollama.Ollama # or download from https://ollama.com/download/windows
ollama pull mistral:7b
git clone https://github.com/jordanaftermidnight/multi-ai-integration-CLI.git
cd multi-ai-integration-CLI
npm install
npm install -g .
iris help
```
Set provider keys (current session):
```powershell
$env:OPENAI_API_KEY = "..."
$env:ANTHROPIC_API_KEY = "..."
```
Persist them across sessions:
```powershell
[Environment]::SetEnvironmentVariable("OPENAI_API_KEY", "...", "User")
```
The SQLite store lands at `C:\Users\<name>\.iris\iris.db`. `iris serve`
listens identically on port 8782; `Ctrl+C` shuts down cleanly. Paths,
process signals, and Ollama's HTTP API all behave the same as on
macOS / Linux.
## Cross-machine deploy (Mac client → Linux/Windows server)
Run IRIS on a server with the cloud keys, hit it from any client over
the network. Useful when the keys live somewhere central or when you
want the SQLite store + memory-backend connection to outlive any one laptop.
**1. On the server**
```bash
# Linux (systemd unit, Windows service, or just a tmux session)
export IRIS_AUTH_TOKEN="$(openssl rand -hex 32)" # share this with clients
export OPENAI_API_KEY="..."
export ANTHROPIC_API_KEY="..."
iris serve --host=0.0.0.0 --port=8782
```
PowerShell equivalent on Windows:
```powershell
$env:IRIS_AUTH_TOKEN = [Convert]::ToHexString([System.Security.Cryptography.RandomNumberGenerator]::GetBytes(32)).ToLower()
$env:OPENAI_API_KEY = "..."
iris serve --host=0.0.0.0 --port=8782
```
Bind firewall rules so 8782 only opens to your LAN / VPN subnet. The
bearer token is the auth layer, but defense-in-depth is cheap.
### TLS / mTLS (optional, for untrusted networks)
Add a `tls` block to `config/iris-config.json`:
```json
{
"server": {
"enabled": true,
"host": "0.0.0.0",
"port": 8782,
"tls": {
"certPath": "/etc/iris/cert.pem",
"keyPath": "/etc/iris/key.pem",
"caPath": "/etc/iris/ca.pem",
"requestCert": true,
"rejectUnauthorized": true
}
}
}
```
With `certPath` + `keyPath` set, IRIS serves HTTPS. Add `caPath`,
`requestCert: true`, and `rejectUnauthorized: true` for full mTLS —
clients must present a cert signed by your CA. Useful when the LAN
isn't trusted or the bearer token alone isn't enough.
The boot log shows `tls: true, mtls: true|false` so you can verify
the config landed.
**2. From any client (Mac, Linux, Windows)**
Any MCP-aware client connects to `http://<server>:8782/sse` with the
shared bearer:
```bash
# Example: register IRIS with Claude Code on a different machine
claude mcp add --transport sse iris http://192.168.1.10:8782/sse \
--header "Authorization: Bearer $IRIS_AUTH_TOKEN"
```
Dashboard dockviews subscribe to `/events` for live updates and pull
`/metrics` for the cost ticker. Both honor the same bearer token.
## Memory backend integration
IRIS optionally connects to [`localmem`](https://github.com/jordanaftermidnight/localmem)
— a local-first MCP/SSE memory backend. When the memory backend is enabled in
config, IRIS:
- Logs every routing decision to wing `iris`, room `routing`
- Logs request outcomes (success/failure, latency, cost) to wing
`iris`, room `requests`
- Reads back per-task provider preferences from the memory backend's
intelligence engine every 5 minutes, biasing the router toward
patterns learned from history
- Pushes provider health snapshots to the memory backend's knowledge graph
To enable, install `localmem` locally on `localhost:8781` and flip
`memory.enabled = true` in `config/iris-config.json`. IRIS expects the
backend to expose three MCP tools: `memory_store`, `memory_intel_alerts`,
and `memory_kg_add`. If your backend uses different tool names, the
learning loop will fail silently (logged at debug level). Connection
failures are non-blocking — IRIS works fine without it.
## Architecture
```
src/
├── enhanced-ai.js # global entry, runs CLI
├── index.js # MultiAI: provider lifecycle, sessions, knowledge
├── cli.js # command parsing, subcommands
├── core/
│ ├── ai-router.js # score-based selection, retry, alert bonus, availability cache
│ └── store.js # IrisStore (better-sqlite3): provider_stats, requests, sessions, messages, knowledge
├── providers/
│ ├── ollama-provider.js
│ ├── groq-provider.js
│ ├── openai-provider.js
│ ├── gemini-provider.js
│ ├── claude-provider.js
│ ├── openai-compatible-provider.js # generic adapter for any OpenAI-compatible service
│ └── builtin-registry.js # 9 first-class OpenAI-compatible defaults
└── integrations/
└── memory-client.js # MCP/SSE client
```
See [ROADMAP.md](./ROADMAP.md) for the full development history and
upcoming phases (C: provider base class + multi-turn API; D: IRIS as
MCP server; E: council fan-out; F: live dashboard readiness).
## Development
```bash
npm test # 32 tests, all hand-rolled (no vitest dep yet)
npm run dev # auto-reload on file change
npm run lint # eslint
```
## Troubleshooting
**"No providers available"**
```bash
iris health --verbose
ollama serve & # start Ollama if not running
ollama list # confirm models are pulled
```
**Provider initialization is slow on cold start**
The first `iris` invocation pings every provider with an API key set
to confirm reachability. Subsequent calls use a 60s availability cache.
Provider init runs in parallel since v2.4.0.
**Session not remembered**
Make sure you pass `--session=<id>` (or set `IRIS_SESSION`) on every
call. `iris session list` shows recent sessions.
## License
MIT — see [LICENSE](./LICENSE).
## Acknowledgments
[Ollama](https://ollama.ai/), [Anthropic](https://anthropic.com/),
[Google AI](https://ai.google.dev/), [OpenAI](https://openai.com/),
[Groq](https://groq.com/), and the providers in the built-in registry
for shipping OpenAI-compatible endpoints that make this kind of
adapter possible.
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
No recommendations available