@suzuke/agend 1.0.0 → 1.0.2

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 (66) hide show
  1. package/README.md +50 -528
  2. package/README.zh-TW.md +49 -474
  3. package/dist/channel/adapters/discord.js +1 -1
  4. package/dist/channel/adapters/discord.js.map +1 -1
  5. package/dist/channel/factory.js +2 -2
  6. package/dist/channel/factory.js.map +1 -1
  7. package/dist/channel/mcp-tools.js +3 -3
  8. package/dist/channel/mcp-tools.js.map +1 -1
  9. package/dist/cli.js +1 -1
  10. package/dist/cli.js.map +1 -1
  11. package/dist/daemon.js +37 -36
  12. package/dist/daemon.js.map +1 -1
  13. package/dist/export-import.js +2 -2
  14. package/dist/export-import.js.map +1 -1
  15. package/dist/fleet-manager.js +5 -8
  16. package/dist/fleet-manager.js.map +1 -1
  17. package/dist/setup-wizard.js +2 -2
  18. package/dist/setup-wizard.js.map +1 -1
  19. package/dist/tmux-manager.js +3 -2
  20. package/dist/tmux-manager.js.map +1 -1
  21. package/package.json +3 -5
  22. package/dist/approval/approval-server.d.ts +0 -30
  23. package/dist/approval/approval-server.js +0 -156
  24. package/dist/approval/approval-server.js.map +0 -1
  25. package/dist/approval/tmux-prompt-detector.d.ts +0 -34
  26. package/dist/approval/tmux-prompt-detector.js +0 -264
  27. package/dist/approval/tmux-prompt-detector.js.map +0 -1
  28. package/dist/backend/approval-strategy.d.ts +0 -14
  29. package/dist/backend/approval-strategy.js +0 -2
  30. package/dist/backend/approval-strategy.js.map +0 -1
  31. package/dist/backend/hook-based-approval.d.ts +0 -20
  32. package/dist/backend/hook-based-approval.js +0 -41
  33. package/dist/backend/hook-based-approval.js.map +0 -1
  34. package/dist/container-manager.d.ts +0 -24
  35. package/dist/container-manager.js +0 -148
  36. package/dist/container-manager.js.map +0 -1
  37. package/dist/db.d.ts +0 -10
  38. package/dist/db.js +0 -43
  39. package/dist/db.js.map +0 -1
  40. package/dist/install-recorder.d.ts +0 -30
  41. package/dist/install-recorder.js +0 -159
  42. package/dist/install-recorder.js.map +0 -1
  43. package/dist/meeting/orchestrator.d.ts +0 -30
  44. package/dist/meeting/orchestrator.js +0 -355
  45. package/dist/meeting/orchestrator.js.map +0 -1
  46. package/dist/meeting/prompt-builder.d.ts +0 -12
  47. package/dist/meeting/prompt-builder.js +0 -96
  48. package/dist/meeting/prompt-builder.js.map +0 -1
  49. package/dist/meeting/role-assigner.d.ts +0 -2
  50. package/dist/meeting/role-assigner.js +0 -25
  51. package/dist/meeting/role-assigner.js.map +0 -1
  52. package/dist/meeting/types.d.ts +0 -21
  53. package/dist/meeting/types.js +0 -2
  54. package/dist/meeting/types.js.map +0 -1
  55. package/dist/meeting-manager.d.ts +0 -10
  56. package/dist/meeting-manager.js +0 -38
  57. package/dist/meeting-manager.js.map +0 -1
  58. package/dist/memory-layer.d.ts +0 -13
  59. package/dist/memory-layer.js +0 -44
  60. package/dist/memory-layer.js.map +0 -1
  61. package/dist/plugin/agend/.mcp.json +0 -9
  62. package/dist/plugin/ccd-channel/.claude-plugin/plugin.json +0 -5
  63. package/dist/plugin/ccd-channel/.mcp.json +0 -9
  64. package/dist/process-manager.d.ts +0 -31
  65. package/dist/process-manager.js +0 -264
  66. package/dist/process-manager.js.map +0 -1
package/README.md CHANGED
@@ -1,512 +1,58 @@
1
- # claude-channel-daemon
1
+ # AgEnD
2
2
 
