This is the public Homebrew tap and APT mirror for the kavilo-bot projects. Three products are published here:
| Product | What it is | brew | apt |
|---|---|---|---|
kavilo |
A lightweight personal AI assistant — single binary, zero dependencies. | brew install kavilo-bot/tap/kavilo |
sudo apt install kavilo |
kavilo-tunnel |
A cloudflared-style HTTP tunneling client. Exposes a local service via a public URL through a hosted edge. | brew install kavilo-bot/tap/kavilo-tunnel |
sudo apt install kavilo-tunnel |
kavilo-hive |
End-user CLI for an actor-based messaging hub with Signal-protocol E2E encryption. Paired with the kavilo-hived server (Docker image + tarballs in the same releases). |
brew install kavilo-bot/tap/kavilo-hive |
sudo apt install kavilo-hive |
All three products’ binaries, Homebrew formulas, and .deb packages are
hosted in this repo. Client installs from this tap continue to work even
when the upstream source repositories
(kavilo-bot/kavilo,
kavilo-bot/kavilo-tunnel,
kavilo-bot/kavilo-hive)
go private — everything end-users need is mirrored here under
Releases and the
GitHub Pages-served APT repo.
Most of this README is the long-form guide for kavilo (the AI
assistant). For kavilo-tunnel, jump to
the section near the end or read the full
user guide. For kavilo-hive,
the client and operator guides live under
docs/kavilo-hive/ — see
user-guide.md for end users and
operator-guide.md for running
the server.
A lightweight personal AI assistant — single binary, zero dependencies.
brew install kavilo-bot/tap/kavilo
That single command:
kavilo-bot/homebrew-tapdarwin_arm64, darwin_amd64,
linux_arm64, or linux_amd64) from this repo’s latest releasekavilo to $(brew --prefix)/bin/kavilobrew services definition you can use to keep it running
in the backgroundEach release ships unversioned aliases so the URLs are stable across versions:
# macOS (Apple Silicon)
curl -LO https://github.com/kavilo-bot/homebrew-tap/releases/latest/download/kavilo_darwin_arm64.zip
unzip kavilo_darwin_arm64.zip && sudo mv kavilo /usr/local/bin/
# macOS (Intel)
curl -LO https://github.com/kavilo-bot/homebrew-tap/releases/latest/download/kavilo_darwin_amd64.zip
unzip kavilo_darwin_amd64.zip && sudo mv kavilo /usr/local/bin/
# Linux (x86_64)
curl -LO https://github.com/kavilo-bot/homebrew-tap/releases/latest/download/kavilo_linux_amd64.tar.gz
tar xzf kavilo_linux_amd64.tar.gz && sudo mv kavilo /usr/local/bin/
# Linux (arm64)
curl -LO https://github.com/kavilo-bot/homebrew-tap/releases/latest/download/kavilo_linux_arm64.tar.gz
tar xzf kavilo_linux_arm64.tar.gz && sudo mv kavilo /usr/local/bin/
# Windows
curl -LO https://github.com/kavilo-bot/homebrew-tap/releases/latest/download/kavilo_windows_amd64.zip
Darwin archives are currently unsigned. macOS Gatekeeper will not block binaries that arrived via
brew install,curl, orgit, but will warn if you download the.zipfrom a browser. See Troubleshooting.
kavilo --version
# → 🤖 kavilo v2.0.0-alpha.2
kavilo --help
# 1. Initialize ~/.kavilo/ (config, workspace, default skills, templates)
kavilo onboard
# 2. Add a provider API key — open ~/.kavilo/config.json and edit
# "providers.<name>.apiKey". Common providers:
#
# openrouter https://openrouter.ai/keys
# anthropic https://console.anthropic.com/settings/keys
# openai https://platform.openai.com/api-keys
# deepseek https://platform.deepseek.com/api_keys
# groq https://console.groq.com/keys
# gemini https://aistudio.google.com/apikey
# 3. Talk to the assistant interactively
kavilo agent
# 4. Or one-shot
kavilo agent -m "What is the capital of France?"
# 5. Or run the long-lived service (chat channels, cron, heartbeat)
kavilo start
Out of the box kavilo ships with a sensible default model
(anthropic/claude-opus-4-5 via OpenRouter). Override per call with
KAVILO_MODEL=... or persistently in config.json under
agents.defaults.model.
Homebrew installs a launchd / systemd service definition so you can keep the runtime alive without a terminal session:
# Start now and on every login
brew services start kavilo
# Check status
brew services list | grep kavilo
# Tail the logs (default Homebrew paths)
tail -f $(brew --prefix)/var/log/kavilo.log
tail -f $(brew --prefix)/var/log/kavilo.err.log
# Stop
brew services stop kavilo
# Restart after editing ~/.kavilo/config.json
brew services restart kavilo
The service runs kavilo start, which spins up:
enabled: true in config.json~/.kavilo/cron/jobs.jsonworkspace/HEARTBEAT.mdIf you’d rather run it ad-hoc, just run kavilo start in a terminal (or
inside tmux so it survives a disconnect).
All state lives under ~/.kavilo/:
~/.kavilo/
├── config.json ← settings, credentials, channels, MCP
├── workspace/ ← prompt files, skills, memory, sessions
│ ├── AGENTS.md ← system prompt
│ ├── MEMORY.md ← long-term memory
│ ├── HEARTBEAT.md ← periodic tasks
│ └── skills/
├── mcp-auth/slack/ ← Slack MCP OAuth tokens (per alias)
├── cron/jobs.json ← scheduled jobs
├── media/ ← uploaded media cache
├── usage/ ← token-usage rollups
├── logs/ ← runtime logs
└── profiles/<name>/ ← isolated alternate homes (see Profiles)
config.json{
"agents": {
"defaults": {
"model": "anthropic/claude-opus-4-5",
"provider": "auto",
"maxTokens": 8192,
"workspace": "~/.kavilo/workspace"
}
},
"providers": {
"openrouter": { "apiKey": "sk-or-..." },
"anthropic": { "apiKey": "sk-ant-..." },
"openai": { "apiKey": "sk-..." }
},
"runtime": {
"heartbeat": { "enabled": true, "intervalS": 1800 }
}
}
provider: "auto" picks the first provider with a configured key at
request time. To pin a single provider, set agents.defaults.provider
to one of: openai, anthropic, openrouter, deepseek, groq,
gemini, dashscope, moonshot, minimax, ollama, vllm,
zhipu, etc.
These shell-env vars override anything in config.json (process-wide,
not per-profile):
| Variable | Effect |
|---|---|
KAVILO_MODEL |
Override agents.defaults.model |
KAVILO_PROVIDER |
Override agents.defaults.provider |
KAVILO_API_KEY |
Override the resolved provider’s API key |
KAVILO_API_BASE |
Override the resolved provider’s base URL |
KAVILO_WORKSPACE |
Override agents.defaults.workspace |
KAVILO_HOME |
Use a different ~/.kavilo root |
ANTHROPIC_API_KEY etc. |
Pick up provider keys from the OS env |
kavilo start connects to every enabled channel. Each lives under
channels.<name> in config.json and has an enabled flag plus a
per-platform allow-list.
"channels": {
"slack": {
"enabled": true,
"mode": "socket",
"botToken": "xoxb-...",
"appToken": "xapp-...",
"groupPolicy": "mention",
"allowFrom": ["U0123ABC"]
}
}
DMs and @bot mentions become inbound prompts; replies post back into the
same thread. Socket Mode means no port forwarding required.
"channels": {
"telegram": {
"enabled": true,
"token": "12345:ABC...",
"allowFrom": ["123456789"],
"groupPolicy": "mention"
}
}
"channels": {
"discord": {
"enabled": true,
"token": "...",
"allowFrom": ["705222568751267870"],
"intents": 4609,
"groupPolicy": "mention"
}
}
Other supported channels (all opt-in via enabled: true in
config.json): dingtalk, email, feishu, mochat, nanorelay,
qq, wecom, whatsapp.
groupPolicy accepts mention (default — only respond when @-mentioned
in groups) or all. allowFrom is a per-platform allow-list of user IDs
or ["*"] to allow everyone.
kavilo mcp serve <name> runs a built-in MCP server over stdio. Two
servers ship out of the box:
self — exposes sessions, config, channels, MCP servers, cron
jobs, and token usage. Sensitive fields (auth tokens, webhook secrets,
API keys) are sanitized.slack — exposes search, post, history, users, and search-context
tools against the workspace whose alias is configured.Cursor / Claude Desktop entry:
{
"mcpServers": {
"kavilo-self": {
"command": "kavilo",
"args": ["mcp", "serve", "self"]
}
}
}
Add entries under tools.mcpServers in config.json:
"tools": {
"mcpServers": {
"context7": {
"command": "npx",
"args": ["-y", "@upstash/context7-mcp", "--transport", "stdio"],
"env": { "CONTEXT7_API_KEY": "ctx7sk-..." },
"toolTimeout": 30,
"enabledTools": ["resolve-library-id", "query-docs"]
},
"my-http-server": {
"type": "http",
"url": "https://example.com/mcp",
"headers": { "Authorization": "Bearer ..." }
}
}
}
stdio and streamable-http transports are both supported.
# Production (built-in client ID + hosted OAuth callback)
kavilo mcp slack login workspace-alias --team YOUR_TEAM_ID
# Development (your own dev Slack app, loopback callback)
kavilo mcp slack login dev \
--client-id YOUR_DEV_CLIENT_ID \
--client-secret YOUR_DEV_CLIENT_SECRET \
--redirect-uri http://127.0.0.1:7898/oauth/callback
kavilo mcp slack status # all aliases
kavilo mcp slack status workspace-alias # one alias
kavilo mcp slack logout workspace-alias # revoke + delete
Tokens live under ~/.kavilo/mcp-auth/slack/<alias>.json and are
injected only at runtime — never written to config.json.
Each profile is an isolated KAVILO_HOME directory with its own config,
sessions, MCP auth, cron jobs, and workspace.
kavilo profile use work # sticky switch
kavilo profile show # active profile + path
kavilo profile list # all profiles
kavilo profile rm scratch # delete (asks for confirmation)
# One-shot per-invocation override
kavilo --profile work agent
KAVILO_HOME=/path/to/home kavilo agent
Resolution order, evaluated once at process start:
KAVILO_HOME env (set explicitly or by --profile)~/.kavilo/active_profile~/.kavilo/<KAVILO_HOME>/): config.json, the workspace
(sessions, AGENTS.md, skills, memory), Slack MCP tokens,
cron/jobs.json, media/, usage/, logs/, CLI history.ANTHROPIC_API_KEY,
OPENAI_API_KEY, etc.), KAVILO_* overlays, the sticky profile file,
the Slack OAuth loopback port (127.0.0.1:7898).| Command | Description |
|---|---|
kavilo onboard |
Initialize ~/.kavilo/ |
kavilo agent |
Interactive REPL with the agent |
kavilo agent -m "msg" |
One-shot prompt |
kavilo start |
Start enabled channels + cron + heartbeat |
kavilo status |
Show config / data / workspace / daemon status |
kavilo version |
Print version |
kavilo profile {use,show,list,rm} |
Manage isolated ~/.kavilo/profiles/<name>/ homes |
kavilo mcp serve <self\|slack> |
Run a built-in MCP server over stdio |
kavilo mcp slack {login,status,logout} |
Manage Slack MCP OAuth aliases |
All commands accept --profile/-p <name> to pin KAVILO_HOME for that
invocation.
brew update
brew upgrade kavilo
brew services restart kavilo # only if you run it as a service
brew services stop kavilo
brew uninstall kavilo
brew untap kavilo-bot/tap
# Optional: remove your data
rm -rf ~/.kavilo
kavilo: command not foundCheck your PATH includes the Homebrew bin directory:
echo $PATH | tr ':' '\n' | grep -E '^/(opt/homebrew|usr/local)/bin$'
which kavilo
If which kavilo returns a stale path (e.g. an old ~/.cargo/bin/kavilo),
either remove that copy or reorder your PATH so Homebrew comes first.
kavilo status shows daemon: stopped but you ran kavilo startThe runtime writes a PID file at ~/.kavilo/gateway.pid only on kavilo
start. If you started it inside another process manager (or it was
killed by SIGHUP when a terminal closed), the file may be missing. Use:
brew services list | grep kavilo
ps -ef | grep '[k]avilo start'
For a persistent foreground run, prefer:
brew services start kavilo # recommended
# or
nohup kavilo start >> ~/.kavilo/logs/run.log 2>&1 &
Darwin binaries in this tap are currently unsigned. Gatekeeper only
quarantines binaries that arrived with the
com.apple.quarantine extended attribute — typically because you
double-clicked a .zip from your browser. brew install, curl, and
git do not set that attribute, so binaries installed through them
run cleanly.
If you do hit the warning, clear it with:
xattr -dr com.apple.quarantine $(brew --prefix)/bin/kavilo
401 Unauthorized / invalid api keyCheck ~/.kavilo/config.json → providers.<name>.apiKey, and make sure
no shell env var (OPENAI_API_KEY, KAVILO_API_KEY, etc.) is overriding
it with a stale value:
env | grep -E '(KAVILO|API_KEY)'
| Source | Where |
|---|---|
kavilo start (via brew services) |
$(brew --prefix)/var/log/kavilo.{log,err.log} |
kavilo start (foreground) |
~/.kavilo/logs/kavilo-<timestamp>.log |
| Per-session token usage | ~/.kavilo/usage/ |
tools.restrictToWorkspace (default true) is a correctness
boundary, not an adversarial one. It prevents read_file /
write_file / list_directory / glob_files from touching paths
outside the workspace, but the shell tool still runs sh -c with
full host access.kavilo itself inside a container, VM,
or seccomp jail.tools.exec.scrubEnv = true (off by default) drops *_API_KEY,
*_API_TOKEN, *_SECRET, and KAVILO_* from the shell tool’s
child env so the agent cannot exfiltrate provider credentials via
printenv.config.json under
~/.kavilo/mcp-auth/slack/ so backups of the config don’t leak them.kavilo-tunnel is the second product in this tap. It’s an entirely separate
binary from kavilo and serves a different purpose: expose a local HTTP
service on the public internet via a kavilo-tunnel server (cloudflared/ngrok
style).
brew install kavilo-bot/tap/kavilo-tunnel
The macOS arm64 binary is codesigned and Apple-notarized, so there’s no Gatekeeper warning on first run.
sudo install -d /etc/apt/keyrings
curl -fsSL https://kavilo-bot.github.io/homebrew-tap/apt/keyring.asc \
| sudo gpg --dearmor -o /etc/apt/keyrings/kavilo.gpg
echo "deb [signed-by=/etc/apt/keyrings/kavilo.gpg] https://kavilo-bot.github.io/homebrew-tap/apt stable main" \
| sudo tee /etc/apt/sources.list.d/kavilo.list
sudo apt update
sudo apt install kavilo-tunnel
The same apt repo serves kavilo and kavilo-tunnel; adding the source
once gives you both.
Versioned assets attached to the kavilo-tunnel-vX.Y.Z tag in the
Releases page of
this repo. The .deb is also reachable directly from the apt pool:
https://kavilo-bot.github.io/homebrew-tap/apt/pool/main/k/kavilo-tunnel/.
# 1. Get a token from your kavilo-tunnel operator and log in
kavilo-tunnel login \
--token <your-token> \
--endpoint https://<your-base-host>:7777
# 2. Run some local service
python3 -m http.server 3000 &
# 3. Open a named tunnel (stable URL across reconnects)
kavilo-tunnel tunnel --url http://127.0.0.1:3000 --name myapp
# → public URL: https://myapp-<your-slug>.<your-base-host>/
See the full user guide in the source repo for:
--takeoverFor operators wanting to run the server side (kavilo-tunneld) or
contribute, see the
kavilo-bot/kavilo-tunnel repo.
kavilo-hive is the end-user CLI for an actor-based messaging hub with
Signal-protocol end-to-end encryption. You connect to a kavilo-hived
server your operator runs and exchange encrypted messages with other
actors (people, bots) or fan-out groups over a persistent WSS
connection. The server never sees plaintext — every relayed envelope
carries opaque libsignal ciphertext.
This tap ships both halves of the system:
kavilo-hive — the Rust client CLI (this Homebrew formula / apt
package).kavilo-hived — the Go server binary, distributed as
ghcr.io/kavilo-bot/kavilo-hived:<v> (cosign-keyless signed +
SPDX SBOM attestation) and as kavilo-hived_<v>_<os>_<arch>.tar.gz
on each release.brew install kavilo-bot/tap/kavilo-hive
The macOS arm64 binary is codesigned and Apple-notarized, so there’s no Gatekeeper warning on first run.
sudo install -d /etc/apt/keyrings
curl -fsSL https://kavilo-bot.github.io/homebrew-tap/apt/keyring.asc \
| sudo gpg --dearmor -o /etc/apt/keyrings/kavilo.gpg
echo "deb [signed-by=/etc/apt/keyrings/kavilo.gpg] https://kavilo-bot.github.io/homebrew-tap/apt stable main" \
| sudo tee /etc/apt/sources.list.d/kavilo.list
sudo apt update
sudo apt install kavilo-hive
The same apt repo serves kavilo, kavilo-tunnel, and kavilo-hive;
adding the source once gives you all three.
Versioned assets attached to the kavilo-hive-vX.Y.Z tag in the
Releases page of
this repo. The .deb is also reachable directly from the apt pool:
https://kavilo-bot.github.io/homebrew-tap/apt/pool/main/k/kavilo-hive/.
Pull the multi-arch image:
docker pull ghcr.io/kavilo-bot/kavilo-hived:0.1.2
Verify the cosign signature before deploying:
cosign verify \
--certificate-identity-regexp '^https://github.com/kavilo-bot/homebrew-tap/.github/workflows/build-kavilo-hive-release.yml@.*$' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
ghcr.io/kavilo-bot/kavilo-hived:0.1.2
The image ships both /app/kavilo-hived and /app/kavilo-cert-tool
(sealed-sender certificate minter), with /app on $PATH.
# 1. Operator runs the server, creates a hive + bootstrap code for you
# (see operator guide).
#
# 2. You initialize a local profile against the server URL.
kavilo-hive config init \
--server-url https://hive.example.com:8443/h/team-alpha \
--ca-file ~/Downloads/kavilo-hive-ca.crt \
--name personal \
--actor-id alice \
--actor-role user
# 3. Redeem the bootstrap code (one-shot, short-lived).
kavilo-hive claim --code 123456
# 4. Sanity check.
kavilo-hive health
kavilo-hive whoami
# 5. Send a one-shot message.
kavilo-hive send --to bob --body "ping"
# 6. Or drop into the interactive shell.
kavilo-hive shell
For source, protocol design, and threat model, see the
kavilo-bot/kavilo-hive repo
— in particular
docs/adr/0001-signal-level-e2e.md
(end-to-end encryption design) and
docs/adr/0002-multi-server-federation.md
(federation between independent hubs).
MIT — see LICENSE.