Kai
Agentic AI assistant on Telegram, powered by Claude Code. Runs locally with shell access, spec-driven PR reviews, layered security, persistent memory, and scheduled jobs. Your machine, your data, your rules.
Install / Use
/learn @dcellison/KaiQuality Score
Category
Development & EngineeringSupported Platforms
README
Kai
Kai is an AI agent, not a chatbot. It manages persistent agent subprocesses running on your hardware - Claude Code by default, with Goose as an alternative backend - and connects them to Telegram as a control surface. Shell, filesystem, git, web search, scheduling - the agent has real access to your system and can take real action on it. It reviews PRs when code is pushed, triages issues when they're opened, monitors conditions on a schedule, and operates across any project on your machine. Multiple users can share a single Kai instance, each with their own isolated subprocess, workspace, conversation history, and optional OS-level process separation.
For detailed guides on setup, architecture, and optional features, see the Wiki.
Architecture
Kai is two layers: an outer Python application that handles Telegram, HTTP, and scheduling, and one or more inner agent subprocesses that do the thinking and acting. The outer process programs against an AgentBackend ABC (backend.py), so it manages lifecycle, authentication, and transport identically regardless of which backend is running. Claude Code is the default; Goose ACP is an alternative. Both follow the same lifecycle: one subprocess per user, lazy creation, idle eviction. Resource usage scales with active users, not registered ones.
This is what separates Kai from API-wrapper bots that send text to a model endpoint and relay the response. The inner agent is a full agentic runtime - it reads files, runs shell commands, searches the web, writes and commits code, and maintains context across a session. Claude Code and Goose each bring their own model ecosystem. Kai gives the runtime a durable home, a scheduling system, event-driven inputs, persistent memory, and a security model designed around the fact that it has all of this power.
Everything runs locally. Conversations never transit a relay server. Voice transcription and synthesis happen on-device. API keys are proxied through an internal service layer so they never appear in conversation context. There is no cloud component between you and your machine.
Security model
Giving an AI agent shell access is a real trust decision. Kai's approach is layered defense - each layer independent, so no single failure is catastrophic:
- Telegram auth - only explicitly whitelisted user IDs can interact. Unauthorized messages are silently dropped before reaching any handler.
- TOTP gate (optional) - two-factor authentication via time-based one-time passwords. After a configurable idle timeout, Kai requires a 6-digit authenticator code before processing anything. The secret lives in a root-owned file (mode 0600) that the bot process cannot read directly; it verifies codes through narrowly-scoped sudoers rules. Even if someone compromises your Telegram account, they can't use your assistant without your authenticator device. Rate limiting with disk-persisted lockout protects against brute force.
- Process isolation - authentication state lives in the bot's in-memory context, not in the filesystem or conversation history. The inner agent process cannot read, manipulate, or bypass the auth gate.
- Path confinement - file exchange operations are restricted to the active workspace via
Path.relative_to(). Traversal attempts are rejected. The send-file API also blocks access to history and memory directories. - Service proxy - external API keys live in server-side config (
services.yaml) and are injected at request time. The agent calls APIs through a local proxy endpoint; the keys never enter the conversation. Per-service SSRF controls prevent services from being used as open HTTP proxies. - Multi-user isolation - each user's data is namespaced by chat ID: separate conversation history, workspace state, scheduled jobs, and file storage. When
os_useris configured inusers.yaml, the inner agent subprocess runs as a dedicated OS account viasudo -u, creating a hard process-level boundary between users and between the bot and the AI.
Setup for TOTP requires the optional dependency group and root access:
pip install -e '.[totp]' # adds pyotp and qrcode
sudo python -m kai totp setup # generate secret, display QR code, confirm
For the full architecture, see System Architecture. For TOTP details, see TOTP Authentication.
Features
Workspaces
Switch the agent between projects on your system with /workspace <name>. Names resolve relative to WORKSPACE_BASE (set in .env). Identity and memory carry over from the home workspace, so Kai retains full context regardless of what it's working on. Create new workspaces with /workspace new <name>. Absolute paths are not accepted - all workspaces must live under the configured base directory.
Per-workspace configuration is supported via workspaces.yaml (or /etc/kai/workspaces.yaml for protected installations). Each workspace can override the model, budget, timeout, environment variables, and system prompt. See workspaces.example.yaml for the full format.
Multi-user
A single Kai instance can serve multiple Telegram users, each fully isolated. Define users in users.yaml (or /etc/kai/users.yaml for protected installations):
users:
- telegram_id: 123456789
name: alice
role: admin # receives webhook notifications (GitHub, generic)
github: alice-dev # routes GitHub events to this user
os_user: alice # subprocess runs as this OS account
home_workspace: /home/alice/workspace
max_budget: 15.0 # ceiling for /settings budget (CLAUDE_MAX_BUDGET_USD is the default)
Each user gets:
- Own agent subprocess - created lazily on first message, evicted after idle timeout (
CLAUDE_IDLE_TIMEOUT, default 30 minutes). No shared conversation state. - Isolated data - conversation history, workspace settings, scheduled jobs, and file uploads are all namespaced by user. One user cannot see or affect another's state.
- Optional OS-level separation - set
os_userto run that user's agent process as a dedicated system account viasudo -u. Requires a sudoers rule (the install script generates one automatically). - Per-user home workspace - each user can have their own default workspace directory.
- Role-based routing - admins receive unattributed webhook events (GitHub pushes, generic webhooks). Regular users interact only through Telegram messages.
Run make config to generate users.yaml, or create one manually from users.example.yaml. See the Multi-User Setup wiki page for the full field reference. When users.yaml is absent, Kai falls back to ALLOWED_USER_IDS for backward compatibility. If neither is set, Kai refuses to start (fail-closed). The CLAUDE_USER env var acts as a global fallback for subprocess isolation; per-user os_user in users.yaml takes precedence when set.
Memory
Three layers of persistent context give the agent continuity across sessions:
- Identity (
home/.claude/CLAUDE.md) - voice, rules, and operational guidelines. Lives in the home workspace. When the agent switches to a foreign workspace, Kai injects it so behavior stays consistent. In the home workspace, the agent reads it natively. - Home memory (
DATA_DIR/memory/MEMORY.md) - personal memory, always injected regardless of current workspace. Proactively updated by Kai. - Conversation history (
DATA_DIR/history/<chat_id>/) - JSONL logs, one file per day per user. Searchable for past conversations.
Workspaces can also define a system prompt via workspaces.yaml for workspace-specific instructions. See System Architecture.
Scheduled jobs
Reminders and recurring agent jobs with one-shot, daily, and interval schedules. Ask naturally ("remind me at 3pm") or use the HTTP API (POST /api/schedule). Agent jobs run as full agent sessions - Kai can check conditions, search the web, run commands, and report back on a schedule. Auto-remove jobs support monitoring use cases where the agent watches for a condition and deactivates itself when it's met. See Scheduling and Conditional Jobs.
PR Review Agent
When code is pushed to a pull request, Kai automatically reviews it. A one-shot agent subprocess analyzes the diff, checks for bugs, style issues, and spec compliance, and posts a review comment directly on the PR. If you push fixes, it reviews again - and checks its own prior comments so it doesn't nag about things you already addressed. See PR Review Agent.
Issue Triage Agent
When a new issue is opened, Kai triages it automatically. A one-shot agent subprocess reads the issue, applies labels (creating them if they don't exist), checks for duplicates and related issues, assigns it to a project board if appropriate, posts a triage summary comment, and sends you a Telegram notification. See Issue Triage Agent.
Both agents are fire-and-forget background tasks that run independently of your chat session. They use se
Related Skills
imsg
352.9kiMessage/SMS CLI for listing chats, history, and sending messages via Messages.app.
node-connect
352.9kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
oracle
352.9kBest practices for using the oracle CLI (prompt + file bundling, engines, sessions, and file attachment patterns).
lobster
352.9kLobster Lobster executes multi-step workflows with approval checkpoints. Use it when: - User wants a repeatable automation (triage, monitor, sync) - Actions need human approval before executing (s
