Iris
Integrates with Google Calendar to read and manage events, using a projection system that treats the calendar as a rendered view of the brain's planned schedule.
Enables communication with the assistant over Telegram, including sending messages and approving or denying gated actions via interactive buttons.
Integrates with Todoist to manage tasks, allowing the assistant to create, update, and move tasks as part of daily planning and execution.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@IrisWhat should I work on today?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Iris
A self-hosted personal AI assistant that runs my life over Telegram — calendar, tasks, daily planning, memory — built as a custom MCP server and hook-plugin suite on top of the open-source OpenClaw agent harness, with Claude as the intelligence.
The design bet: an assistant you trust with write access to your life cannot be a prompt. Everything that must never go wrong — action gating, priority ranking, conflict resolution, provenance, "what day is it" — is deterministic, unit-tested code. The model supplies judgment inside an envelope that code enforces.
Why it exists
Calendar, task app, and notes are three disconnected surfaces, each claiming to be the truth. Iris inverts that: a small git-backed "brain" (mission → goals → priorities) that I own is the single source of truth, and the calendar/task apps are projection surfaces rendered from it. The assistant reads all of it, ranks the day deterministically, delivers a morning digest, and acts — creating events, moving tasks, updating memory — behind approval gates that scale with blast radius.
It has been my daily driver since June 2026.
Related MCP server: mnemory
Architecture
flowchart LR
TG[Telegram]
subgraph BOX["Ubuntu box — Docker, Tailscale-only, no public ports"]
GW["OpenClaw gateway<br/>(rented: agent loop, channels, cron)"]
subgraph OWNED["Owned core — this repo"]
MCP["MCP server (src/)<br/>planner · brain · memory · taxonomy<br/>reconciliation · security envelope"]
PLUG["Hook plugins (plugins/)<br/>confirm-gate · verify-gate<br/>live-state · traits · prompt-capture"]
end
BRAIN[("Markdown brain + memory<br/>git-backed workspace")]
end
TG <--> GW
GW <-->|"tools"| MCP
GW -.->|"before_tool_call · prompt hooks"| PLUG
MCP <--> BRAIN
GW <--> GCAL["Google Calendar MCP<br/>(rented, OAuth scope-narrowed)"]
GW <--> TODO["Todoist MCP<br/>(rented, tool-allowlisted)"]
GW <--> ANTH["Anthropic API<br/>Haiku default (live) · /model escalation"]Own the brain, rent the surfaces. The repo builds only the differentiator — planning, memory, authority, safety. The agent loop is rented (OpenClaw), the calendar and task surfaces are rented MCP servers pinned and narrowed to least privilege (OAuth scope patch on the calendar server; tool allowlists on both). The security envelope wraps the rented servers too.
Component map
Path | Responsibility |
|
|
| Authority engine: a brain-vs-live conflict is decided by the slot's type-authority prior (state→live surface, intent→brain), downgrading to flag-and-ask when the prior's loser is fresher; same-side conflicts use a recency → provenance → ask ladder. No model on the path |
| Action classifier: every tool call maps to |
| Quarantine (untrusted-content sanitize + envelope), provenance tagging, Rule-of-Two invariant, web egress gate |
| Git-backed Markdown SSOT: read tools + gated write tools ( |
| Owner-tuneable personality dials (humor, verbosity, bluntness…) with a non-tuneable safety/honesty floor |
| Verify-before-act helpers; calendar-as-projection write path (tagged, idempotent by record id) |
|
|
| Hard-blocks destructive calendar and Todoist writes whose target wasn't read in the same turn |
| Injects fresh calendar/task state + an authoritative local |
| Persona rendering into the system prompt; wire-level capture feeding the eval harness |
| Offline model-eval harness: wire-exact corpus, replay across providers, deterministic scorers, cross-family LLM judge |
| Hardened gateway config, compose, vendored patches (pinned + hash-checked) |
| The development process: one research-gated PR file per change, architecture SSOT, design logs with the full decision trail |
The gated write path
flowchart TD
A["Proposed tool call"] --> V{"verify-gate:<br/>destructive write —<br/>target read this turn?"}
V -- "no" --> B["Blocked → model told to read first"]
V -- "yes / not destructive" --> T["taxonomy classifier<br/>(deterministic, unit-tested)"]
T --> C{"action class"}
C -- "autonomous /<br/>auto+notify" --> X["Execute"]
C -- "confirm-first /<br/>quarantine+confirm" --> P["Telegram approval — /approve command<br/>fail-closed, 300s timeout → deny"]
P -- "approve" --> X
P -- "deny / timeout" --> D["Denied"]Governing invariant (Rule of Two): no single operation may combine reads untrusted content + accesses sensitive data + changes external state without a mandatory human gate. In practice it's enforced as a system rather than one choke-point function: session taint escalates every same-turn write after untrusted input, and the sensitive store is read through its own gated tool. Confirm-gate additionally runs a web-egress gate — a web_fetch to a domain this turn's searches never surfaced is confirm-first (kills the classic exfil-by-URL channel). Prompt injection is unsolved; the dangerous combination stays permanently gated no matter how good the model is.
Key design decisions
Each of these had a live alternative that was researched and rejected — the full trail is in docs/*/DESIGN-log.md and the prs/ files.
Deterministic gates, not prompt-based safety. System-prompt instructions like "verify before acting" were live-tested and proven insufficient — the assistant still moved real calendar events off a wrong-day inference. The fix each time was a code-level hook (
verify-gate,confirm-gate) that makes the failure structurally impossible rather than discouraged. Rejected: relying on model compliance.Logic in code wherever judgment isn't required. Ranking, conflict authority, action classification, and time grounding are pure functions with unit tests. Deterministic code beats model judgment over long context, and the system stays correct even with extended thinking off. The model handles what only a model can: natural-language policy, tie-breaks, conversation. Rejected: letting the LLM rank the day and arbitrate stale-vs-fresh conflicts.
Quarantine untrusted content at persistence time. Calendar invite notes and fetched web content are Unicode-stripped, wrapped in an explicit "data, not instructions" envelope, and provenance-tagged
untrusted-derivedbefore the planner ever sees them — a synchronous rewrite hook, not an async model pass — and the turn is tainted so same-turn writes escalate to gated approval. Nothing untrusted is ever durably written unguarded (anti-memory-poisoning; injection canaries live-verified quarantined). PDF attachments take a separate path: the runtime's bundled extractor inlines them inside OpenClaw's native untrusted-content framing (canary-verified live), not the owned pipeline. Rejected: dual-LLM token isolation — the runtime's persist hook is synchronous, so it's deferred, not dismissed.Model selection by measurement, not vibes.
scripts/eval/replays the assistant's own captured traffic offline against candidate models with deterministic scorers and a cross-family judge. The capture path is wire-exact (billed request body reproduced to ±0 tokens) after the naive approach — replaying reconstructed trajectories — was tested and refuted (−18.8% token fidelity). The harness's verdict set the current default (Haiku, −67% cost/turn at parity for routine traffic, with per-conversation escalation to Sonnet/Opus). It also halted a shipped decision: per-turn cross-provider routing was reverted when the live trial showed a stateful turn ships its whole session history to whichever provider serves it — the privacy carve-out unit is the session, not the turn. Rejected: benchmark-driven model choice, and the cross-provider router it initially justified.Time is an injected fact. A real incident (assistant asserted the wrong weekday, concluded the calendar UI was buggy, and moved real events) traced to a context where every ambient timestamp was UTC and no authoritative local "now" existed. The fix: a hook injects
Now: <local datetime> — AUTHORITATIVEplus weekday annotations on every date, each turn, cache-neutrally. The incident class is closed structurally. Rejected: prompt rules telling the model to be careful about timezones.
Testing
294 tests across 22 files (vitest), verified passing from a clean clone. Coverage follows the "logic in code" rule — the deterministic pieces are the tested pieces:
ranking math, taxonomy classification, reconciliation authority, provenance parse/render, quarantine sanitization, egress-gate policy, eval-harness scorers/corpus logic
adversarial fixtures: prompt-injection and memory-poisoning payloads assert the gates fire and nothing durable is written from untrusted content
beyond unit tests, every PR in
prs/records its live binding test — the deployed behavior verified over Telegram against the real gateway before the PR closes
npm ci
npm test # 294 tests
npm run typecheck
npm run build # server bundle; build:plugin:* for each pluginRunning it
This is a personal, single-user system — the repo is published as a working reference, not a turnkey product. A full deployment needs an OpenClaw gateway (Docker), a Telegram bot, Google Calendar OAuth, a Todoist token, and an Anthropic API key; deploy/ contains the hardened gateway config, compose file, vendored patches, and a README with the wiring. One drift note: the committed gateway config predates the Haiku-default model switch (PR-033, applied on the live box) — it still pins Sonnet as primary. Expect to adapt paths and secrets handling to your own box.
Status — honest scope
In daily use since June 2026; v0.2.x. The commit history is the real changelog — each change is a research-gated PR with verification criteria.
The agent loop, channels, and cron are OpenClaw (third-party). This repo is the MCP server, plugins, eval harness, and deployment hardening on top.
Proactivity is deliberately minimal (one daily digest); the interrupt engine is designed but deferred.
Scanned/image-only PDFs don't reach the turn (documented gap); finance integration is designed for a sidecar-isolation pattern but not built.
Two vendored runtime patches (thinking-block handling, wire capture) are pinned to the current OpenClaw release and retire when upstream ships equivalents.
License
MIT
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- FlicenseAqualityAmaintenanceBridges AI assistants to a Telegram bot to enable two-way messaging, interactive confirmations, and live status updates. It supports automatic voice transcription via local Whisper models and provides secure, single-user communication for MCP-compatible hosts.46
- Alicense-qualityBmaintenanceSelf-hosted MCP server giving AI agents persistent memory for personalization and context across conversations.230Apache 2.0
- Alicense-qualityCmaintenanceA personal AI assistant server that provides MCP tools for notes, files, reminders, memory, shell, browser, and 30+ SaaS integrations, enabling AI clients to access and manage your data across sessions.3,939MIT
- Alicense-qualityAmaintenanceMCP server with persistent memory, voice understanding, multi-thread orchestration, and remote control via Telegram for AI assistants.2,2995MIT
Related MCP Connectors
Person-owned, portable AI memory as a remote MCP server, readable and writable by any MCP client.
Personal assistant MCP server with search, execute, packages, jobs, secrets, and integrations.
User-owned memory for AI agents, Copilot, Claude, IDEs, CLIs, and chat apps over remote MCP.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/rux-eth/iris'
If you have feedback or need assistance with the MCP directory API, please join our Discord server