3
+ [![npm](https://img.shields.io/npm/v/@suzuke/agend)](https://www.npmjs.com/package/@suzuke/agend)
3
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
4
5
  [![Node.js >= 20](https://img.shields.io/badge/Node.js-%3E%3D%2020-green.svg)](https://nodejs.org)
5
- [![Claude Code](https://img.shields.io/badge/Claude%20Code-compatible-blueviolet.svg)](https://docs.anthropic.com/en/docs/claude-code)
6
6
 
7
- **Run a fleet of Claude Code agents from your phone.** One Telegram bot, unlimited projects — each Forum Topic is an independent Claude session with crash recovery and zero babysitting.
7
+ **Agent Engineering Daemon** — run a fleet of AI coding agents from your phone.
8
8
 
9
- [繁體中文](README.zh-TW.md)
10
-
11
- > **⚠️** The daemon uses Claude Code's native permission relay — permission requests are forwarded to Telegram as inline buttons (Allow/Deny). See [Permission System](#permission-system).
12
-
13
- ## Why this exists
14
-
15
- Claude Code's official Telegram plugin gives you **1 bot = 1 session**. Close the terminal and it goes offline. No scheduling. No multi-project support.
16
-
17
- **claude-channel-daemon** turns Claude Code into an always-on, multi-project AI engineering team you control from Telegram:
18
-
19
- | Feature | Official Plugin | claude-channel-daemon |
20
- |---------|:-:|:-:|
21
- | Multiple projects simultaneously | — | **N sessions, 1 bot** |
22
- | Survives terminal close / SSH disconnect | — | **tmux persistence** |
23
- | Cron-based scheduled tasks | Session-scoped (expires in 3 days) | **Persistent (SQLite-backed)** |
24
- | Auto context rotation (prevent stale sessions) | — | **Built-in** |
25
- | Permission requests via Telegram | Text-based reply | **Inline buttons** |
26
- | Voice messages → Claude | — | **Groq Whisper** |
27
- | Dynamic instance creation via General topic | — | **Built-in** |
28
- | Install as system service (launchd/systemd) | — | **One command** |
29
- | Crash recovery | — | **Auto-restart** |
30
- | Cost guard (daily spending limits) | Platform-level (`--max-budget-usd`) | **Per-instance daily limits** |
31
- | Fleet status from Telegram | — | **/status command** |
32
- | Daily fleet summary | — | **Scheduled report** |
33
- | Hang detection | — | **Auto-detect + notify** |
34
- | Peer-to-peer agent collaboration | — | **Built-in** |
35
-
36
- ## Who is this for
37
-
38
- - **Solo developers** who want Claude working on multiple repos around the clock
39
- - **Small teams** sharing a single bot — each team member gets their own Forum Topic
40
- - **CI/CD power users** who want cron-scheduled Claude tasks (daily PR reviews, deploy checks)
41
- - **Security-conscious users** who need explicit permission approval for tool use
42
- - Anyone who's tired of keeping a terminal window open just to talk to Claude
43
-
44
- ## How it compares
45
-
46
- | | claude-channel-daemon | Claude Code Telegram Plugin | Cursor | Cline (VS Code) |
47
- |---|:-:|:-:|:-:|:-:|
48
- | Runs headless (no IDE/terminal) | **Yes** | Needs terminal | No | No |
49
- | Multi-project fleet | **Yes** | 1 session | 1 window | 1 window |
50
- | Multi-channel (Telegram, Discord) | **Yes** | Telegram only | N/A | N/A |
51
- | Scheduled tasks | **Persistent** | Session-scoped | No | No |
52
- | Context auto-rotation | **Yes** | No | N/A | No |
53
- | Permission approval flow | **Inline buttons** | Text-based | N/A | Limited |
54
- | Mobile-first (Telegram) | **Yes** | Yes | No | No |
55
- | Voice input | **Yes** | No | No | No |
56
- | System service | **Yes** | No | N/A | N/A |
57
- | Cost controls | **Per-instance** | Platform-level | N/A | N/A |
58
- | Model failover | **Auto-switch** | No | No | No |
59
- | Crash recovery | **Yes** | No | N/A | N/A |
60
-
61
- ## Architecture
62
-
63
- ```
64
- ┌──────────────────────────────────────────────────────────────┐
65
- │ Fleet Manager │
66
- │ │
67
- Telegram ◄──long-poll──► │ ChannelAdapter Scheduler (croner) │
68
- Discord ◄──gateway────► │ (Telegram/Discord) │ │
69
- │ │ │ cron triggers │
70
- │ threadId routing table │ │
71
- │ #277→proj-a #672→proj-b │ │
72
- │ │ │ CostGuard HangDetector │
73
- │ ┌────┴────┐ ┌────┴────┐ ┌────┴────┐ WebhookEmitter │
74
- │ │Daemon A │ │Daemon B │ │Daemon C │ │
75
- │ │Permission│ │Permission│ │Permission│ │
76
- │ │Relay │ │Relay │ │Relay │ │
77
- │ │Context │ │Context │ │Context │ │
78
- │ │Guardian │ │Guardian │ │Guardian │ │
79
- │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
80
- │ │ │ │ │
81
- │ ┌────┴─────┐ ┌────┴─────┐ ┌────┴─────┐ │
82
- │ │tmux win │ │tmux win │ │tmux win │ │
83
- │ │Claude │ │Claude │ │Claude │ │
84
- │ │+MCP srv │ │+MCP srv │ │+MCP srv │ │
85
- │ └──────────┘ └──────────┘ └──────────┘ │
86
- └──────────────────────────────────────────────────────────────┘
87
- ```
88
-
89
- ## Key features
90
-
91
- ### Fleet mode — one bot, many projects
92
-
93
- Each Telegram Forum Topic maps to an independent Claude Code session. Create a topic, pick a project directory, and Claude starts working. Delete the topic, instance stops. Scale to as many projects as your machine can handle.
94
-
95
- ### Scheduled tasks
96
-
97
- Claude can create cron-based schedules via MCP tools. Schedules survive daemon restarts (SQLite-backed).
98
-
99
- ```
100
- User: "Every morning at 9am, check if there are any open PRs that need review"
101
- Claude: → create_schedule(cron: "0 9 * * *", message: "Check open PRs needing review")
102
- ```
103
-
104
- Available MCP tools: `create_schedule`, `list_schedules`, `update_schedule`, `delete_schedule`
105
-
106
- Collaboration MCP tools: `list_instances`, `send_to_instance`, `start_instance`, `create_instance`, `delete_instance`
107
-
108
- Schedules can target a specific instance or the same instance that created them. When a schedule triggers, the daemon pushes the message to Claude as if a user sent it.
109
-
110
- ### Context rotation
111
-
112
- Watches Claude's status line JSON. When context usage exceeds the threshold or the session reaches its max age, the daemon performs a simple restart:
113
-
114
- ```
115
- NORMAL → RESTARTING → GRACE
116
- ```
117
-
118
- 1. **Trigger** — context exceeds threshold (default 80%) or `max_age_hours` reached (default 8h)
119
- 2. **Idle barrier** — waits up to 5 seconds for current activity to settle (best-effort, not a handover)
120
- 3. **Snapshot** — daemon collects recent user messages, tool activity, and statusline data into `rotation-state.json`
121
- 4. **Restart** — kills tmux window, spawns fresh session with the snapshot injected into the system prompt
122
- 5. **Grace** — 10-minute cooldown to prevent rapid re-rotation
123
-
124
- No handover prompt is sent to Claude. Recovery context comes entirely from the daemon-side snapshot.
125
-
126
- ### Peer-to-peer agent collaboration
127
-
128
- Every instance is an equal peer that can discover, wake, create, and message other instances. No dispatcher needed — collaboration emerges from the tools available to each agent.
129
-
130
- **Core MCP tools:**
131
-
132
- - `list_instances` — discover all configured instances (running or stopped) with status, working directory, tags, and last activity
133
- - `send_to_instance` — send a message to another instance or external session; supports structured metadata (`request_kind`, `requires_reply`, `correlation_id`, `task_summary`)
134
- - `start_instance` — wake a stopped instance so you can message it
135
- - `create_instance` — create a new instance with a topic from a project directory (supports `--branch` for git worktree isolation)
136
- - `delete_instance` — remove an instance and its topic
137
- - `describe_instance` — get detailed info about a specific instance (description, tags, model, last activity)
138
-
139
- **High-level collaboration tools** (prefer these over raw `send_to_instance`):
140
-
141
- - `request_information` — ask another instance a question and expect a reply (`request_kind=query`, `requires_reply=true`)
142
- - `delegate_task` — assign work to another instance with success criteria (`request_kind=task`, `requires_reply=true`)
143
- - `report_result` — return results to the requester, echoing `correlation_id` to link the response to its request
144
-
145
- Messages are posted to the recipient's Telegram topic for visibility. Sender topic notifications are only posted for instance-to-instance messages (not from external sessions).
146
-
147
- If you `send_to_instance` a stopped instance, the error tells you to use `start_instance()` first — agents self-correct without human intervention.
148
-
149
- #### Fleet context system prompt
150
-
151
- On startup, each instance automatically receives a fleet context system prompt that tells it:
152
-
153
- - Its own identity (`instanceName`) and working directory
154
- - The full list of fleet tools and how to use them
155
- - Collaboration rules: how to handle `from_instance` messages, when to echo `correlation_id`, scope awareness (never assume direct file access to another instance's repo)
156
-
157
- This means instances understand their role in the fleet from the first message, without any manual configuration.
158
-
159
- ### General Topic instance
160
-
161
- A regular instance bound to the Telegram General Topic. Auto-created on fleet startup, it serves as a natural language entry point for tasks that don't belong to a specific project. Its behavior is defined entirely by its project's `CLAUDE.md`:
162
-
163
- - Simple tasks (web search, translation, general questions) — handles directly
164
- - Project-specific tasks — uses `list_instances()` to find the right agent, `start_instance()` if needed, then `send_to_instance()` to delegate
165
- - New project requests — uses `create_instance()` to set up a new agent
166
-
167
- Use `/status` in the General topic for a fleet overview. All other project management is handled by the General instance through natural language.
168
-
169
- ### External session support
170
-
171
- You can connect a local Claude Code session to the daemon's channel tools (reply, send_to_instance, etc.) by pointing `.mcp.json` at an instance's IPC socket:
172
-
173
- ```json
174
- {
175
- "mcpServers": {
176
- "ccd-channel": {
177
- "command": "node",
178
- "args": ["path/to/dist/channel/mcp-server.js"],
179
- "env": {
180
- "CCD_SOCKET_PATH": "~/.claude-channel-daemon/instances/<name>/channel.sock"
181
- }
182
- }
183
- }
184
- }
185
- ```
186
-
187
- The daemon automatically isolates external sessions from internal ones using env var layering:
188
-
189
- | Session type | Identity source | Example |
190
- |---|---|---|
191
- | Internal (daemon-managed) | `CCD_INSTANCE_NAME` via tmux env | `ccplugin` |
192
- | External (custom name) | `CCD_SESSION_NAME` in `.mcp.json` env | `dev` |
193
- | External (zero-config) | `external-<basename(cwd)>` fallback | `external-myproject` |
194
-
195
- Internal sessions get `CCD_INSTANCE_NAME` injected by the daemon into the tmux shell environment. External sessions don't have this, so they fall through to `CCD_SESSION_NAME` (if set) or an auto-generated name based on the working directory. This means the same `.mcp.json` produces different identities for internal vs external sessions — no configuration conflicts.
196
-
197
- External sessions appear in `list_instances` and can be targeted by `send_to_instance`.
198
-
199
- ### Graceful restart
200
-
201
- `ccd fleet restart` sends SIGUSR2 to the fleet manager. It waits for all instances to go idle (no transcript activity for 10s), then restarts them one by one. A 5-minute timeout prevents hanging on stuck instances.
202
-
203
- ### Telegram commands
204
-
205
- In topic mode, the bot responds to commands in the General topic:
206
-
207
- - `/status` — show fleet status and costs
208
-
209
- Project management commands (`/open`, `/new`, `/meets`, `/debate`, `/collab`) were removed in v0.3.4. The General instance now handles these tasks via natural language — just tell it what you need and it will use `create_instance`, `start_instance`, or `send_to_instance` as appropriate.
210
-
211
- ### Permission system
212
-
213
- Uses Claude Code's native permission relay — permission requests are forwarded to Telegram as inline buttons (Allow/Deny). When Claude requests a sensitive tool use, the daemon surfaces it to you in Telegram and waits for your response before proceeding.
214
-
215
- ### Voice transcription
216
-
217
- Telegram voice messages are transcribed via Groq Whisper API and sent to Claude as text. Works in both topic mode and DM mode. Requires `GROQ_API_KEY` in `.env`.
218
-
219
- ### Dynamic instance management
220
-
221
- Instances are created through the General instance using `create_instance`. Tell the General instance what project you want to work on — it creates a Telegram topic, binds the project directory, and starts Claude automatically. Instances can also be created with `--branch` to spawn a git worktree for feature branch isolation. Deleting a topic auto-unbinds and stops the instance. Use `delete_instance` to fully remove an instance and its topic.
222
-
223
- ### Cost guard
224
-
225
- Prevent bill shock when running unattended. Configure daily spending limits in `fleet.yaml`:
226
-
227
- ```yaml
228
- defaults:
229
- cost_guard:
230
- daily_limit_usd: 50
231
- warn_at_percentage: 80
232
- timezone: "Asia/Taipei"
233
- ```
234
-
235
- When an instance approaches the limit, a warning is posted to its Telegram topic. When the limit is reached, the instance is automatically paused and a notification is sent. Paused instances resume the next day or when manually restarted.
236
-
237
- ### Fleet status
238
-
239
- Use `/status` in the General topic to see a live overview:
240
-
241
- ```
242
- 🟢 proj-a — ctx 42%, $3.20 today
243
- 🟢 proj-b — ctx 67%, $8.50 today
244
- ⏸ proj-c — paused (cost limit)
245
-
246
- Fleet: $11.70 / $50.00 daily
247
- ```
248
-
249
- ### Daily summary
250
-
251
- A daily report is posted to the General topic at a configurable time (default 21:00):
252
-
253
- ```
254
- 📊 Daily Report — 2026-03-26
255
-
256
- proj-a: $8.20, 2 restarts
257
- proj-b: $2.10
258
- proj-c: $0.00 ⚠️ 1 hang
259
-
260
- Total: $10.30
261
- ```
262
-
263
- ### Hang detection
264
-
265
- If an instance shows no activity for 15 minutes (configurable), the daemon posts a notification with inline buttons:
266
-
267
- - **Force restart** — stops and restarts the instance
268
- - **Keep waiting** — dismisses the alert
9
+ One Telegram bot, multiple CLI backends (Claude Code, Gemini CLI, Codex, OpenCode), unlimited projects. Each Forum Topic is an independent agent session with crash recovery and zero babysitting.
269
10
 
270
- Uses multi-signal detection: checks both transcript activity and statusline freshness to avoid false positives during long-running tool calls.
271
-
272
- ### Rate limit-aware scheduling
273
-
274
- When the 5-hour API rate limit exceeds 85%, scheduled triggers are automatically deferred instead of firing. A notification is posted to the instance's topic. Deferred schedules are not lost — they will fire on the next cron tick when rate limits are below threshold.
275
-
276
- ### Model failover
277
-
278
- When the primary model hits a rate limit, the daemon automatically switches to a backup model on the next context rotation. Configure a fallback chain in `fleet.yaml`:
279
-
280
- ```yaml
281
- instances:
282
- my-project:
283
- model_failover: ["opus", "sonnet"]
284
- ```
285
-
286
- The daemon notifies you in Telegram when a failover occurs and switches back to the primary model when rate limits recover.
287
-
288
- ### Topic icon + idle archive
289
-
290
- Running instances get a visual icon indicator in Telegram. When an instance stops or crashes, the icon changes. Idle instances are automatically archived — sending a message to an archived topic re-opens it automatically.
291
-
292
- ### Permission countdown + Always Allow
293
-
294
- Permission prompts now show a countdown timer that updates every 30 seconds. An "Always Allow" button lets you approve all future uses of a specific tool for the current session. Decisions are shown inline after you respond ("✅ Approved" / "❌ Denied").
295
-
296
- ### Daemon-side restart snapshot
297
-
298
- Before each context restart, the daemon saves a `rotation-state.json` with recent user messages, tool activity, context usage, and statusline data. The next session receives this snapshot in its system prompt, providing continuity without relying on Claude to write a handover report.
299
-
300
- ### Service message filter
301
-
302
- Telegram system events (topic rename, pin, member join, etc.) are filtered out before reaching Claude, saving context window tokens.
303
-
304
- ### Health endpoint
305
-
306
- A lightweight HTTP endpoint for external monitoring tools:
307
-
308
- ```
309
- GET /health → { status: "ok", instances: 3, uptime: 86400 }
310
- GET /status → { instances: [{ name, status, context_pct, cost_today }] }
311
- ```
312
-
313
- Configure in `fleet.yaml`:
314
-
315
- ```yaml
316
- health_port: 19280 # top-level, default 19280, binds to 127.0.0.1
317
- ```
318
-
319
- ### Webhook notifications
320
-
321
- Push fleet events to external endpoints (Slack, custom dashboards, etc.):
322
-
323
- ```yaml
324
- defaults:
325
- webhooks:
326
- - url: https://hooks.slack.com/...
327
- events: ["restart", "hang", "cost_warn"]
328
- - url: https://custom.endpoint/ccd
329
- events: ["*"]
330
- ```
331
-
332
- ### Discord adapter (MVP)
333
-
334
- Connect your fleet to Discord instead of (or alongside) Telegram. Configure in `fleet.yaml`:
335
-
336
- ```yaml
337
- channel:
338
- type: discord
339
- bot_token_env: CCD_DISCORD_TOKEN
340
- guild_id: "123456789"
341
- ```
342
-
343
- ### External adapter plugin system
11
+ [繁體中文](README.zh-TW.md)
344
12
 
345
- Community adapters can be installed via npm and loaded automatically:
13
+ > **⚠️** All CLI backends run with `--dangerously-skip-permissions` (or equivalent). See [Security](SECURITY.md).
346
14
 
347
- ```bash
348
- npm install ccd-adapter-slack
349
- ```
15
+ ## Problems agend solves
350
16
 
351
- The daemon discovers adapters matching the `ccd-adapter-*` naming convention. Channel types are exported from the package entry point for adapter authors.
17
+ | Without agend | With agend |
18
+ |---|---|
19
+ | Close the terminal, agent goes offline | Runs as a system service — survives reboots |
20
+ | One terminal = one project | One bot, unlimited projects running in parallel |
21
+ | Long-running sessions accumulate stale context | Auto-rotates sessions by max age to stay fresh |
22
+ | No idea what your agents are doing overnight | Daily cost reports + hang detection alerts |
23
+ | Cron tasks disappear when the session ends | Persistent schedules backed by SQLite |
24
+ | Rate limited on one model, everything stops | Auto-failover to backup models |
25
+ | Can't approve tool use from your phone | Inline Telegram buttons with countdown + Always Allow |
26
+ | Agents work in silos, can't coordinate | Peer-to-peer collaboration via MCP tools |
27
+ | Runaway costs from unattended sessions | Per-instance daily spending limits with auto-pause |
352
28
 
353
29
  ## Quick start
354
30
 
355
31
  ```bash
356
- # Prerequisites
357
- brew install tmux # macOS
358
-
359
- # Install
360
- npm install -g claude-channel-daemon
361
-
362
- # Interactive setup
363
- ccd init
364
-
365
- # Start the fleet
366
- ccd fleet start
367
- ```
368
-
369
- ## Commands
370
-
371
- ### Telegram commands (General topic)
372
-
373
- | Command | Description |
374
- |---------|-------------|
375
- | `/status` | Show fleet status, context %, and costs |
376
- | `/reload` | Restart fleet with new code (requires launchd service) |
377
-
378
- All other operations (create/delete/start instances, delegate tasks) are handled by the General instance through natural language.
379
-
380
- ### Fleet management
381
-
382
- ```bash
383
- ccd fleet start # Start all instances (not needed with launchd)
384
- ccd fleet stop # Stop all instances
385
- ccd fleet restart # Graceful restart (wait for idle, same code)
386
- ccd fleet restart --reload # Restart with new code (launchd auto-restarts)
387
- ccd fleet status # Show instance status
388
- ccd fleet logs <name> # Show instance logs
389
- ccd fleet history # Show event history (cost, rotations, hangs)
390
- ccd fleet start <name> # Start specific instance
391
- ccd fleet stop <name> # Stop specific instance
392
- ccd fleet cleanup # Remove orphaned instance directories
393
- ccd fleet cleanup --dry-run # Preview cleanup without deleting
394
- ```
395
-
396
- ### Schedules
397
-
398
- ```bash
399
- ccd schedule list # List all schedules
400
- ccd schedule add # Add a schedule from CLI
401
- ccd schedule delete <id> # Delete a schedule
402
- ccd schedule enable <id> # Enable a schedule
403
- ccd schedule disable <id> # Disable a schedule
404
- ccd schedule history <id> # Show schedule run history
405
- ```
406
-
407
- ### Topic bindings
408
-
409
- ```bash
410
- ccd topic list # List topic bindings
411
- ccd topic bind <name> <tid> # Bind instance to topic
412
- ccd topic unbind <name> # Unbind instance from topic
413
- ```
414
-
415
- ### Access control
416
-
417
- ```bash
418
- ccd access lock <name> # Lock instance access
419
- ccd access unlock <name> # Unlock instance access
420
- ccd access list <name> # List allowed users
421
- ccd access remove <name> <uid> # Remove user
422
- ccd access pair <name> <uid> # Generate pairing code
423
- ```
424
-
425
- ### Setup & service
426
-
427
- ```bash
428
- ccd init # Interactive setup wizard
429
- ccd install # Install as system service (launchd/systemd)
430
- ccd install --activate # Install and start immediately
431
- ccd uninstall # Remove system service
432
- ccd export [path] # Export config for device migration
433
- ccd export --full [path] # Export config + all instance data
434
- ccd import <file> # Import config from export file
435
- ```
436
-
437
- ## Configuration
438
-
439
- Fleet config at `~/.claude-channel-daemon/fleet.yaml`:
440
-
441
- ```yaml
442
- project_roots:
443
- - ~/Projects
444
-
445
- channel:
446
- type: telegram # telegram or discord
447
- mode: topic # topic (recommended) or dm
448
- bot_token_env: CCD_BOT_TOKEN
449
- group_id: -100xxxxxxxxxx
450
- access:
451
- mode: locked # locked or pairing
452
- allowed_users:
453
- - 123456789
454
-
455
- defaults:
456
- cost_guard:
457
- daily_limit_usd: 50
458
- warn_at_percentage: 80
459
- timezone: "Asia/Taipei"
460
- daily_summary:
461
- enabled: true
462
- hour: 21
463
- minute: 0
464
- context_guardian:
465
- restart_threshold_pct: 80
466
- max_age_hours: 8
467
- model_failover: ["opus", "sonnet"]
468
- webhooks:
469
- - url: https://hooks.slack.com/...
470
- events: ["rotation", "hang", "cost_warn"]
471
- log_level: info
472
-
473
- instances:
474
- my-project:
475
- working_directory: /path/to/project
476
- topic_id: 277
477
- description: "Main backend service"
478
- tags: ["backend", "api"] # searchable labels; visible in list_instances
479
- cost_guard:
480
- daily_limit_usd: 30
481
- model: opus
482
- ```
483
-
484
- Secrets in `~/.claude-channel-daemon/.env`:
485
- ```
486
- CCD_BOT_TOKEN=123456789:AAH...
487
- GROQ_API_KEY=gsk_... # optional, for voice transcription
488
- ```
489
-
490
- ## Data directory
491
-
492
- `~/.claude-channel-daemon/`:
493
-
494
- | Path | Purpose |
495
- |------|---------|
496
- | `fleet.yaml` | Fleet configuration |
497
- | `.env` | Bot token + API keys |
498
- | `fleet.log` | Fleet log (JSON) |
499
- | `fleet.pid` | Fleet manager PID |
500
- | `scheduler.db` | Schedule database (SQLite) |
501
- | `events.db` | Event log (cost snapshots, rotations, hangs) |
502
- | `instances/<name>/` | Per-instance data |
503
- | `instances/<name>/daemon.log` | Instance log |
504
- | `instances/<name>/session-id` | Session UUID for `--resume` |
505
- | `instances/<name>/statusline.json` | Latest Claude status line |
506
- | `instances/<name>/channel.sock` | IPC Unix socket |
507
- | `instances/<name>/claude-settings.json` | Per-instance Claude settings |
508
- | `instances/<name>/rotation-state.json` | Context restart snapshot |
509
- | `instances/<name>/output.log` | Claude tmux output capture |
32
+ brew install tmux # macOS (prerequisite)
33
+ npm install -g @suzuke/agend # install
34
+ agend init # interactive setup
35
+ agend fleet start # launch the fleet
36
+ ```
37
+
38
+ ## Features
39
+
40
+ - **Fleet mode** — one bot, N projects, each in its own Telegram Forum Topic
41
+ - **Persistent schedules** — cron-based tasks that survive restarts (SQLite-backed)
42
+ - **Context rotation** — auto-restart long-running sessions to keep context fresh (max-age based)
43
+ - **Peer-to-peer collaboration** — agents discover, wake, and message each other via MCP tools
44
+ - **General Topic** — natural language dispatcher that routes tasks to the right agent
45
+ - **Permission relay** — inline Telegram buttons for Allow/Deny with countdown + Always Allow
46
+ - **Voice messages** — Groq Whisper transcription, talk to your agents
47
+ - **Cost guard** per-instance daily spending limits with auto-pause
48
+ - **Hang detection** — auto-detect stuck sessions, notify with restart buttons
49
+ - **Model failover** auto-switch to backup model on rate limits
50
+ - **Daily summary** — fleet cost report posted to Telegram
51
+ - **External sessions** connect local Claude Code to the fleet via IPC
52
+ - **Discord adapter** use Discord instead of (or alongside) Telegram
53
+ - **Health endpoint** — HTTP API for external monitoring
54
+ - **Webhook notifications** push events to Slack or custom endpoints
55
+ - **System service** — one command to install as launchd/systemd service
510
56
 
511
57
  ## Requirements
512
58
 
@@ -514,43 +60,19 @@ GROQ_API_KEY=gsk_... # optional, for voice transcription
514
60
  - tmux
515
61
  - Claude Code CLI (`claude`)
516
62
  - Telegram bot token ([@BotFather](https://t.me/BotFather))
517
- - Groq API key (optional, for voice transcription)
518
-
519
- ## Security considerations
520
-
521
- Running Claude Code remotely via Telegram changes the trust model compared to sitting at a terminal. Be aware of the following:
522
-
523
- ### Telegram account = shell access
524
-
525
- Any user in `allowed_users` can instruct Claude to run arbitrary shell commands on the host machine. If your Telegram account is compromised (stolen session, social engineering, borrowed phone), the attacker effectively has shell access. Mitigations:
526
-
527
- - Enable Telegram 2FA
528
- - Keep `allowed_users` minimal
529
- - Use `pairing` mode instead of pre-configuring user IDs when possible
530
- - Review the Claude Code permission allow/deny lists in `claude-settings.json`
531
-
532
- ### Permission bypass (`skipPermissions`)
533
-
534
- The `skipPermissions` config option passes `--dangerously-skip-permissions` to Claude Code, which disables all tool-use permission prompts. This means Claude can read/write any file, run any command, and make network requests without asking. This is Claude Code's official flag for automation scenarios, but in a remote Telegram context it means **zero human-in-the-loop for any operation**. Only enable this if you fully trust the deployment environment.
535
-
536
- ### `Bash(*)` in the allow list
537
-
538
- By default (when `skipPermissions` is false), ccd configures `Bash(*)` in Claude Code's permission allow list so that shell commands don't require individual approval. The deny list blocks a few destructive patterns (`rm -rf /`, `dd`, `mkfs`), but this is a blocklist — it cannot cover all dangerous commands. This matches Claude Code's own permission model, where `Bash(*)` is a supported power-user configuration.
539
-
540
- If you want tighter control, edit the `allow` list in `claude-settings.json` (generated per-instance in `~/.claude-channel-daemon/instances/<name>/`) to use specific patterns like `Bash(npm test)`, `Bash(git *)` instead of `Bash(*)`.
541
-
542
- ### IPC socket
543
-
544
- The daemon communicates with Claude's MCP server via a Unix socket at `~/.claude-channel-daemon/instances/<name>/channel.sock`. The socket is restricted to owner-only access (`0600`) and requires a shared secret handshake. These measures prevent other local processes from injecting messages, but do not protect against a compromised user account on the same machine.
63
+ - Groq API key (optional, for voice)
545
64
 
546
- ### Secrets storage
65
+ ## Documentation
547
66
 
548
- Bot tokens and API keys are stored in plaintext at `~/.claude-channel-daemon/.env`. The `ccd export` command includes this file and warns about secure transfer. Consider filesystem encryption if the host is shared.
67
+ - [Features](docs/features.md) detailed feature documentation
68
+ - [CLI Reference](docs/cli.md) — all commands and options
69
+ - [Configuration](docs/configuration.md) — fleet.yaml, .env, data directory
70
+ - [Security](SECURITY.md) — trust model and hardening
549
71
 
550
72
  ## Known limitations
551
73
 
552
- - Only tested on macOS
553
- - Official telegram plugin in global `enabledPlugins` causes 409 polling conflicts (daemon retries with backoff)
74
+ - macOS (launchd) and Linux (systemd) supported; Windows is not
75
+ - Official Telegram plugin in global `enabledPlugins` causes 409 polling conflicts
554
76
 
555
77
  ## License
556
78