alvin-bot 4.5.1 → 4.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/CHANGELOG.md +278 -0
  2. package/README.md +25 -2
  3. package/bin/cli.js +325 -26
  4. package/dist/handlers/commands.js +505 -63
  5. package/dist/handlers/message.js +209 -14
  6. package/dist/i18n.js +470 -13
  7. package/dist/index.js +45 -5
  8. package/dist/providers/claude-sdk-provider.js +106 -14
  9. package/dist/providers/ollama-provider.js +32 -0
  10. package/dist/providers/openai-compatible.js +10 -1
  11. package/dist/providers/registry.js +112 -17
  12. package/dist/providers/types.js +25 -3
  13. package/dist/services/compaction.js +2 -0
  14. package/dist/services/cron.js +53 -42
  15. package/dist/services/heartbeat.js +41 -7
  16. package/dist/services/language-detect.js +12 -2
  17. package/dist/services/ollama-manager.js +339 -0
  18. package/dist/services/personality.js +20 -14
  19. package/dist/services/session.js +21 -3
  20. package/dist/services/subagent-delivery.js +266 -0
  21. package/dist/services/subagent-stats.js +123 -0
  22. package/dist/services/subagents.js +509 -42
  23. package/dist/services/telegram.js +28 -1
  24. package/dist/services/updater.js +158 -0
  25. package/dist/services/usage-tracker.js +11 -4
  26. package/dist/services/users.js +2 -1
  27. package/docs/HANDBOOK.md +856 -0
  28. package/package.json +7 -2
  29. package/test/claude-sdk-provider.test.ts +69 -0
  30. package/test/i18n.test.ts +108 -0
  31. package/test/registry.test.ts +201 -0
  32. package/test/subagent-delivery.test.ts +273 -0
  33. package/test/subagent-stats.test.ts +119 -0
  34. package/test/subagents-commands.test.ts +64 -0
  35. package/test/subagents-config.test.ts +114 -0
  36. package/test/subagents-depth.test.ts +58 -0
  37. package/test/subagents-inheritance.test.ts +67 -0
  38. package/test/subagents-name-resolver.test.ts +122 -0
  39. package/test/subagents-priority-reject.test.ts +88 -0
  40. package/test/subagents-queue.test.ts +127 -0
  41. package/test/subagents-shutdown.test.ts +126 -0
  42. package/test/subagents-toolset.test.ts +51 -0
  43. package/vitest.config.ts +17 -0
