@songsid/agend 0.0.1
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.
- package/README.md +210 -0
- package/README.zh-TW.md +134 -0
- package/dist/access-path.d.ts +10 -0
- package/dist/access-path.js +32 -0
- package/dist/access-path.js.map +1 -0
- package/dist/adapter-world.d.ts +25 -0
- package/dist/adapter-world.js +41 -0
- package/dist/adapter-world.js.map +1 -0
- package/dist/agent-cli-instructions.md +50 -0
- package/dist/agent-cli.d.ts +2 -0
- package/dist/agent-cli.js +200 -0
- package/dist/agent-cli.js.map +1 -0
- package/dist/agent-endpoint.d.ts +25 -0
- package/dist/agent-endpoint.js +162 -0
- package/dist/agent-endpoint.js.map +1 -0
- package/dist/backend/antigravity.d.ts +17 -0
- package/dist/backend/antigravity.js +98 -0
- package/dist/backend/antigravity.js.map +1 -0
- package/dist/backend/claude-code.d.ts +23 -0
- package/dist/backend/claude-code.js +171 -0
- package/dist/backend/claude-code.js.map +1 -0
- package/dist/backend/codex.d.ts +18 -0
- package/dist/backend/codex.js +160 -0
- package/dist/backend/codex.js.map +1 -0
- package/dist/backend/factory.d.ts +2 -0
- package/dist/backend/factory.js +28 -0
- package/dist/backend/factory.js.map +1 -0
- package/dist/backend/gemini-cli.d.ts +17 -0
- package/dist/backend/gemini-cli.js +163 -0
- package/dist/backend/gemini-cli.js.map +1 -0
- package/dist/backend/index.d.ts +7 -0
- package/dist/backend/index.js +7 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/kiro.d.ts +17 -0
- package/dist/backend/kiro.js +147 -0
- package/dist/backend/kiro.js.map +1 -0
- package/dist/backend/marker-utils.d.ts +13 -0
- package/dist/backend/marker-utils.js +64 -0
- package/dist/backend/marker-utils.js.map +1 -0
- package/dist/backend/mock.d.ts +25 -0
- package/dist/backend/mock.js +85 -0
- package/dist/backend/mock.js.map +1 -0
- package/dist/backend/opencode.d.ts +16 -0
- package/dist/backend/opencode.js +136 -0
- package/dist/backend/opencode.js.map +1 -0
- package/dist/backend/types.d.ts +86 -0
- package/dist/backend/types.js +33 -0
- package/dist/backend/types.js.map +1 -0
- package/dist/channel/access-manager.d.ts +18 -0
- package/dist/channel/access-manager.js +153 -0
- package/dist/channel/access-manager.js.map +1 -0
- package/dist/channel/adapters/telegram.d.ts +63 -0
- package/dist/channel/adapters/telegram.js +646 -0
- package/dist/channel/adapters/telegram.js.map +1 -0
- package/dist/channel/attachment-handler.d.ts +15 -0
- package/dist/channel/attachment-handler.js +88 -0
- package/dist/channel/attachment-handler.js.map +1 -0
- package/dist/channel/factory.d.ts +12 -0
- package/dist/channel/factory.js +67 -0
- package/dist/channel/factory.js.map +1 -0
- package/dist/channel/ipc-bridge.d.ts +26 -0
- package/dist/channel/ipc-bridge.js +220 -0
- package/dist/channel/ipc-bridge.js.map +1 -0
- package/dist/channel/mcp-server.d.ts +10 -0
- package/dist/channel/mcp-server.js +288 -0
- package/dist/channel/mcp-server.js.map +1 -0
- package/dist/channel/mcp-tools.d.ts +17 -0
- package/dist/channel/mcp-tools.js +110 -0
- package/dist/channel/mcp-tools.js.map +1 -0
- package/dist/channel/message-bus.d.ts +17 -0
- package/dist/channel/message-bus.js +86 -0
- package/dist/channel/message-bus.js.map +1 -0
- package/dist/channel/message-queue.d.ts +39 -0
- package/dist/channel/message-queue.js +253 -0
- package/dist/channel/message-queue.js.map +1 -0
- package/dist/channel/tool-router.d.ts +6 -0
- package/dist/channel/tool-router.js +75 -0
- package/dist/channel/tool-router.js.map +1 -0
- package/dist/channel/tool-tracker.d.ts +13 -0
- package/dist/channel/tool-tracker.js +58 -0
- package/dist/channel/tool-tracker.js.map +1 -0
- package/dist/channel/types.d.ts +118 -0
- package/dist/channel/types.js +2 -0
- package/dist/channel/types.js.map +1 -0
- package/dist/chat-export.d.ts +4 -0
- package/dist/chat-export.js +91 -0
- package/dist/chat-export.js.map +1 -0
- package/dist/classic-channel-manager.d.ts +59 -0
- package/dist/classic-channel-manager.js +193 -0
- package/dist/classic-channel-manager.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +1833 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +9 -0
- package/dist/config.js +118 -0
- package/dist/config.js.map +1 -0
- package/dist/context-guardian.d.ts +26 -0
- package/dist/context-guardian.js +73 -0
- package/dist/context-guardian.js.map +1 -0
- package/dist/cost-guard.d.ts +36 -0
- package/dist/cost-guard.js +147 -0
- package/dist/cost-guard.js.map +1 -0
- package/dist/daemon-entry.d.ts +1 -0
- package/dist/daemon-entry.js +29 -0
- package/dist/daemon-entry.js.map +1 -0
- package/dist/daemon.d.ts +152 -0
- package/dist/daemon.js +1714 -0
- package/dist/daemon.js.map +1 -0
- package/dist/daily-summary.d.ts +13 -0
- package/dist/daily-summary.js +55 -0
- package/dist/daily-summary.js.map +1 -0
- package/dist/event-log.d.ts +36 -0
- package/dist/event-log.js +100 -0
- package/dist/event-log.js.map +1 -0
- package/dist/export-import.d.ts +2 -0
- package/dist/export-import.js +162 -0
- package/dist/export-import.js.map +1 -0
- package/dist/fleet-context.d.ts +61 -0
- package/dist/fleet-context.js +4 -0
- package/dist/fleet-context.js.map +1 -0
- package/dist/fleet-dashboard-html.d.ts +6 -0
- package/dist/fleet-dashboard-html.js +443 -0
- package/dist/fleet-dashboard-html.js.map +1 -0
- package/dist/fleet-health-server.d.ts +35 -0
- package/dist/fleet-health-server.js +290 -0
- package/dist/fleet-health-server.js.map +1 -0
- package/dist/fleet-instructions.d.ts +5 -0
- package/dist/fleet-instructions.js +161 -0
- package/dist/fleet-instructions.js.map +1 -0
- package/dist/fleet-manager.d.ts +212 -0
- package/dist/fleet-manager.js +3655 -0
- package/dist/fleet-manager.js.map +1 -0
- package/dist/fleet-rpc-handlers.d.ts +42 -0
- package/dist/fleet-rpc-handlers.js +356 -0
- package/dist/fleet-rpc-handlers.js.map +1 -0
- package/dist/fleet-system-prompt.d.ts +11 -0
- package/dist/fleet-system-prompt.js +61 -0
- package/dist/fleet-system-prompt.js.map +1 -0
- package/dist/general-knowledge/skills.md +177 -0
- package/dist/hang-detector.d.ts +16 -0
- package/dist/hang-detector.js +53 -0
- package/dist/hang-detector.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/instance-lifecycle.d.ts +90 -0
- package/dist/instance-lifecycle.js +592 -0
- package/dist/instance-lifecycle.js.map +1 -0
- package/dist/instructions.d.ts +15 -0
- package/dist/instructions.js +90 -0
- package/dist/instructions.js.map +1 -0
- package/dist/logger.d.ts +7 -0
- package/dist/logger.js +84 -0
- package/dist/logger.js.map +1 -0
- package/dist/outbound-handlers.d.ts +51 -0
- package/dist/outbound-handlers.js +739 -0
- package/dist/outbound-handlers.js.map +1 -0
- package/dist/outbound-schemas.d.ts +238 -0
- package/dist/outbound-schemas.js +248 -0
- package/dist/outbound-schemas.js.map +1 -0
- package/dist/paths.d.ts +10 -0
- package/dist/paths.js +42 -0
- package/dist/paths.js.map +1 -0
- package/dist/plugin/agend/.claude-plugin/plugin.json +5 -0
- package/dist/quickstart.d.ts +1 -0
- package/dist/quickstart.js +595 -0
- package/dist/quickstart.js.map +1 -0
- package/dist/routing-engine.d.ts +22 -0
- package/dist/routing-engine.js +44 -0
- package/dist/routing-engine.js.map +1 -0
- package/dist/safe-async.d.ts +6 -0
- package/dist/safe-async.js +20 -0
- package/dist/safe-async.js.map +1 -0
- package/dist/scheduler/db.d.ts +37 -0
- package/dist/scheduler/db.js +360 -0
- package/dist/scheduler/db.js.map +1 -0
- package/dist/scheduler/db.test.d.ts +1 -0
- package/dist/scheduler/db.test.js +92 -0
- package/dist/scheduler/db.test.js.map +1 -0
- package/dist/scheduler/index.d.ts +4 -0
- package/dist/scheduler/index.js +4 -0
- package/dist/scheduler/index.js.map +1 -0
- package/dist/scheduler/scheduler.d.ts +44 -0
- package/dist/scheduler/scheduler.js +197 -0
- package/dist/scheduler/scheduler.js.map +1 -0
- package/dist/scheduler/scheduler.test.d.ts +1 -0
- package/dist/scheduler/scheduler.test.js +119 -0
- package/dist/scheduler/scheduler.test.js.map +1 -0
- package/dist/scheduler/types.d.ts +107 -0
- package/dist/scheduler/types.js +7 -0
- package/dist/scheduler/types.js.map +1 -0
- package/dist/service-installer.d.ts +17 -0
- package/dist/service-installer.js +182 -0
- package/dist/service-installer.js.map +1 -0
- package/dist/setup-wizard.d.ts +48 -0
- package/dist/setup-wizard.js +701 -0
- package/dist/setup-wizard.js.map +1 -0
- package/dist/statusline-watcher.d.ts +34 -0
- package/dist/statusline-watcher.js +73 -0
- package/dist/statusline-watcher.js.map +1 -0
- package/dist/stt.d.ts +10 -0
- package/dist/stt.js +33 -0
- package/dist/stt.js.map +1 -0
- package/dist/tmux-control.d.ts +52 -0
- package/dist/tmux-control.js +207 -0
- package/dist/tmux-control.js.map +1 -0
- package/dist/tmux-manager.d.ts +44 -0
- package/dist/tmux-manager.js +218 -0
- package/dist/tmux-manager.js.map +1 -0
- package/dist/topic-archiver.d.ts +40 -0
- package/dist/topic-archiver.js +103 -0
- package/dist/topic-archiver.js.map +1 -0
- package/dist/topic-commands.d.ts +28 -0
- package/dist/topic-commands.js +359 -0
- package/dist/topic-commands.js.map +1 -0
- package/dist/transcript-monitor.d.ts +23 -0
- package/dist/transcript-monitor.js +164 -0
- package/dist/transcript-monitor.js.map +1 -0
- package/dist/types.d.ts +211 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/ui/dashboard.html +719 -0
- package/dist/web-api.d.ts +101 -0
- package/dist/web-api.js +648 -0
- package/dist/web-api.js.map +1 -0
- package/dist/webhook-emitter.d.ts +15 -0
- package/dist/webhook-emitter.js +41 -0
- package/dist/webhook-emitter.js.map +1 -0
- package/dist/workflow-templates/default.md +35 -0
- package/package.json +76 -0
- package/templates/launchd.plist.ejs +31 -0
- package/templates/systemd.service.ejs +16 -0
package/README.md
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<h1 align="center">AgEnD</h1>
|
|
3
|
+
<p align="center">
|
|
4
|
+
<strong>Run a fleet of AI coding agents from your phone.</strong>
|
|
5
|
+
</p>
|
|
6
|
+
<p align="center">
|
|
7
|
+
<a href="https://www.npmjs.com/package/@suzuke/agend"><img src="https://img.shields.io/npm/v/@suzuke/agend" alt="npm"></a>
|
|
8
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT"></a>
|
|
9
|
+
<a href="https://nodejs.org"><img src="https://img.shields.io/badge/Node.js-%3E%3D%2020-green.svg" alt="Node.js >= 20"></a>
|
|
10
|
+
</p>
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
AgEnD (**Agent Engineering Daemon**) turns your Telegram or Discord into a command center for AI coding agents. One bot, multiple CLI backends, unlimited projects — each running as an independent session with crash recovery and zero babysitting.
|
|
14
|
+
|
|
15
|
+
<p align="center">
|
|
16
|
+
<code>You → Telegram/Discord → AgEnD → Fleet of AI Agents → Results back to your phone</code>
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
[繁體中文](README.zh-TW.md) · [Documentation](docs/features.md) · [CLI Reference](docs/cli.md)
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Why AgEnD?
|
|
24
|
+
|
|
25
|
+
| Without AgEnD | With AgEnD |
|
|
26
|
+
|---|---|
|
|
27
|
+
| Close the terminal, agent goes offline | Runs as a system service — survives reboots |
|
|
28
|
+
| One terminal = one project | One bot, unlimited projects running in parallel |
|
|
29
|
+
| Long-running sessions accumulate stale context | CLI auto-compact + crash recovery with context snapshots |
|
|
30
|
+
| No idea what your agents are doing overnight | Daily cost reports + hang detection alerts |
|
|
31
|
+
| Agents work in silos, can't coordinate | Peer-to-peer collaboration via MCP tools |
|
|
32
|
+
| Runaway costs from unattended sessions | Per-instance daily spending limits with auto-pause |
|
|
33
|
+
|
|
34
|
+
## Feature Highlights
|
|
35
|
+
|
|
36
|
+
🚀 **Fleet Management** — One bot, N projects. Each Telegram Forum Topic is an isolated agent session.
|
|
37
|
+
|
|
38
|
+
🔄 **Multi-Backend** — Claude Code, Gemini CLI, Codex, OpenCode, Kiro CLI. Switch or mix freely.
|
|
39
|
+
|
|
40
|
+
🤝 **Agent Collaboration** — Agents discover, wake, and message each other via MCP tools. A General Topic routes tasks to the right agent using natural language.
|
|
41
|
+
|
|
42
|
+
📱 **Mobile Control** — Approve tool use, restart sessions, and manage your fleet from Telegram inline buttons.
|
|
43
|
+
|
|
44
|
+
🛡️ **Autonomous & Safe** — Cost guards, hang detection, model failover, and crash recovery keep your fleet running without babysitting.
|
|
45
|
+
|
|
46
|
+
⏰ **Persistent Schedules** — Cron-based tasks backed by SQLite. Survives restarts.
|
|
47
|
+
|
|
48
|
+
🎤 **Voice Messages** — Talk to your agents with Groq Whisper transcription.
|
|
49
|
+
|
|
50
|
+
📄 **HTML Chat Export** — Export any agent session as a self-contained HTML file for sharing or archiving.
|
|
51
|
+
|
|
52
|
+
🪞 **Mirror Topic** — Cross-instance visibility. Watch another agent's work in real time from a separate topic.
|
|
53
|
+
|
|
54
|
+
🖥️ **Web Dashboard** — Live fleet monitoring in the browser with SSE updates and integrated chat UI.
|
|
55
|
+
|
|
56
|
+
🔌 **Extensible** — Discord adapter, webhook notifications, health endpoint, external session support via IPC.
|
|
57
|
+
|
|
58
|
+
👥 **Teams & Task Board** — Named groups for targeted broadcasting. Shared task board for multi-step work tracking across instances.
|
|
59
|
+
|
|
60
|
+
📋 **Fleet Templates** — Define reusable fleet configurations. Deploy multi-instance setups with one command, each with its own git worktree.
|
|
61
|
+
|
|
62
|
+
## Quick Start
|
|
63
|
+
|
|
64
|
+
One-liner (macOS / Linux — installs Node.js via nvm + tmux + agend, then runs quickstart):
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
curl -fsSL https://suzuke.github.io/AgEnD/install.sh | bash
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Or install manually:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# Option A: One-line install (Linux / macOS / WSL)
|
|
74
|
+
curl -fsSL https://suzuke.github.io/AgEnD/install.sh | bash
|
|
75
|
+
|
|
76
|
+
# Option B: Manual install
|
|
77
|
+
npm install -g @suzuke/agend # 1. Install
|
|
78
|
+
agend quickstart # 2. Setup — bot token, backend, done
|
|
79
|
+
agend fleet start # 3. Launch your fleet 🎉
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Open Telegram, send a message to your bot, and start coding from your phone.
|
|
83
|
+
|
|
84
|
+
> **Discord?** `agend quickstart` supports Discord too — install the plugin first: `npm install -g @suzuke/agend-plugin-discord`. See [Discord setup guide](docs/features.md#discord-adapter-mvp).
|
|
85
|
+
|
|
86
|
+
## How It Works
|
|
87
|
+
|
|
88
|
+
```mermaid
|
|
89
|
+
graph LR
|
|
90
|
+
You["You<br/>(Phone / PC)"] <-->|messages| Channel["Telegram / Discord<br/>/ Web UI"]
|
|
91
|
+
Channel <-->|routing| Daemon["AgEnD Daemon"]
|
|
92
|
+
|
|
93
|
+
subgraph Fleet
|
|
94
|
+
Daemon --> General["General<br/>Dispatcher"]
|
|
95
|
+
Daemon --> A["Instance A<br/>Claude Code<br/>Project X"]
|
|
96
|
+
Daemon --> B["Instance B<br/>Gemini CLI<br/>Project Y"]
|
|
97
|
+
A <-.->|MCP Tools| B
|
|
98
|
+
General -.->|routes tasks| A
|
|
99
|
+
General -.->|routes tasks| B
|
|
100
|
+
end
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
1. **You send a message** to your Telegram/Discord bot
|
|
104
|
+
2. Messages sent to the **General Topic** are interpreted and routed to the right agent. Messages to a specific topic go directly to that instance.
|
|
105
|
+
3. **Agent instances** run in isolated tmux sessions, each with its own project and CLI backend
|
|
106
|
+
4. **Agents collaborate** peer-to-peer via MCP tools — delegating tasks, sharing context, reporting results
|
|
107
|
+
5. **Results flow back** to your chat. Permission requests arrive as inline buttons.
|
|
108
|
+
|
|
109
|
+
## Supported Backends
|
|
110
|
+
|
|
111
|
+
| Backend | Install | Auth |
|
|
112
|
+
|---------|---------|------|
|
|
113
|
+
| Claude Code | `curl -fsSL https://claude.ai/install.sh \| bash` | `claude` (OAuth) or `ANTHROPIC_API_KEY` |
|
|
114
|
+
| OpenAI Codex | `npm i -g @openai/codex` | `codex` (ChatGPT login) or `OPENAI_API_KEY` |
|
|
115
|
+
| Gemini CLI | `npm i -g @google/gemini-cli` | `gemini` (Google OAuth) |
|
|
116
|
+
| OpenCode | `curl -fsSL https://opencode.ai/install \| bash` | `opencode` (configure provider) |
|
|
117
|
+
| Kiro CLI | `brew install --cask kiro-cli` | `kiro-cli login` (AWS Builder ID) |
|
|
118
|
+
|
|
119
|
+
## Requirements
|
|
120
|
+
|
|
121
|
+
- Node.js >= 20
|
|
122
|
+
- tmux
|
|
123
|
+
- One of the supported AI coding CLIs (installed and authenticated)
|
|
124
|
+
- Telegram bot token ([@BotFather](https://t.me/BotFather)) or Discord bot token
|
|
125
|
+
- Groq API key (optional, for voice)
|
|
126
|
+
|
|
127
|
+
> **⚠️** All CLI backends run with `--dangerously-skip-permissions` (or equivalent). See [Security](SECURITY.md).
|
|
128
|
+
|
|
129
|
+
> **WSL (Windows Subsystem for Linux):** Fully supported. The install script auto-detects WSL and avoids using Windows `node.exe` from PATH. If you encounter PATH issues, add to `/etc/wsl.conf`:
|
|
130
|
+
> ```ini
|
|
131
|
+
> [interop]
|
|
132
|
+
> appendWindowsPath=false
|
|
133
|
+
> ```
|
|
134
|
+
> Then restart WSL (`wsl --shutdown`). Install with: `curl -fsSL https://suzuke.github.io/AgEnD/install.sh | bash`
|
|
135
|
+
|
|
136
|
+
## Documentation
|
|
137
|
+
|
|
138
|
+
- [Features](docs/features.md) — detailed feature documentation
|
|
139
|
+
- [CLI Reference](docs/cli.md) — all commands and options
|
|
140
|
+
- [Configuration](docs/configuration.md) — fleet.yaml complete reference
|
|
141
|
+
- [Security](SECURITY.md) — trust model and hardening
|
|
142
|
+
|
|
143
|
+
## Discord ClassicBot
|
|
144
|
+
|
|
145
|
+
ClassicBot lets users start AI agents in any Discord text channel using slash commands — no forum topics required.
|
|
146
|
+
|
|
147
|
+
### Setup
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
# 1. Install Discord plugin
|
|
151
|
+
npm install -g @suzuke/agend-plugin-discord
|
|
152
|
+
|
|
153
|
+
# 2. Run quickstart (select Discord)
|
|
154
|
+
agend quickstart
|
|
155
|
+
|
|
156
|
+
# 3. Start the fleet
|
|
157
|
+
agend fleet start
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
The quickstart will set up both `fleet.yaml` and `classicBot.yaml`. Run `agend quickstart` again to add users or guilds to existing config.
|
|
161
|
+
|
|
162
|
+
### Usage
|
|
163
|
+
|
|
164
|
+
| Command | Description |
|
|
165
|
+
|---------|-------------|
|
|
166
|
+
| `/start` | Start an agent in the current channel |
|
|
167
|
+
| `/chat <message>` | Send a message to the agent |
|
|
168
|
+
| `/stop` | Stop the agent in the current channel |
|
|
169
|
+
|
|
170
|
+
### Server Whitelist
|
|
171
|
+
|
|
172
|
+
Control which Discord servers can use ClassicBot via `~/.agend/classicBot.yaml`:
|
|
173
|
+
|
|
174
|
+
```yaml
|
|
175
|
+
defaults:
|
|
176
|
+
backend: claude-code
|
|
177
|
+
allowed_guilds: # Only these servers can /start
|
|
178
|
+
- "1496855124440780912"
|
|
179
|
+
- "9876543210123456789"
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
- **Empty or omitted** `allowed_guilds` → all servers allowed (default)
|
|
183
|
+
- **Primary guild** (fleet.yaml `group_id`) → full access (topic mode + ClassicBot)
|
|
184
|
+
- **Whitelisted guilds** → ClassicBot only (`/start`, `/chat`, `/stop`)
|
|
185
|
+
- **Hot reload** — changes detected every 30 seconds, no restart needed
|
|
186
|
+
|
|
187
|
+
### Per-Channel Backend
|
|
188
|
+
|
|
189
|
+
Override the backend for specific channels:
|
|
190
|
+
|
|
191
|
+
```yaml
|
|
192
|
+
defaults:
|
|
193
|
+
backend: claude-code
|
|
194
|
+
channels:
|
|
195
|
+
"1234567890": # Discord channel ID
|
|
196
|
+
name: dev-help
|
|
197
|
+
backend: gemini-cli # Override for this channel
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Backend fallback: channel → `defaults.backend` → `fleet.yaml` defaults → `claude-code`
|
|
201
|
+
|
|
202
|
+
## Known Limitations
|
|
203
|
+
|
|
204
|
+
- macOS (launchd) and Linux (systemd) supported; Windows is not
|
|
205
|
+
- Official Telegram plugin in global `enabledPlugins` causes 409 polling conflicts
|
|
206
|
+
- OpenCode and Kiro CLI do not read MCP server `instructions` field — fleet context and workflow templates are not injected into these backends' system prompts. Awaiting upstream fix.
|
|
207
|
+
|
|
208
|
+
## License
|
|
209
|
+
|
|
210
|
+
MIT
|
package/README.zh-TW.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<h1 align="center">AgEnD</h1>
|
|
3
|
+
<p align="center">
|
|
4
|
+
<strong>用手機管理一整個 AI coding agent 團隊。</strong>
|
|
5
|
+
</p>
|
|
6
|
+
<p align="center">
|
|
7
|
+
<a href="https://www.npmjs.com/package/@suzuke/agend"><img src="https://img.shields.io/npm/v/@suzuke/agend" alt="npm"></a>
|
|
8
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT"></a>
|
|
9
|
+
<a href="https://nodejs.org"><img src="https://img.shields.io/badge/Node.js-%3E%3D%2020-green.svg" alt="Node.js >= 20"></a>
|
|
10
|
+
</p>
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
AgEnD(**Agent Engineering Daemon**)把你的 Telegram 或 Discord 變成 AI coding agent 的指揮中心。一個 bot,多種 CLI 後端,無限專案 — 每個都是獨立 session,crash 自動恢復,不用顧。
|
|
14
|
+
|
|
15
|
+
<p align="center">
|
|
16
|
+
<code>你 → Telegram/Discord → AgEnD → AI Agent 團隊 → 結果回到你的手機</code>
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
[English](README.md) · [功能文件](docs/features.md) · [CLI 參考](docs/cli.md)
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 為什麼用 AgEnD?
|
|
24
|
+
|
|
25
|
+
| 沒有 AgEnD | 有 AgEnD |
|
|
26
|
+
|---|---|
|
|
27
|
+
| 關掉終端機,agent 就斷線 | 系統服務常駐,重開機也不怕 |
|
|
28
|
+
| 一個終端機 = 一個專案 | 一個 bot,無限專案同時跑 |
|
|
29
|
+
| 長時間 session 累積過時 context | 依 max age 自動輪替 session,保持新鮮 |
|
|
30
|
+
| 不知道 agent 半夜在幹嘛 | 每日花費報告 + 卡住偵測通知 |
|
|
31
|
+
| Agent 各做各的,無法協作 | 點對點協作,透過 MCP tools |
|
|
32
|
+
| 無人看管時帳單暴增 | 每個 instance 每日花費上限,自動暫停 |
|
|
33
|
+
|
|
34
|
+
## 功能亮點
|
|
35
|
+
|
|
36
|
+
🚀 **Fleet 管理** — 一個 bot、N 個專案。每個 Telegram Forum Topic 就是獨立的 agent session。
|
|
37
|
+
|
|
38
|
+
🔄 **多後端支援** — Claude Code、Gemini CLI、Codex、OpenCode、Kiro CLI,自由切換或混用。
|
|
39
|
+
|
|
40
|
+
🤝 **Agent 協作** — Agent 之間透過 MCP tools 互相發現、喚醒、傳訊。General Topic 用自然語言把任務路由到對的 agent。
|
|
41
|
+
|
|
42
|
+
📱 **手機操控** — 從 Telegram inline 按鈕核准工具使用、重啟 session、管理整個 fleet。
|
|
43
|
+
|
|
44
|
+
🛡️ **自主又安全** — 花費上限、卡住偵測、model failover、context 輪替,fleet 不用顧也能穩穩跑。
|
|
45
|
+
|
|
46
|
+
⏰ **持久化排程** — cron 排程任務,SQLite 儲存,重啟不遺失。
|
|
47
|
+
|
|
48
|
+
🎤 **語音訊息** — 用 Groq Whisper 轉文字,用說的跟 agent 溝通。
|
|
49
|
+
|
|
50
|
+
📄 **HTML 對話匯出** — 把任何 agent session 匯出成獨立 HTML 檔,方便分享或存檔。
|
|
51
|
+
|
|
52
|
+
🪞 **Mirror Topic** — 跨 instance 可見性。從另一個 topic 即時觀看其他 agent 的工作。
|
|
53
|
+
|
|
54
|
+
🖥️ **Web Dashboard** — 瀏覽器即時 fleet 監控,SSE 更新 + 整合聊天介面。
|
|
55
|
+
|
|
56
|
+
🔌 **可擴充** — Discord adapter、webhook 通知、health endpoint、外部 session 透過 IPC 連入。
|
|
57
|
+
|
|
58
|
+
## 開始用
|
|
59
|
+
|
|
60
|
+
一行安裝(macOS / Linux — 自動裝 Node.js(經 nvm)+ tmux + agend,完成後跑 quickstart):
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
curl -fsSL https://suzuke.github.io/AgEnD/install.sh | bash
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
或手動安裝:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npm install -g @suzuke/agend # 1. 安裝
|
|
70
|
+
agend quickstart # 2. 設定 — bot token、backend,搞定
|
|
71
|
+
agend fleet start # 3. 啟動 fleet 🎉
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
打開 Telegram,傳訊息給你的 bot,開始用手機寫 code。
|
|
75
|
+
|
|
76
|
+
## 運作原理
|
|
77
|
+
|
|
78
|
+
```mermaid
|
|
79
|
+
graph LR
|
|
80
|
+
You["你<br/>(手機 / 電腦)"] <-->|訊息| Channel["Telegram / Discord<br/>/ Web UI"]
|
|
81
|
+
Channel <-->|路由| Daemon["AgEnD Daemon"]
|
|
82
|
+
|
|
83
|
+
subgraph Fleet
|
|
84
|
+
Daemon --> General["General<br/>Dispatcher"]
|
|
85
|
+
Daemon --> A["Instance A<br/>Claude Code<br/>專案 X"]
|
|
86
|
+
Daemon --> B["Instance B<br/>Gemini CLI<br/>專案 Y"]
|
|
87
|
+
A <-.->|MCP Tools| B
|
|
88
|
+
General -.->|路由任務| A
|
|
89
|
+
General -.->|路由任務| B
|
|
90
|
+
end
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
1. **你傳訊息**給 Telegram/Discord bot
|
|
94
|
+
2. 傳到 **General Topic** 的訊息會被解讀並路由到對的 agent。傳到特定 topic 的訊息則直接送到該 instance。
|
|
95
|
+
3. **Agent instance** 在獨立的 tmux session 跑,各有自己的專案和 CLI 後端
|
|
96
|
+
4. **Agent 之間協作** — 透過 MCP tools 委派任務、分享 context、回報結果
|
|
97
|
+
5. **結果回傳**到你的聊天室。權限請求以 inline 按鈕呈現。
|
|
98
|
+
|
|
99
|
+
## 支援的後端
|
|
100
|
+
|
|
101
|
+
| Backend | 安裝 | 認證 |
|
|
102
|
+
|---------|------|------|
|
|
103
|
+
| Claude Code | `curl -fsSL https://claude.ai/install.sh \| bash` | `claude`(OAuth)或 `ANTHROPIC_API_KEY` |
|
|
104
|
+
| OpenAI Codex | `npm i -g @openai/codex` | `codex`(ChatGPT 登入)或 `OPENAI_API_KEY` |
|
|
105
|
+
| Gemini CLI | `npm i -g @google/gemini-cli` | `gemini`(Google OAuth) |
|
|
106
|
+
| OpenCode | `curl -fsSL https://opencode.ai/install \| bash` | `opencode`(設定 provider) |
|
|
107
|
+
| Kiro CLI | `brew install --cask kiro-cli` | `kiro-cli login`(AWS Builder ID) |
|
|
108
|
+
|
|
109
|
+
## 系統需求
|
|
110
|
+
|
|
111
|
+
- Node.js >= 20
|
|
112
|
+
- tmux
|
|
113
|
+
- 以下任一 AI coding CLI(需安裝並完成認證)
|
|
114
|
+
- Telegram bot token([@BotFather](https://t.me/BotFather))或 Discord bot token
|
|
115
|
+
- Groq API key(選用,語音轉文字用)
|
|
116
|
+
|
|
117
|
+
> **⚠️** 所有 CLI 後端都以 `--dangerously-skip-permissions`(或等效參數)執行。詳見 [Security](SECURITY.md)。
|
|
118
|
+
|
|
119
|
+
## 文件
|
|
120
|
+
|
|
121
|
+
- [Features](docs/features.md) — 功能詳細說明
|
|
122
|
+
- [CLI Reference](docs/cli.md) — 所有指令與選項
|
|
123
|
+
- [Configuration](docs/configuration.zh-TW.md) — fleet.yaml 完整設定參考
|
|
124
|
+
- [Security](SECURITY.md) — 信任模型與安全強化
|
|
125
|
+
|
|
126
|
+
## 已知限制
|
|
127
|
+
|
|
128
|
+
- 支援 macOS(launchd)和 Linux(systemd),不支援 Windows
|
|
129
|
+
- 全域 `enabledPlugins` 裡有官方 Telegram plugin 會造成 409 polling 衝突
|
|
130
|
+
- OpenCode 和 Kiro CLI 不讀取 MCP server 的 `instructions` 欄位 — fleet context 和 workflow template 不會注入到這些 backend 的 system prompt。等待上游修復。
|
|
131
|
+
|
|
132
|
+
## 授權
|
|
133
|
+
|
|
134
|
+
MIT
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the access.json path for an instance.
|
|
3
|
+
* Topic mode uses fleet-level access; otherwise per-instance.
|
|
4
|
+
*
|
|
5
|
+
* Throws if `instance` is not a safe path segment (per-instance mode only;
|
|
6
|
+
* topic mode does not embed `instance` in the returned path).
|
|
7
|
+
*/
|
|
8
|
+
export declare function resolveAccessPathFromConfig(dataDir: string, instance: string, fleetChannel: {
|
|
9
|
+
mode?: string;
|
|
10
|
+
} | undefined): string;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
/**
|
|
3
|
+
* Conservative whitelist for an instance name when it is going to be used as a
|
|
4
|
+
* path segment. Allows letters, digits, `_`, `-`, `.`. Empty / pure-`.` /
|
|
5
|
+
* pure-`..` is rejected so we cannot escape `dataDir/instances/`.
|
|
6
|
+
*
|
|
7
|
+
* Defence-in-depth: callers (CLI / fleet config loader) already constrain
|
|
8
|
+
* instance names, but `resolveAccessPathFromConfig` is invoked from several
|
|
9
|
+
* entry points and the consequence of a traversal here is reading or writing
|
|
10
|
+
* an attacker-supplied file path.
|
|
11
|
+
*/
|
|
12
|
+
const VALID_INSTANCE_NAME = /^[A-Za-z0-9._-]+$/;
|
|
13
|
+
function assertSafeInstanceName(instance) {
|
|
14
|
+
if (!VALID_INSTANCE_NAME.test(instance) || instance === "." || instance === "..") {
|
|
15
|
+
throw new Error(`Invalid instance name "${instance}" — must match ${VALID_INSTANCE_NAME}`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Resolve the access.json path for an instance.
|
|
20
|
+
* Topic mode uses fleet-level access; otherwise per-instance.
|
|
21
|
+
*
|
|
22
|
+
* Throws if `instance` is not a safe path segment (per-instance mode only;
|
|
23
|
+
* topic mode does not embed `instance` in the returned path).
|
|
24
|
+
*/
|
|
25
|
+
export function resolveAccessPathFromConfig(dataDir, instance, fleetChannel) {
|
|
26
|
+
if (fleetChannel?.mode === "topic") {
|
|
27
|
+
return join(dataDir, "access", "access.json");
|
|
28
|
+
}
|
|
29
|
+
assertSafeInstanceName(instance);
|
|
30
|
+
return join(dataDir, "instances", instance, "access.json");
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=access-path.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"access-path.js","sourceRoot":"","sources":["../src/access-path.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC;;;;;;;;;GASG;AACH,MAAM,mBAAmB,GAAG,mBAAmB,CAAC;AAEhD,SAAS,sBAAsB,CAAC,QAAgB;IAC9C,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,QAAQ,KAAK,GAAG,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACjF,MAAM,IAAI,KAAK,CAAC,0BAA0B,QAAQ,kBAAkB,mBAAmB,EAAE,CAAC,CAAC;IAC7F,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,2BAA2B,CACzC,OAAe,EACf,QAAgB,EAChB,YAA2C;IAE3C,IAAI,YAAY,EAAE,IAAI,KAAK,OAAO,EAAE,CAAC;QACnC,OAAO,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;IAChD,CAAC;IACD,sBAAsB,CAAC,QAAQ,CAAC,CAAC;IACjC,OAAO,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;AAC7D,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ChannelAdapter, SendOpts, SentMessage } from "./channel/types.js";
|
|
2
|
+
import type { AccessManager } from "./channel/access-manager.js";
|
|
3
|
+
import type { ChannelConfig } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* AdapterWorld encapsulates a single channel adapter with its associated
|
|
6
|
+
* access manager and config. Each platform (Telegram, Discord) gets its
|
|
7
|
+
* own world. Instances are bound to exactly one world.
|
|
8
|
+
*/
|
|
9
|
+
export declare class AdapterWorld {
|
|
10
|
+
readonly id: string;
|
|
11
|
+
readonly adapter: ChannelAdapter;
|
|
12
|
+
readonly accessManager: AccessManager;
|
|
13
|
+
readonly channelConfig: ChannelConfig;
|
|
14
|
+
botUsername?: string;
|
|
15
|
+
botUserId?: string;
|
|
16
|
+
constructor(id: string, adapter: ChannelAdapter, accessManager: AccessManager, channelConfig: ChannelConfig);
|
|
17
|
+
get groupId(): string;
|
|
18
|
+
get type(): string;
|
|
19
|
+
sendText(chatId: string, text: string, opts?: SendOpts): Promise<SentMessage>;
|
|
20
|
+
react(chatId: string, messageId: string, emoji: string): Promise<void>;
|
|
21
|
+
editMessage(chatId: string, messageId: string, text: string): Promise<void>;
|
|
22
|
+
downloadAttachment(fileId: string): Promise<string>;
|
|
23
|
+
isAllowed(userId: string | number): boolean;
|
|
24
|
+
stop(): Promise<void>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AdapterWorld encapsulates a single channel adapter with its associated
|
|
3
|
+
* access manager and config. Each platform (Telegram, Discord) gets its
|
|
4
|
+
* own world. Instances are bound to exactly one world.
|
|
5
|
+
*/
|
|
6
|
+
export class AdapterWorld {
|
|
7
|
+
id;
|
|
8
|
+
adapter;
|
|
9
|
+
accessManager;
|
|
10
|
+
channelConfig;
|
|
11
|
+
botUsername;
|
|
12
|
+
botUserId;
|
|
13
|
+
constructor(id, adapter, accessManager, channelConfig) {
|
|
14
|
+
this.id = id;
|
|
15
|
+
this.adapter = adapter;
|
|
16
|
+
this.accessManager = accessManager;
|
|
17
|
+
this.channelConfig = channelConfig;
|
|
18
|
+
}
|
|
19
|
+
get groupId() { return String(this.channelConfig.group_id ?? ""); }
|
|
20
|
+
get type() { return this.channelConfig.type; }
|
|
21
|
+
// ── Thin wrappers over adapter ──
|
|
22
|
+
sendText(chatId, text, opts) {
|
|
23
|
+
return this.adapter.sendText(chatId, text, opts);
|
|
24
|
+
}
|
|
25
|
+
react(chatId, messageId, emoji) {
|
|
26
|
+
return this.adapter.react(chatId, messageId, emoji);
|
|
27
|
+
}
|
|
28
|
+
editMessage(chatId, messageId, text) {
|
|
29
|
+
return this.adapter.editMessage(chatId, messageId, text);
|
|
30
|
+
}
|
|
31
|
+
downloadAttachment(fileId) {
|
|
32
|
+
return this.adapter.downloadAttachment(fileId);
|
|
33
|
+
}
|
|
34
|
+
isAllowed(userId) {
|
|
35
|
+
return this.accessManager.isAllowed(userId);
|
|
36
|
+
}
|
|
37
|
+
async stop() {
|
|
38
|
+
await this.adapter.stop();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=adapter-world.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter-world.js","sourceRoot":"","sources":["../src/adapter-world.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,MAAM,OAAO,YAAY;IAKZ;IACA;IACA;IACA;IAPX,WAAW,CAAU;IACrB,SAAS,CAAU;IAEnB,YACW,EAAU,EACV,OAAuB,EACvB,aAA4B,EAC5B,aAA4B;QAH5B,OAAE,GAAF,EAAE,CAAQ;QACV,YAAO,GAAP,OAAO,CAAgB;QACvB,kBAAa,GAAb,aAAa,CAAe;QAC5B,kBAAa,GAAb,aAAa,CAAe;IACpC,CAAC;IAEJ,IAAI,OAAO,KAAa,OAAO,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC3E,IAAI,IAAI,KAAa,OAAO,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;IAEtD,mCAAmC;IAEnC,QAAQ,CAAC,MAAc,EAAE,IAAY,EAAE,IAAe;QACpD,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACnD,CAAC;IAED,KAAK,CAAC,MAAc,EAAE,SAAiB,EAAE,KAAa;QACpD,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;IACtD,CAAC;IAED,WAAW,CAAC,MAAc,EAAE,SAAiB,EAAE,IAAY;QACzD,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IAC3D,CAAC;IAED,kBAAkB,CAAC,MAAc;QAC/B,OAAO,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;IACjD,CAAC;IAED,SAAS,CAAC,MAAuB;QAC/B,OAAO,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,IAAI;QACR,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;IAC5B,CAAC;CACF"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# AgEnD Agent CLI Reference
|
|
2
|
+
<!-- agend-cli instructions v1 -->
|
|
3
|
+
|
|
4
|
+
You are an agent managed by AgEnD. Use `agend-agent` commands in bash to communicate.
|
|
5
|
+
All commands output JSON.
|
|
6
|
+
|
|
7
|
+
## Message Types You Receive
|
|
8
|
+
|
|
9
|
+
1. **`[user:NAME via telegram] text`** — A human sent you a message.
|
|
10
|
+
Reply: `agend-agent reply "your response"`
|
|
11
|
+
|
|
12
|
+
2. **`[from:INSTANCE-NAME] text`** — Another agent sent you a message.
|
|
13
|
+
Reply: `agend-agent send INSTANCE-NAME "your response"`
|
|
14
|
+
|
|
15
|
+
3. **`[delegate_task] ...`** — You've been assigned a task.
|
|
16
|
+
When done: `agend-agent report REQUESTER "summary of results"`
|
|
17
|
+
|
|
18
|
+
## Quick Reference
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Communication
|
|
22
|
+
agend-agent reply "text" # Reply to user
|
|
23
|
+
agend-agent send TARGET "message" # Message another agent
|
|
24
|
+
agend-agent delegate TARGET "task" # Assign work
|
|
25
|
+
agend-agent report TARGET "summary" # Report results
|
|
26
|
+
agend-agent ask TARGET "question" # Request info
|
|
27
|
+
agend-agent broadcast "message" # Message all agents
|
|
28
|
+
|
|
29
|
+
# Instance Management
|
|
30
|
+
agend-agent list # List running agents
|
|
31
|
+
agend-agent describe NAME # Get agent details
|
|
32
|
+
agend-agent start NAME # Start stopped agent
|
|
33
|
+
|
|
34
|
+
# Task Board
|
|
35
|
+
agend-agent task create "title" # Create task
|
|
36
|
+
agend-agent task list # List tasks
|
|
37
|
+
agend-agent task claim ID # Claim task
|
|
38
|
+
agend-agent task done ID "result" # Complete task
|
|
39
|
+
|
|
40
|
+
# Decisions
|
|
41
|
+
agend-agent decision-post "title" "content" # Post decision
|
|
42
|
+
agend-agent decision-list # List decisions
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Rules
|
|
46
|
+
|
|
47
|
+
- `[user:... via telegram]` → use `agend-agent reply` (NOT `agend-agent send`)
|
|
48
|
+
- `[from:INSTANCE]` → use `agend-agent send` (NOT `agend-agent reply`)
|
|
49
|
+
- Task flow: `agend-agent delegate` → silent work → `agend-agent report`. Zero messages in between.
|
|
50
|
+
- Never send acknowledgment-only messages. Only send messages with actionable content.
|