iris-core
Health Pass
- License — License: Apache-2.0
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Community trust — 10 GitHub stars
Code Fail
- rm -rf — Recursive force deletion command in bootstrap.sh
- process.env — Environment variable access in iris-runtime/examples/bridge/server.js
- network request — Outbound network request in iris-runtime/examples/bridge/server.js
Permissions Pass
- Permissions — No dangerous permissions requested
No AI report is available for this listing yet.
Self-hosted Slack/Telegram bot that agents itself — writes and deploys skills at runtime
Iris
An AI operator that never clocks out. Message it on Slack, Telegram, or its
built-in web UI and it
runs commands, writes its own skills on the fly, provisions infrastructure, and
spins up a fleet of specialized sub-agents — each one optionally sealed inside
its own Firecracker microVM — to get the work done.
One curl | bash on any Linux box turns it into a self-hosted, self-healing
AI teammate — no cloud account, no Kubernetes, no vendor lock-in required.
- Self-extending — Iris writes and hot-reloads her own skills; no redeploy to teach her something new
- Fleet, not chatbot — spins up specialized sub-agents on demand, each talking over an HTTP bridge
- Defense in depth, opt-in — Docker by default; flip a flag and every sub-agent runs in its own Firecracker microVM with a hardware KVM boundary
- Provider-agnostic — Anthropic, OpenAI, Azure AI Foundry, or AWS Bedrock, switchable via env vars
- Three transports, one engine — Slack, Telegram, and an optional built-in web UI (thread sidebar, live tool-call cards, attachments); adding a transport requires zero engine edits
- MCP servers — external toolsets (stdio or remote HTTP) plug in via
data/mcp.json, hot-reloaded and manageable through chat (seedocs/mcp.md) - Resilient — LLM retry with backoff, automatic context compaction, self-healing escalation
- Durable by design — GitHub is the source of truth; the machine itself is cattle, not a pet
- Zero cloud dependencies to start — secrets in
/iris/.env, sub-agents in Docker; Azure Key Vault and Terraform are opt-in hardening, not requirements - Opt-in credential broker — encrypted local secret storage or a separate-uid injection proxy (
IRIS_SECRETS_MODE=store|proxy), plus one-time drop links so users never have to paste a secret into chat (seedocs/secrets.md)
Quickstart
One command on any Ubuntu 22.04 machine — no Azure, no KVM:
curl -fsSL https://raw.githubusercontent.com/irisworks/iris-core/main/install.sh | bash
This clones the repo to /iris/repo and runs the interactive bootstrap: it installs
dependencies, asks for your LLM API key, walks you through creating a Slack app
and/or Telegram bot (exact scopes shown in-terminal), builds the runtime, and starts
Iris as a systemd service.
Verify: sudo systemctl status iris, then in Slack: @iris what model are you?
Want secrets in Azure Key Vault, or every command isolated in a Firecracker microVM?
Pass bootstrap flags through the installer — see docs/SETUP.md
for full walkthroughs of all four paths, including Telegram bot claiming:
| No Firecracker | With Firecracker | |
|---|---|---|
| No Azure | (default) | | bash -s -- --setup --no-keyvault --firecracker |
| Azure Key Vault | | bash -s -- --setup --keyvault |
| bash -s -- --setup --keyvault --firecracker |
Already cloned? bash bootstrap.sh --setup --no-keyvault does the same without the installer.
Talking to Iris
- Slack:
@iris <anything>in a channel, or DM her directly. Attachments work both ways. - Telegram: message your claimed bot; groups and topic threads supported.
- Web UI: set
IRIS_WEBUI_PORTand open it in a browser — thread sidebar,
agent picker, live tool-call cards, file attachments, and Stop/Compact/Reset
buttons. Off by default; see docs/web-ui.md. - Control commands:
stop,compact,resetin an admin-mode Slack DM;/stop,/compact,/reseton Telegram; buttons in the web UI.
Channel Modes
How Iris behaves in a Slack channel is configured per channel in<workspace>/data/channels.json:
| Mode | Behavior |
|---|---|
dm |
Default. Responds in DMs; channels need an @iris mention |
admin |
Like dm, plus stop / compact / reset control commands |
thread |
Only responds inside registered session threads (sessions created via the API) |
interactive-thread |
Top-level @iris mention opens a session; replies in that thread continue it without further mentions |
leads |
Every top-level message triggers Iris — no mention needed |
passthrough |
Messages are forwarded to an external HTTP endpoint; the reply is posted back. Iris's LLM never runs |
{
"C0XXXXXXX": { "mode": "interactive-thread", "requireMentionForTopLevel": true },
"C0YYYYYYY": {
"mode": "passthrough",
"url": "https://example.com/webhook",
"secretName": "MY-WEBHOOK-KEY",
"payload": { "sender_id": "{{sender_id}}", "message_text": "{{text}}" },
"replyPrefix": "*Bot:* "
},
"D*": { "mode": "admin" }
}
Keys are channel IDs (prefix wildcards like D* supported). Passthrough payload
is a JSON template — string values may use {{text}}, {{user_id}}, {{user_name}},{{user_handle}}, {{sender_id}}, {{channel}}, {{ts}}. The API key comes fromsecretName (via the get-secret skill) or the PASSTHROUGH_API_KEY env var.
Configuration
Set in /iris/.env (written by bootstrap) or as CLI flags (--provider, --model,--sandbox, --transport, --api-port). Flags override env.
| Variable | Default | Purpose |
|---|---|---|
IRIS_PROVIDER / IRIS_MODEL |
anthropic / provider default |
LLM provider and model (see data/models.json) |
IRIS_SLACK_APP_TOKEN / IRIS_SLACK_BOT_TOKEN |
— | Slack tokens; presence enables the Slack transport |
TELEGRAM_BOT_TOKEN |
— | Telegram token; presence enables the Telegram transport |
IRIS_ENV |
prod |
preview | prod |
IRIS_API_PORT / IRIS_API_HOST |
3000 / 127.0.0.1 |
Internal HTTP API bind (always on) |
IRIS_API_TOKEN |
— | When set, API requires Authorization: Bearer <token> (except /health) |
IRIS_BRIDGE_PORT / IRIS_BRIDGE_HOST |
— / 127.0.0.1 |
Sub-agent bridge server (sub-agents only) |
IRIS_LLM_TIMEOUT_SECS |
90 |
Per-attempt LLM timeout |
IRIS_LLM_MAX_RETRIES / IRIS_LLM_RETRY_BASE_MS |
3 / 2000 |
Retry with exponential backoff on 429/timeout/transient errors |
IRIS_COMPACT_THRESHOLD / IRIS_COMPACT_TARGET |
0.6 / 0.1 |
Pre-run auto-compaction trigger/target (fraction of context window) |
IRIS_SLACK_MAX_CHARS |
30000 |
Safe Slack message length before splitting |
IRIS_TELEGRAM_FORCE_RECLAIM |
— | Set true + restart to transfer bot ownership |
IRIS_WEBUI_PORT / IRIS_WEBUI_PASSWORD |
— (off) / — | Enable the built-in web UI on this port; shared-secret login (set it before exposing beyond loopback) |
IRIS_SECRETS_MODE |
env |
env | store | proxy — opt-in encrypted store / injection-proxy credential broker (see docs/secrets.md) |
IRIS_SECRET_BROKER_URL / IRIS_SECRET_BROKER_TOKEN |
— | External secret broker for GET /secrets/:name (the bundled iris-broker in proxy mode, Vault, Infisical, or any HTTP service speaking the contract); default backend is env vars, then Key Vault if IRIS_KEY_VAULT is set |
IRIS_GITHUB_ORG / IRIS_GITHUB_REPO |
— | Identity injected into the constitution |
IRIS_KEY_VAULT |
— | Azure Key Vault name (Key Vault profile only) |
IRIS_BASE_DOMAIN / IRIS_EMAIL_FROM |
— | Public serving domain / outbound email sender |
Security note: the internal API binds to loopback by default. If sub-agent
containers reach Iris via the Docker gateway (172.18.0.1:3000), setIRIS_API_HOST=0.0.0.0andIRIS_API_TOKEN— never expose the API beyond
loopback without a token.
Sandboxing
Iris's bash tool executes at one of four isolation levels (--sandbox):
| Mode | Flag | Use case |
|---|---|---|
| Host | --sandbox=host |
Iris herself — trusted ops, full access |
| Docker | --sandbox=docker:<name> |
Containerized sub-agents |
| Static Firecracker | --sandbox=firecracker:<ip> |
Persistent sub-agent at a fixed IP |
| Dynamic pool | --sandbox=firecracker-pool |
Fresh microVM per channel, auto-destroyed after 30 min idle |
Each microVM is defended in depth: KVM hardware boundary → minimal Firecracker VMM
→ jailer (chroot, uid 10000, seccomp) → per-VM /30 TAP network → ephemeral rootfs
destroyed with the VM.
Skills
A skill is a directory with a SKILL.md (YAML frontmatter: name, description)
plus any scripts it needs. Workspace-level skills live in <workspace>/skills/
(symlinked to this repo's skills/ for hot reload); per-channel skills in<channel>/skills/ override workspace skills on name collision. Edits apply
without a restart.
Core ships platform skills only — things Iris needs to operate, extend, and heal
herself (spawn-agent, self-heal, self-extend, get-secret, github,send-email, serve-public, schedule, status, ...). Domain and business skills belong
in your install's overlay (see below).
Sub-agents and the Internal API
Sub-agents are separate runtime instances in Docker/Firecracker, registered inagents.json and reachable through an HTTP bridge (@agentname routing). Scaffolds
live in agents/.
The runtime exposes an internal HTTP API (default 127.0.0.1:3000) for events,
escalations, and session management — create sessions, inject messages, read
history, reset context. Endpoint list in iris-runtime/src/engine/api.ts.
Secrets are agent-scoped: sub-agents resolve them via GET /secrets/:name and
must be allow-listed per secret in their agents.json entry ("secrets": [...]);
caller identity comes from the authenticating API token, not a self-reported header.
Company-Specific Extensions (Overlay)
Don't fork core — link it. Create a private repo with core as a submodule and your
own agents/skills/config as an overlay:
gh repo create iris-yourcompany --private
cd iris-yourcompany
git submodule add https://github.com/irisworks/iris-core.git core
mkdir -p overlay/{agents,skills,data}
Add a bootstrap-yourcompany.sh wrapper that sets REPO_DIR before callingcore/bootstrap.sh, then symlinks your overlay into the workspace. Pin core to a
release tag and bump deliberately (see docs/RELEASING.md).
Operating
sudo systemctl status iris # health
sudo journalctl -u iris -f # logs
sudo systemctl restart iris # restart (state is on disk; nothing is lost)
If start silently does nothing, rebuild first:cd /iris/repo/iris-runtime && npm install && npm run build
| Symptom | Likely cause | Fix |
|---|---|---|
iris.service fails to start |
Missing env vars | Check /iris/.env and journalctl -u iris |
/dev/kvm not found |
VM series without KVM | On Azure, resize to Ddsv5 (e.g. Standard_D4ds_v5) |
firecracker: permission denied |
Not in kvm group | sudo usermod -aG kvm $USER, re-login |
VM boots but /health times out |
exec-server not started | journalctl -u iris-fc-<name> |
| Jailer fails to chroot | irisjailer user missing |
sudo groupadd -g 10000 irisjailer; sudo useradd -u 10000 -g 10000 -r -s /usr/sbin/nologin irisjailer |
| rootfs missing | Build script not run | sudo bash scripts/build-firecracker-rootfs.sh |
Repository Layout
iris-core/
├── install.sh # curl-able one-command installer (clone + bootstrap)
├── bootstrap.sh # interactive install / full rebuild
├── iris-runtime/ # @iris-core/runtime — the TypeScript engine
├── skills/ # platform skills (hot-reloaded)
├── agents/ # sub-agent scaffolds
├── scripts/ # Firecracker VM lifecycle
├── data/ # CONSTITUTION.md, MEMORY.md, models.json.template — LLM provider config
├── docs/ # rendered docs site — setup, configuration, channel modes, web UI, ...
└── terraform/ # optional profile — dynamic Azure resources
Releases
Semver tags (vX.Y.Z); installs pin their core submodule to a tag. Changelog iniris-runtime/CHANGELOG.md, process indocs/RELEASING.md.
License
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found