@@ -0,0 +1,856 @@
1
+ # Alvin Bot Handbook
2
+
3
+ > A complete, standalone reference for everything Alvin Bot can do — installation, architecture, providers, sub-agents, cron jobs, plugins, MCP, platforms, security, and troubleshooting. Written for users who want to understand the whole system, not just the quick-start.
4
+
5
+ ---
6
+
7
+ ## Table of contents
8
+
9
+ 1. [What Alvin Bot is](#1-what-alvin-bot-is)
10
+ 2. [Installation](#2-installation)
11
+ 3. [First run: the setup wizard](#3-first-run-the-setup-wizard)
12
+ 4. [Architecture at a glance](#4-architecture-at-a-glance)
13
+ 5. [AI providers](#5-ai-providers)
14
+ 6. [The chat session model](#6-the-chat-session-model)
15
+ 7. [Sub-agents](#7-sub-agents)
16
+ 8. [Cron jobs](#8-cron-jobs)
17
+ 9. [Commands reference](#9-commands-reference)
18
+ 10. [Platforms: Telegram, WhatsApp, Discord, Signal, Web, TUI](#10-platforms)
19
+ 11. [Plugins and MCP servers](#11-plugins-and-mcp-servers)
20
+ 12. [Skills](#12-skills)
21
+ 13. [Security](#13-security)
22
+ 14. [Running in production](#14-running-in-production)
23
+ 15. [Troubleshooting](#15-troubleshooting)
24
+ 16. [Upgrading](#16-upgrading)
25
+
26
+ ---
27
+
28
+ ## 1. What Alvin Bot is
29
+
30
+ Alvin Bot is a self-hosted AI agent that lives where you chat. Instead of being a single-purpose chatbot, it connects a multi-model engine (Claude, OpenAI, Gemini, Groq, NVIDIA NIM, Ollama, OpenRouter, or any OpenAI-compatible endpoint) to every messaging platform you care about (Telegram, WhatsApp, Discord, Signal, Web UI, terminal), plus a set of superpowers: persistent memory, cron jobs, file access, skill files, MCP tool use, sub-agents for parallel work, and a comprehensive security audit.
31
+
32
+ The design goal is **"the assistant that actually lives on your machine"**: it has real tool access (not a sandboxed chat), it remembers across sessions, it runs scheduled tasks, and you talk to it through whatever app you already have open.
33
+
34
+ **Alvin Bot is the bot process.** Your identity — what it calls you, your preferences, long-running context — lives in `~/.alvin-bot/memory/` and is independent of the bot version.
35
+
36
+ ---
37
+
38
+ ## 2. Installation
39
+
40
+ ### 2.1 Quickest path — npm
41
+
42
+ ```bash
43
+ npm install -g alvin-bot
44
+ alvin-bot setup
45
+ alvin-bot start
46
+ ```
47
+
48
+ Requirements:
49
+ - Node.js 18 or newer
50
+ - A Telegram bot token (free from [@BotFather](https://t.me/BotFather))
51
+ - Your Telegram user ID (from [@userinfobot](https://t.me/userinfobot))
52
+
53
+ Everything else — an AI provider key — the setup wizard walks you through.
54
+
55
+ ### 2.2 From source
56
+
57
+ ```bash
58
+ git clone https://github.com/alvbln/Alvin-Bot.git
59
+ cd Alvin-Bot
60
+ npm install
61
+ npm run build
62
+ node bin/cli.js setup
63
+ node bin/cli.js start
64
+ ```
65
+
66
+ This is the path if you want to track `main` or apply local patches.
67
+
68
+ ### 2.3 One-line install script
69
+
70
+ ```bash
71
+ curl -fsSL https://raw.githubusercontent.com/alvbln/Alvin-Bot/main/install.sh | bash
72
+ ```
73
+
74
+ Downloads, builds, and runs the setup wizard in one shot. Linux and macOS only.
75
+
76
+ ### 2.4 Desktop app (macOS)
77
+
78
+ Download the latest `.dmg` from [GitHub Releases](https://github.com/alvbln/Alvin-Bot/releases). The desktop app wraps the bot in an Electron shell with a system tray icon, auto-updater, and the embedded web UI.
79
+
80
+ Current build: Apple Silicon (arm64). Windows and Linux desktop builds are on the roadmap.
81
+
82
+ ### 2.5 Docker
83
+
84
+ ```bash
85
+ docker compose up -d
86
+ ```
87
+
88
+ Use this for headless servers. See `docker-compose.yml` for the expected environment variables.
89
+
90
+ ### 2.6 The data directory
91
+
92
+ Alvin Bot stores all user data under `~/.alvin-bot/` (overridable via the `ALVIN_DATA_DIR` environment variable):
93
+
94
+ ```
95
+ ~/.alvin-bot/
96
+ ├── .env # bot token, API keys, config
97
+ ├── memory/ # long-term memory (vector-indexed)
98
+ ├── sessions/ # session transcripts
99
+ ├── cron-jobs.json # scheduled jobs
100
+ ├── sub-agents.json # sub-agent config (maxParallel, visibility)
101
+ ├── delivery-queue.json # pending outgoing messages with retry
102
+ ├── logs/ # stdout/stderr if running under launchd
103
+ ├── custom-models.json # user-added OpenAI-compatible providers
104
+ ├── users/ # multi-user approval + preferences
105
+ └── whatsapp-groups.json # WhatsApp group allowlist
106
+ ```
107
+
108
+ The bot code itself lives wherever you installed it (`/usr/local/lib/node_modules/alvin-bot` for npm-global, or your git clone directory). The data directory is portable: copy it between machines and the bot comes up with the same memories, jobs, and settings.
109
+
110
+ ---
111
+
112
+ ## 3. First run: the setup wizard
113
+
114
+ Running `alvin-bot setup` walks you through four screens:
115
+
116
+ 1. **AI provider** — pick one of the supported providers. Free options first (Groq, Gemini, NVIDIA NIM, Ollama, Claude Max via the CLI). The wizard validates the API key with a test call before saving.
117
+ 2. **Telegram bot token** — paste the token from BotFather. The wizard calls `getMe` to confirm it's valid and shows you the bot's handle.
118
+ 3. **Authorized user ID** — paste your Telegram user ID. Only users listed in `ALLOWED_USERS` can chat with the bot; everyone else gets a silent deny.
119
+ 4. **Optional platforms** — Slack, WhatsApp, Discord, Signal. Each is configured independently; skip any you don't use.
120
+
121
+ All values land in `~/.alvin-bot/.env` so you can edit them later.
122
+
123
+ ---
124
+
125
+ ## 4. Architecture at a glance
126
+
127
+ ```
128
+ ┌─────────────────────────────────────────────────────────────┐
129
+ │ Platform layer │
130
+ │ Telegram · WhatsApp · Discord · Signal · Slack · TUI · Web │
131
+ └──────────────────────────┬──────────────────────────────────┘
132
+
133
+ platform-message
134
+
135
+ ┌──────────────────────────▼──────────────────────────────────┐
136
+ │ Handler layer │
137
+ │ handleMessage · handleVoice · handlePhoto · handleDocument │
138
+ └──────────────────────────┬──────────────────────────────────┘
139
+
140
+ Engine.query()
141
+
142
+ ┌──────────────────────────▼──────────────────────────────────┐
143
+ │ Provider registry │
144
+ │ Claude SDK · OpenAI-compat · Codex CLI · Ollama · custom... │
145
+ │ Heartbeat monitor · fallback chain · retry on transient │
146
+ └──────────────────────────┬──────────────────────────────────┘
147
+
148
+ ┌──────────────────────────▼──────────────────────────────────┐
149
+ │ Services │
150
+ │ Memory · Sub-agents · Cron · Skills · MCP · Plugins · Queue │
151
+ └─────────────────────────────────────────────────────────────┘
152
+ ```
153
+
154
+ Everything is wired together in `src/index.ts`. The process boots by:
155
+
156
+ 1. Creating `~/.alvin-bot/` and migrating any legacy data
157
+ 2. Validating the `.env` against the chosen provider
158
+ 3. Initializing the provider registry
159
+ 4. Loading plugins and MCP servers
160
+ 5. Creating the grammy bot instance and attaching the sub-agent delivery router
161
+ 6. Starting the web server, cron scheduler, delivery queue, and heartbeat
162
+ 7. Starting optional platform adapters
163
+ 8. Beginning Telegram polling
164
+
165
+ A `shutdown()` function in the same file runs in reverse: cancel all running sub-agents (with Telegram notifications), stop the scheduler, drain the delivery queue, unload plugins, disconnect MCP, tear down provider lifecycles (Ollama, LM Studio), then exit cleanly.
166
+
167
+ ---
168
+
169
+ ## 5. AI providers
170
+
171
+ Alvin Bot supports a multi-provider registry with a fallback chain. You pick a primary, optionally define fallbacks, and the bot picks the best available provider per request.
172
+
173
+ ### 5.1 Built-in providers
174
+
175
+ | Registry key | Source | Auth | Cost | Notes |
176
+ |---|---|---|---|---|
177
+ | `claude-sdk` | Anthropic Claude Code SDK | OAuth (Claude Max) or API key | Max plan or per-token | Full tool use: Read, Write, Edit, Bash, Glob, Grep, WebSearch, WebFetch, Task. Needs the `claude` CLI installed. |
178
+ | `codex-cli` | OpenAI Codex CLI | Local CLI | Per-token | Needs the `codex` CLI installed. |
179
+ | `google` | Google Gemini 2.5 Flash | `GOOGLE_API_KEY` | Free tier available | Vision + embeddings. |
180
+ | `ollama` | Local Ollama daemon | none | Free | Auto-detected. Bot can start/stop the Ollama daemon on demand. |
181
+
182
+ ### 5.2 Custom providers
183
+
184
+ Any OpenAI-compatible endpoint (Groq, NVIDIA NIM, OpenRouter, LM Studio, vLLM, any self-hosted LLM server) goes into `~/.alvin-bot/custom-models.json`:
185
+
186
+ ```json
187
+ [
188
+ {
189
+ "key": "groq",
190
+ "name": "Groq (Llama 3.3 70B)",
191
+ "model": "llama-3.3-70b-versatile",
192
+ "baseUrl": "https://api.groq.com/openai/v1",
193
+ "apiKeyEnv": "GROQ_API_KEY",
194
+ "supportsVision": false,
195
+ "supportsStreaming": true,
196
+ "maxTokens": 32768
197
+ }
198
+ ]
199
+ ```
200
+
201
+ Set `PRIMARY_PROVIDER=groq` in `.env` and add `GROQ_API_KEY`. The setup wizard writes this for you for the common providers.
202
+
203
+ ### 5.3 The fallback chain
204
+
205
+ `.env` can define a fallback order:
206
+
207
+ ```
208
+ PRIMARY_PROVIDER=claude-sdk
209
+ FALLBACK_PROVIDERS=google,groq
210
+ ```
211
+
212
+ On every query, the registry tries the primary first. If it's unavailable (auth fails, rate-limited, service down), it cascades through the fallback list in order. The registry also learns — a provider that fails twice in a row gets temporarily deprioritized until the heartbeat monitor confirms it's healthy again.
213
+
214
+ ### 5.4 The heartbeat monitor
215
+
216
+ Every 5 minutes, the heartbeat monitor pings each configured provider with a tiny probe. Providers that fail twice in a row are marked unhealthy and get skipped until they recover. You see the current state in `/status` and in the web UI's Dashboard.
217
+
218
+ ### 5.5 Model switching from chat
219
+
220
+ `/model` — pick a different provider as your current primary.
221
+ `/fallback` — rearrange the fallback chain from Telegram.
222
+ `/effort low|medium|high|max` — adjust reasoning depth (where supported).
223
+
224
+ Switches are session-scoped by default; persist via `/model save` or the web UI.
225
+
226
+ ---
227
+
228
+ ## 6. The chat session model
229
+
230
+ Alvin Bot separates **sessions** from **users**. Every platform identity maps to a session, and sessions carry:
231
+
232
+ - Current provider and fallback chain
233
+ - Conversation history (bounded — older messages age out)
234
+ - Active skills and personality flags
235
+ - Working directory (from `/dir`)
236
+ - Locale (`/language`)
237
+
238
+ Session isolation is configurable via the `SESSION_MODE` env var:
239
+
240
+ - `per-user` (default) — one shared session per authorized user across all their platform identities. `/new` on Telegram wipes the history for the TUI too.
241
+ - `per-channel` — each platform gets its own session. `/new` on Telegram leaves the TUI untouched.
242
+ - `per-channel-peer` — each platform × user combo gets its own session. Useful when you share a bot between family members.
243
+
244
+ Memory (the long-term knowledge base at `~/.alvin-bot/memory/`) is **always** per-user, regardless of session mode.
245
+
246
+ ### 6.1 Long-running sessions
247
+
248
+ Alvin Bot's defining feature is that **he can think for as long as he needs**. There is no absolute timeout on a query — the only cap is an adaptive "stuck" detector that fires if there's no progress (no text, no tool calls) for `ALVIN_STUCK_TIMEOUT_MINUTES` (default: 10). A legitimate 40-minute reasoning run with continuous tool use never gets killed.
249
+
250
+ This is deliberate and different from most AI chat wrappers. It means Alvin can work overnight on a research task and deliver the answer when you wake up.
251
+
252
+ ### 6.2 Mid-stream abort and resume
253
+
254
+ If a provider drops the connection mid-stream (network blip, provider restart), the registry silently retries the **same** provider once. If visible text was already streamed to the user, mid-stream failover is disabled — we don't fail over to a different provider mid-answer because that would jumble the response.
255
+
256
+ ---
257
+
258
+ ## 7. Sub-agents
259
+
260
+ **Sub-agents are parallel isolated workers that run in the background.** Use them when you have multiple independent tasks, when you need to keep a long-running task from blocking your main chat, or when you want to dispatch work from a cron job.
261
+
262
+ The system distinguishes three sources:
263
+
264
+ | Source | Origin | Delivery |
265
+ |---|---|---|
266
+ | `implicit` | Main Claude calls the SDK `Task` tool | Parent stream (no separate delivery) |
267
+ | `user` | You ask the bot to spawn a sub-agent | Banner + final to your chat |
268
+ | `cron` | Scheduled job uses `ai-query` | Banner + final to `chatId` in the cron job's target |
269
+
270
+ ### 7.1 Spawning
271
+
272
+ From chat, the easiest way is to ask Main Claude to spawn one:
273
+
274
+ > *spawne einen sub-agent der mir in einem Wort 'pong' zurückgibt*
275
+
276
+ Claude invokes the SDK `Task` tool, which runs as `source: "implicit"`. The result streams back into the parent message.
277
+
278
+ From a cron job of type `ai-query`, the scheduler calls `spawnSubAgent({ source: "cron" })` internally. The cron job's `target.chatId` becomes the `parentChatId` so the delivery lands in the right chat.
279
+
280
+ ### 7.2 The `/subagents` command
281
+
282
+ | Command | Effect |
283
+ |---|---|
284
+ | `/subagents` | Show status: max parallel, visibility mode, running list |
285
+ | `/subagents max <n>` | Set max parallel (0 = auto = min(cpu, 16)) |
286
+ | `/subagents visibility auto\|banner\|silent` | Default delivery mode for new spawns |
287
+ | `/subagents list` | Tree view with depth indent and source badges |
288
+ | `/subagents cancel <name\|id>` | Cancel a running sub-agent |
289
+ | `/subagents result <name\|id>` | Show a completed sub-agent's stored result |
290
+
291
+ ### 7.3 Name-first addressing
292
+
293
+ Sub-agents are addressable by name, not just UUID. If you spawn three agents called `code-review` in quick succession, they appear as `code-review`, `code-review#2`, `code-review#3` in `/subagents list`. The name-resolver handles collisions automatically.
294
+
295
+ `/subagents cancel code-review#2` cancels the second one specifically. `/subagents cancel code-review` on an unambiguous base name cancels that one. On an ambiguous base name, the bot replies with a disambiguation list.
296
+
297
+ ### 7.4 Depth cap (F2)
298
+
299
+ Nested spawning is allowed up to depth 2:
300
+
301
+ - depth 0 = root (spawned by main thread)
302
+ - depth 1 = spawned by a depth-0 agent
303
+ - depth 2 = spawned by a depth-1 agent
304
+ - depth 3 = rejected
305
+
306
+ This allows the "scatter-gather" pattern (main → orchestrator → 10 workers) without runaway recursion.
307
+
308
+ ### 7.5 Visibility modes
309
+
310
+ - `auto` (default) — source-based routing: implicit stays in the parent stream, user and cron get a banner+final delivery.
311
+ - `banner` — always send a banner+final, even for implicit spawns.
312
+ - `silent` — never send. The result is still stored in the activeAgents map for 30 minutes and pullable via `/subagents result <name>`.
313
+ - **`live`** — stream incremental updates into a single Telegram message as the agent thinks. Only applies to `source: "user"` spawns with a `parentChatId`. The live message is plain text (so half-formed markdown during streaming can't break the edit), updates are throttled to 800 ms between edits, and a separate banner message is posted at the end so you get a completion notification. If the bot API doesn't support `editMessageText` or the live setup fails, we fall through to `banner` mode automatically.
314
+
315
+ ### 7.6 Inheritance
316
+
317
+ Sub-agents inherit from the spawning context:
318
+
319
+ - **Working directory** — the parent's `cwd` (from `/dir`). Opt out with `inheritCwd: false`.
320
+ - **CLAUDE.md** — via the Claude SDK's `settingSources: ["project"]`. Loads automatically if the cwd is inside a project with a CLAUDE.md.
321
+ - **Model and tools** — inherited via the provider registry.
322
+ - **Conversation history** — **not inherited.** Sub-agents receive only their own prompt. This forces clean, self-describing spawn requests.
323
+
324
+ ### 7.7 Bounded priority queue
325
+
326
+ When the running pool hits `maxParallel`, new spawn requests land in a bounded queue instead of being rejected immediately.
327
+
328
+ - **Default cap:** 20 slots. Configure via `/subagents queue <n>` (clamped to 0–200).
329
+ - **Disable:** `/subagents queue 0` — restores the old reject-on-full behavior.
330
+ - **Priority order on drain:** `user > cron > implicit`. Within each priority class, FIFO.
331
+ - **`/subagents list`** shows queued entries with a `#N` suffix indicating their position.
332
+ - **Cancel a queued entry** with `/subagents cancel <name>` — it's removed from the queue without ever starting.
333
+
334
+ Reject is only triggered when the pool **and** the queue are both full. The reject message is priority-aware and names who's holding the slots.
335
+
336
+ ### 7.8 Stats
337
+
338
+ `/subagents stats` shows a summary of the last 24 hours of sub-agent runs:
339
+
340
+ - Total runs + total tokens + total wall time
341
+ - Runs per source (user / cron / implicit)
342
+ - Runs per status (completed / cancelled / timeout / error)
343
+
344
+ The backing data is an append-only JSON ring buffer at `~/.alvin-bot/subagent-stats.json`. Entries older than 24 hours are pruned automatically. A hard cap of 5000 entries protects against runaway growth on very busy bots.
345
+
346
+ ### 7.9 Shutdown notifications
347
+
348
+ When you restart the bot (SIGTERM), any still-running sub-agents get a cancellation delivery before the process exits:
349
+
350
+ > ⚠️ `<name>` cancelled · `<duration>` · 0 in / 0 out
351
+ > ⚠️ Agent wurde durch Bot-Restart unterbrochen. Bitte neu triggern.
352
+
353
+ The shutdown phase is capped at 5 seconds total so a hanging Telegram send can't block the restart.
354
+
355
+ ---
356
+
357
+ ## 8. Cron jobs
358
+
359
+ Scheduled tasks that run regardless of whether you're chatting with the bot. Use them for daily news digests, weekly reports, periodic health checks, or any recurring automation.
360
+
361
+ ### 8.1 Job types
362
+
363
+ | Type | Payload | Execution |
364
+ |---|---|---|
365
+ | `reminder` | `text` | Sends the text to the target chat at the scheduled time |
366
+ | `message` | `text` | Same as reminder |
367
+ | `shell` | `command` | Runs the shell command, sends the output |
368
+ | `http` | `url`, `method`, `headers`, `body` | Fires an HTTP request, sends the response |
369
+ | `ai-query` | `prompt` | Spawns a sub-agent with `source: "cron"`, result delivered via I3 |
370
+
371
+ ### 8.2 Scheduling syntax
372
+
373
+ Supports two formats:
374
+
375
+ - **Interval** — `30s`, `5m`, `1h`, `6h`, `1d`
376
+ - **Cron** — standard 5-field (`MIN HOUR DAY MONTH WEEKDAY`, 0 = Sunday)
377
+
378
+ ### 8.3 Managing jobs
379
+
380
+ From Telegram:
381
+
382
+ ```
383
+ /cron — list all jobs
384
+ /cron add — create a new one (interactive)
385
+ /cron delete <id> — remove a job
386
+ /cron toggle <id> — enable/disable
387
+ /cron run <id> — trigger a job immediately, outside its schedule
388
+ ```
389
+
390
+ From the command line (useful for scripts):
391
+
392
+ ```
393
+ node scripts/cron-manage.js add \
394
+ --name "Daily email summary" \
395
+ --type ai-query \
396
+ --schedule "0 8 * * *" \
397
+ --prompt "Check my inbox and summarize unread messages" \
398
+ --chatId <your-telegram-id>
399
+
400
+ node scripts/cron-manage.js list
401
+ node scripts/cron-manage.js delete --id <job-id>
402
+ ```
403
+
404
+ The scheduler polls `~/.alvin-bot/cron-jobs.json` every 30 seconds, so hand-edited jobs come into effect at the next tick without a bot restart.
405
+
406
+ ### 8.4 Delivery
407
+
408
+ ai-query jobs route through the sub-agent delivery router (see §7). Other job types (reminder, shell, http, message) use the legacy delivery-queue path with retry and exponential backoff. Both paths respect the job's `target.platform` and `target.chatId`.
409
+
410
+ ---
411
+
412
+ ## 9. Commands reference
413
+
414
+ All commands are triggered from any platform that supports commands (Telegram, Discord).
415
+
416
+ ### 9.1 Core
417
+
418
+ | Command | Purpose |
419
+ |---|---|
420
+ | `/start` | Show the bot intro |
421
+ | `/help` | List all commands |
422
+ | `/new` | Start a fresh session (wipes current history) |
423
+ | `/status` | Current status: provider, model, session age, token usage |
424
+ | `/cancel` | Cancel the currently running request |
425
+ | `/dir <path>` | Change the bot's working directory |
426
+
427
+ ### 9.2 AI control
428
+
429
+ | Command | Purpose |
430
+ |---|---|
431
+ | `/model` | Switch provider |
432
+ | `/model save` | Persist the current provider as default |
433
+ | `/fallback` | Rearrange fallback chain |
434
+ | `/effort low\|medium\|high\|max` | Set reasoning depth |
435
+ | `/voice on\|off` | Toggle voice replies (ElevenLabs or Edge TTS) |
436
+ | `/language en\|de\|es\|fr` | Switch session locale |
437
+
438
+ ### 9.3 Memory and history
439
+
440
+ | Command | Purpose |
441
+ |---|---|
442
+ | `/remember <text>` | Add something to long-term memory |
443
+ | `/recall <query>` | Semantic search across memories |
444
+ | `/export` | Export the current conversation to JSON |
445
+
446
+ ### 9.4 Tools
447
+
448
+ | Command | Purpose |
449
+ |---|---|
450
+ | `/web <query>` | Quick web search |
451
+ | `/imagine <prompt>` | Generate an image (Gemini Nano Banana / Google Imagen) |
452
+ | `/remind 30m <text>` | One-shot reminder |
453
+
454
+ ### 9.5 Bot management
455
+
456
+ | Command | Purpose |
457
+ |---|---|
458
+ | `/cron` | Manage scheduled jobs |
459
+ | `/subagents` | Show sub-agent status |
460
+ | `/subagents max <n>` | Set max parallel (0 = auto) |
461
+ | `/subagents queue <n>` | Set bounded-queue cap (0 = disabled) |
462
+ | `/subagents visibility <auto\|banner\|silent\|live>` | Delivery mode |
463
+ | `/subagents list` | List all (queued + running + recent) |
464
+ | `/subagents cancel <name\|id>` | Cancel one |
465
+ | `/subagents result <name\|id>` | Show a completed result |
466
+ | `/subagents stats` | Last 24h run stats (by source + status) |
467
+ | `/webui` | Open web UI URL |
468
+ | `/setup` | Re-run the setup wizard flow from chat |
469
+ | `/restart` | Restart the bot process |
470
+ | `/update` | Pull latest, rebuild, restart |
471
+ | `/autoupdate on\|off\|status` | Configure auto-update |
472
+
473
+ ### 9.6 CLI commands (from a terminal)
474
+
475
+ | Command | Purpose |
476
+ |---|---|
477
+ | `alvin-bot setup` | Initial setup wizard |
478
+ | `alvin-bot start` | Start in background (pm2) |
479
+ | `alvin-bot start -f` | Start in foreground (for debugging) |
480
+ | `alvin-bot stop` | Stop the bot |
481
+ | `alvin-bot tui` | Terminal chat UI |
482
+ | `alvin-bot doctor` | Health check and diagnostics |
483
+ | `alvin-bot audit` | Security audit |
484
+ | `alvin-bot search <query>` | Search assets, memories, and skills |
485
+ | `alvin-bot update` | Git pull, npm install, rebuild |
486
+ | `alvin-bot launchd install` | **macOS only** — install as LaunchAgent (see §14.1) |
487
+ | `alvin-bot launchd uninstall` | Remove the LaunchAgent |
488
+ | `alvin-bot launchd status` | Show LaunchAgent state + recent logs |
489
+ | `alvin-bot version` | Print version |
490
+
491
+ ---
492
+
493
+ ## 10. Platforms
494
+
495
+ ### 10.1 Telegram
496
+
497
+ The primary platform. Full support: streaming messages, inline keyboards, voice transcription (via OpenAI Whisper or Edge TTS), photo understanding, document ingestion, sticker replies, command autocomplete.
498
+
499
+ Setup: `BOT_TOKEN` from BotFather + your user ID in `ALLOWED_USERS`.
500
+
501
+ ### 10.2 WhatsApp
502
+
503
+ Via WhatsApp Web using `whatsapp-web.js`. Two modes:
504
+
505
+ - **Self-chat** — treat your own WhatsApp number as a personal assistant notepad
506
+ - **Group whitelist** — the bot only responds in explicitly allowed groups, with per-contact access control inside those groups
507
+
508
+ Group messages go through an approval flow: the owner gets a Telegram notification (or WhatsApp DM fallback) before the bot responds, so there's no surprise chatter from the bot in a group.
509
+
510
+ Setup: scan the QR code printed on bot startup. Session cookies persist in `~/.alvin-bot/.wwebjs_auth/`.
511
+
512
+ ### 10.3 Discord
513
+
514
+ Bot with mention detection, slash commands, voice channel support. Uses the standard Discord bot token flow.
515
+
516
+ Setup: `DISCORD_TOKEN` in `.env`, invite the bot to your server with the correct intents (Message Content + Guild Messages).
517
+
518
+ ### 10.4 Signal
519
+
520
+ Via `signal-cli` REST API. Less feature-rich than the others because of Signal's tight UI model, but text, images, and voice messages work.
521
+
522
+ ### 10.5 Web UI
523
+
524
+ A full dashboard at `http://localhost:3100` (configurable via `WEB_PORT`). Password-protected via `WEB_PASSWORD`. Features:
525
+
526
+ - Live chat with streaming
527
+ - Dashboard: provider status, heartbeat, resource usage
528
+ - Memory manager: browse and edit long-term memories
529
+ - File browser: navigate and edit files the bot has access to
530
+ - Cron job editor
531
+ - Settings and env editor
532
+ - Plugin and MCP server manager
533
+ - Web terminal (in-browser shell)
534
+ - Security audit report
535
+
536
+ ### 10.6 TUI
537
+
538
+ `alvin-bot tui` starts a terminal chat with ANSI colors and streaming. Useful on remote servers without a browser.
539
+
540
+ ### 10.7 Slack
541
+
542
+ Uses `@slack/bolt`. Supports DMs and channel mentions.
543
+
544
+ ---
545
+
546
+ ## 11. Plugins and MCP servers
547
+
548
+ ### 11.1 Plugins
549
+
550
+ JavaScript modules under `plugins/` that register new Telegram commands and extend the bot's capabilities. Each plugin exports:
551
+
552
+ - `name`
553
+ - `version`
554
+ - `commands` (array of `{ name, description, handler }`)
555
+ - `init(ctx)` — called at startup, gets access to the bot instance
556
+ - `unload()` — called at shutdown
557
+
558
+ Built-in plugins:
559
+
560
+ | Plugin | Purpose |
561
+ |---|---|
562
+ | `calendar` | Google Calendar integration |
563
+ | `email` | Gmail / IMAP ingest |
564
+ | `finance` | Bank account queries |
565
+ | `notes` | Apple Notes / Obsidian sync |
566
+ | `smarthome` | Home Assistant control |
567
+ | `weather` | Weather forecasts |
568
+
569
+ User plugins go in `~/.alvin-bot/plugins/` and hot-reload on save.
570
+
571
+ ### 11.2 MCP servers
572
+
573
+ Model Context Protocol servers extend the bot with new tools. Configure them in `~/.mcp.json` or `~/.alvin-bot/mcp.json`:
574
+
575
+ ```json
576
+ {
577
+ "mcpServers": {
578
+ "filesystem": {
579
+ "command": "npx",
580
+ "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path"]
581
+ }
582
+ }
583
+ }
584
+ ```
585
+
586
+ The bot auto-discovers MCP tools at startup and makes them available to the AI provider (Claude SDK supports them natively; other providers get the tools as descriptions in the system prompt).
587
+
588
+ ---
589
+
590
+ ## 12. Skills
591
+
592
+ Skills are Markdown files under `skills/` that teach the AI how to do specific tasks. Each skill is a `SKILL.md` file with:
593
+
594
+ - Title and description
595
+ - When to use it (triggers)
596
+ - Step-by-step procedure
597
+ - Code templates and examples
598
+
599
+ Skills auto-activate based on message context. Built-in skills include:
600
+
601
+ - **apple-notes** — create and search Apple Notes
602
+ - **browser-automation** — control Chrome via Playwright
603
+ - **code-project** — scaffold, refactor, and test code projects
604
+ - **data-analysis** — pandas/jupyter-style data exploration
605
+ - **document-creation** — generate PDFs and Word docs
606
+ - **email-summary** — triage and summarize email
607
+ - **github** — issues, PRs, releases
608
+ - **summarize** — generic summarization with citations
609
+ - **system-administration** — shell tasks on Linux/macOS
610
+ - **weather** — forecast queries
611
+ - **web-research** — structured web research with sources
612
+
613
+ User skills go in `~/.alvin-bot/skills/` and are hot-reloaded.
614
+
615
+ ---
616
+
617
+ ## 13. Security
618
+
619
+ Security is taken seriously because this bot has real system access.
620
+
621
+ ### 13.1 Authentication
622
+
623
+ Only users listed in `ALLOWED_USERS` can chat with the Telegram bot. The `authMiddleware` silently drops everyone else.
624
+
625
+ For WhatsApp groups, each group must be explicitly whitelisted and the owner approves each message before the bot responds.
626
+
627
+ For the web UI, access is gated by `WEB_PASSWORD`.
628
+
629
+ ### 13.2 Execution sandboxing
630
+
631
+ The `EXEC_SECURITY` env var controls how shell commands are gated:
632
+
633
+ - `full` — no restrictions (use only on trusted machines)
634
+ - `allowlist` (default) — only whitelisted binaries from `~/.alvin-bot/exec-allowlist.txt` can run
635
+ - `deny` — shell execution completely disabled
636
+
637
+ ### 13.3 Security audit
638
+
639
+ `alvin-bot audit` runs a series of health checks:
640
+
641
+ - Are secrets in `.env` readable only by you?
642
+ - Is the data directory mode `0700`?
643
+ - Are there any API keys leaked into version-controlled files?
644
+ - Is the bot exposed on a public port?
645
+ - Are the allowed users list and exec allowlist intact?
646
+
647
+ Each check reports `PASS` / `WARN` / `FAIL` with a fix suggestion.
648
+
649
+ ### 13.4 Checkpoints during long runs
650
+
651
+ Alvin's Claude SDK provider injects a `[CHECKPOINT]` reminder into the prompt every 5 turns once certain thresholds are crossed (10+ messages or 15+ tool calls in a session). The reminder tells Claude to write a checkpoint to its memory file before processing the next request. This protects against context compaction losing progress on long multi-hour sessions.
652
+
653
+ ### 13.5 Git safety
654
+
655
+ The bot's own code is protected against accidental destruction:
656
+
657
+ - Never changes user passwords in projects
658
+ - Never touches auth functions without explicit instruction
659
+ - Never runs `git push --force` on main/master
660
+ - Never bypasses pre-commit hooks (`--no-verify`)
661
+ - Never amends commits that might be lost
662
+
663
+ ---
664
+
665
+ ## 14. Running in production
666
+
667
+ ### 14.1 macOS: `launchd` (recommended)
668
+
669
+ On macOS with the Claude Code SDK, you **must** run the bot as a `launchd` user agent, not via pm2. Claude Code stores the OAuth token for the Max subscription in the macOS Keychain under the service `"Claude Code-credentials"`, and only processes running inside the user's GUI login session can access that Keychain without a manual unlock.
670
+
671
+ Pm2 starts its daemon in a detached launchd context without Keychain access. Result: the bot sees `Not logged in` on every Claude SDK call. Launchd user agents, on the other hand, run inside the GUI session and inherit the unlocked Keychain automatically.
672
+
673
+ ```bash
674
+ alvin-bot launchd install
675
+ ```
676
+
677
+ This writes `~/Library/LaunchAgents/com.alvinbot.app.plist` with:
678
+
679
+ - `RunAtLoad true` — starts on login
680
+ - `KeepAlive Crashed=true` — auto-restart on crash
681
+ - `ThrottleInterval 10` — prevents restart loops
682
+ - `PATH` covering Apple Silicon and Intel Homebrew plus `~/.local/bin`
683
+ - stdout → `~/.alvin-bot/logs/alvin-bot.out.log`
684
+ - stderr → `~/.alvin-bot/logs/alvin-bot.err.log`
685
+
686
+ Management:
687
+
688
+ ```bash
689
+ alvin-bot launchd status # plist state, PID, last log lines
690
+ alvin-bot launchd uninstall # unload and remove the plist
691
+
692
+ # Restart:
693
+ launchctl kickstart -k gui/$UID/com.alvinbot.app
694
+ ```
695
+
696
+ If you'd previously set up the bot via pm2, uninstall the pm2 process first (`pm2 delete alvin-bot; pm2 kill`) before running `launchd install`.
697
+
698
+ ### 14.2 Linux / Windows: pm2
699
+
700
+ The `alvin-bot start` command wraps pm2:
701
+
702
+ ```bash
703
+ alvin-bot start # start in background, auto-restart on crash
704
+ alvin-bot start -f # start in foreground (for debugging)
705
+ alvin-bot stop # stop the bot
706
+ pm2 logs alvin-bot # live logs
707
+ ```
708
+
709
+ For systemd users, you can write a user unit pointing at `node dist/index.js` — see the example in `docs/systemd.md` (if included in your release).
710
+
711
+ ### 14.3 Auto-update
712
+
713
+ `/autoupdate on` tells the bot to check for updates daily. When an update is found, it runs `git pull`, `npm install`, `npm run build`, and restarts itself. The auto-update flag lives at `~/.alvin-bot/auto-update.flag`.
714
+
715
+ ### 14.4 Environment variables reference
716
+
717
+ Common env vars (all optional unless marked):
718
+
719
+ | Variable | Default | Purpose |
720
+ |---|---|---|
721
+ | `BOT_TOKEN` | — | **Required**. Telegram bot token. |
722
+ | `ALLOWED_USERS` | — | **Required**. Comma-separated Telegram user IDs. |
723
+ | `PRIMARY_PROVIDER` | `claude-sdk` | Registry key of the default provider. |
724
+ | `FALLBACK_PROVIDERS` | — | Comma-separated fallback chain. |
725
+ | `GOOGLE_API_KEY` | — | Required if using `google` as provider. |
726
+ | `GROQ_API_KEY` | — | For custom Groq provider. |
727
+ | `OPENAI_API_KEY` | — | For custom OpenAI provider. |
728
+ | `OPENROUTER_API_KEY` | — | For custom OpenRouter provider. |
729
+ | `NVIDIA_API_KEY` | — | For custom NVIDIA NIM provider. |
730
+ | `ELEVENLABS_API_KEY` | — | Voice synthesis (falls back to Edge TTS). |
731
+ | `WEB_PORT` | `3100` | Web UI port. |
732
+ | `WEB_PASSWORD` | — | Web UI access password. |
733
+ | `SESSION_MODE` | `per-user` | Session isolation mode. |
734
+ | `ALVIN_STUCK_TIMEOUT_MINUTES` | `10` | Adaptive stuck-detector window. |
735
+ | `MAX_SUBAGENTS` | `0` (auto) | Max parallel sub-agents. |
736
+ | `SUBAGENT_TIMEOUT` | `300000` | Per-agent timeout in ms. |
737
+ | `COMPACTION_THRESHOLD` | `80000` | Tokens before context compaction triggers. |
738
+ | `EXEC_SECURITY` | `allowlist` | Shell execution sandbox mode. |
739
+ | `ALVIN_DATA_DIR` | `~/.alvin-bot` | Data directory path. |
740
+
741
+ ---
742
+
743
+ ## 15. Troubleshooting
744
+
745
+ ### 15.1 Bot starts but doesn't respond
746
+
747
+ 1. `alvin-bot doctor` — runs 10+ health checks
748
+ 2. Check the log: `pm2 logs alvin-bot` (or `~/.alvin-bot/logs/alvin-bot.err.log` under launchd)
749
+ 3. Verify your provider: `/status` in chat shows the active provider and its health
750
+
751
+ ### 15.2 Claude SDK says "Not logged in"
752
+
753
+ You're hitting the Keychain problem documented in §14.1. Three paths:
754
+
755
+ - **Preferred**: switch to `alvin-bot launchd install` on macOS
756
+ - **Temporary**: `security unlock-keychain -p '<your-login-password>' ~/Library/Keychains/login.keychain-db`, then restart the bot in the same terminal session
757
+ - **Fallback**: run interactively: `claude` (opens the interactive CLI), then `/login`, then re-run the bot
758
+
759
+ ### 15.3 Sub-agent limit reached
760
+
761
+ Either increase the cap:
762
+
763
+ ```
764
+ /subagents max 8
765
+ ```
766
+
767
+ Or cancel a stuck agent:
768
+
769
+ ```
770
+ /subagents list
771
+ /subagents cancel <name>
772
+ ```
773
+
774
+ ### 15.4 Cron job not firing
775
+
776
+ - Is it `enabled: true`? `/cron` or `cat ~/.alvin-bot/cron-jobs.json`
777
+ - Is the schedule valid? Try `/cron run <id>` to trigger manually
778
+ - Check the bot log for `[cron]` lines
779
+
780
+ ### 15.5 Web UI shows "Not authorized"
781
+
782
+ `WEB_PASSWORD` isn't set or doesn't match. Add `WEB_PASSWORD=<pick-a-password>` to `.env` and restart.
783
+
784
+ ### 15.6 Sub-agent results shown twice
785
+
786
+ Happens if you upgrade from a version before 4.6.0 and a mid-stream shutdown race fired. Fixed in 4.6.0 — see CHANGELOG §9.2.
787
+
788
+ ### 15.7 Upgrading from 4.5.x
789
+
790
+ - Run `npm install -g alvin-bot@latest`
791
+ - Run `alvin-bot update` from chat (pulls, rebuilds, restarts)
792
+ - On macOS, consider switching from pm2 to `alvin-bot launchd install` for the Keychain fix
793
+
794
+ ---
795
+
796
+ ## 16. Upgrading
797
+
798
+ ### 16.1 Data directory compatibility
799
+
800
+ Alvin Bot follows semver for the **data directory format**. Minor version bumps never break `~/.alvin-bot/`; major bumps might introduce migration scripts that run automatically on first startup.
801
+
802
+ ### 16.2 From 4.5.x to 4.6.0
803
+
804
+ - Sub-agents: new fields in `sub-agents.json` (`visibility`). Old files auto-upgrade — the loader treats missing fields as defaults.
805
+ - Cron jobs: no schema change.
806
+ - Memory: no schema change.
807
+ - `.env`: no new required variables. `MAX_SUBAGENTS` and `SUBAGENT_TIMEOUT` are optional.
808
+
809
+ ### 16.3 From 4.6.x to 4.7.0
810
+
811
+ - Sub-agents: new fields in `sub-agents.json` (`queueCap`, defaults to 20). Old files auto-upgrade.
812
+ - New file `~/.alvin-bot/subagent-stats.json` — auto-created when the first sub-agent finishes.
813
+ - `start`/`stop` now auto-detect the LaunchAgent on macOS. No migration needed; if you previously installed the LaunchAgent in 4.6.0, `alvin-bot start` now correctly reloads it instead of spawning a parallel pm2 process.
814
+ - No new required `.env` variables.
815
+
816
+ ### 16.3 From git
817
+
818
+ ```bash
819
+ cd ~/path/to/alvin-bot
820
+ git pull
821
+ npm install
822
+ npm run build
823
+
824
+ # If running under launchd:
825
+ launchctl kickstart -k gui/$UID/com.alvinbot.app
826
+
827
+ # If running under pm2:
828
+ alvin-bot start
829
+
830
+ # If running in foreground:
831
+ # Stop with Ctrl+C, then alvin-bot start -f
832
+ ```
833
+
834
+ ### 16.4 From npm
835
+
836
+ ```bash
837
+ npm install -g alvin-bot@latest
838
+ alvin-bot stop
839
+ alvin-bot start
840
+ ```
841
+
842
+ ### 16.5 Rollback
843
+
844
+ ```bash
845
+ npm install -g alvin-bot@4.5.1
846
+ ```
847
+
848
+ Old data in `~/.alvin-bot/` continues to work — nothing is deleted on upgrade.
849
+
850
+ ---
851
+
852
+ ## Feedback and bug reports
853
+
854
+ - GitHub Issues: <https://github.com/alvbln/Alvin-Bot/issues>
855
+ - Pull requests welcome
856
+ - Maintained by @alvbln