From 56c7486e75103d82ced5a8fb7cc13f03cb1bb159 Mon Sep 17 00:00:00 2001 From: chaodu-agent Date: Thu, 30 Apr 2026 16:13:23 +0000 Subject: [PATCH 1/8] docs: add sendimages.md and sendfiles.md best practice guides Add two new docs for AI agents to send images and files back to Discord: - docs/sendimages.md: sender_context flow, curl/Python/Node examples, sidecar file-watcher pattern, security considerations - docs/sendfiles.md: single/multi-file upload, file size limits, enterprise best practice (S3 presigned URL pattern), common file types --- docs/sendfiles.md | 179 +++++++++++++++++++++++++++++++++++++++++++++ docs/sendimages.md | 132 +++++++++++++++++++++++++++++++++ 2 files changed, 311 insertions(+) create mode 100644 docs/sendfiles.md create mode 100644 docs/sendimages.md diff --git a/docs/sendfiles.md b/docs/sendfiles.md new file mode 100644 index 00000000..c9887112 --- /dev/null +++ b/docs/sendfiles.md @@ -0,0 +1,179 @@ +# Sending Files Back to Discord + +OpenAB streams text only — it does **not** relay file attachments from the agent. +To send a file back to the user, the agent must call the Discord API directly. + +> For image-specific guidance (formats, sidecar pattern), see [sendimages.md](sendimages.md). + +## How It Works + +``` +Agent produces file (code, PDF, CSV, zip, etc.) + → reads thread_id from sender_context + → POST /channels/{thread_id}/messages with file attachment + → file appears in the Discord thread +``` + +## Step-by-Step + +### 1. Get the Target Channel from `sender_context` + +Every message includes a `` JSON block: + +```json +{ + "schema": "openab.sender.v1", + "channel": "discord", + "channel_id": "1490282656913559673", + "thread_id": "1499442140172910654" +} +``` + +Use **`thread_id`** as the target. Fall back to `channel_id` if `thread_id` is absent. + +### 2. Upload the File + +``` +POST https://discord.com/api/v10/channels/{thread_id}/messages +Authorization: Bot {DISCORD_BOT_TOKEN} +Content-Type: multipart/form-data +``` + +#### curl example + +```bash +curl -X POST "https://discord.com/api/v10/channels/${THREAD_ID}/messages" \ + -H "Authorization: Bot ${DISCORD_BOT_TOKEN}" \ + -F "content=Here is the report" \ + -F "files[0]=@/path/to/report.pdf" +``` + +#### Multiple files + +Discord supports up to **10 attachments** per message: + +```bash +curl -X POST "https://discord.com/api/v10/channels/${THREAD_ID}/messages" \ + -H "Authorization: Bot ${DISCORD_BOT_TOKEN}" \ + -F "content=Build artifacts" \ + -F "files[0]=@build.log" \ + -F "files[1]=@coverage.html" +``` + +#### Python example + +```python +import os, requests + +def send_file(thread_id: str, file_path: str, message: str = ""): + url = f"https://discord.com/api/v10/channels/{thread_id}/messages" + headers = {"Authorization": f"Bot {os.environ['DISCORD_BOT_TOKEN']}"} + with open(file_path, "rb") as f: + requests.post(url, headers=headers, + data={"content": message}, + files={"files[0]": (os.path.basename(file_path), f)}) +``` + +#### Node.js example + +```javascript +const fs = require("fs"); +const FormData = require("form-data"); + +async function sendFile(threadId, filePath, message = "") { + const form = new FormData(); + form.append("content", message); + form.append("files[0]", fs.createReadStream(filePath)); + + await fetch(`https://discord.com/api/v10/channels/${threadId}/messages`, { + method: "POST", + headers: { Authorization: `Bot ${process.env.DISCORD_BOT_TOKEN}` }, + body: form, + }); +} +``` + +## File Size Limits + +| Server Boost Level | Max Upload | +|--------------------|------------| +| None | 25 MB | +| Level 2 | 50 MB | +| Level 3 | 100 MB | + +## Large Files & Enterprise Best Practice + +For enterprise use or files exceeding Discord's upload limit, the recommended pattern is: + +1. **Upload to external storage** — Amazon S3, Cloudflare R2, Google Drive, etc. using your own credentials. +2. **Generate a temporary link** — e.g. an [S3 presigned URL](https://docs.aws.amazon.com/AmazonS3/latest/userguide/ShareObjectPresignedURL.html) with a short TTL. +3. **Send the link back to Discord** — post the URL as a regular message in the thread. + +``` +Agent produces large file + → uploads to S3 bucket + → generates presigned URL (e.g. expires in 1 hour) + → sends URL as a Discord message in the thread +``` + +#### Why this is better for enterprise + +- **No file size limit** — S3/R2 handles files of any size. +- **Files stay off Discord** — you control where data lives, important for compliance and data governance. +- **You control the TTL** — the link expires on your terms; no permanent file sitting in a Discord CDN. + +#### S3 presigned URL example (Python) + +```python +import boto3 + +s3 = boto3.client("s3") + +# Upload +s3.upload_file("/path/to/report.pdf", "my-bucket", "reports/report.pdf") + +# Generate presigned URL (expires in 1 hour) +url = s3.generate_presigned_url( + "get_object", + Params={"Bucket": "my-bucket", "Key": "reports/report.pdf"}, + ExpiresIn=3600, +) + +# Then send `url` as a Discord message via the API +``` + +## Common File Types + +| Use Case | Typical Format | Notes | +|----------|---------------|-------| +| Code patches | `.diff`, `.patch` | Attach as file to avoid Discord's 2000-char limit | +| Logs | `.log`, `.txt` | Truncate or compress large logs | +| Reports | `.pdf`, `.csv`, `.html` | PDF renders a preview in Discord | +| Archives | `.zip`, `.tar.gz` | Bundle multiple files | + +## Security Considerations + +- **Never hardcode the bot token.** Read from `$DISCORD_BOT_TOKEN` or a mounted secret. +- **Validate file paths.** Sanitize any dynamically constructed paths to prevent path traversal. +- **Check file size** before uploading to avoid silent failures. +- **Sensitive content.** Do not send files containing secrets, credentials, or PII unless the user explicitly requests it. +- **Rate limits.** Discord enforces per-channel rate limits. Space uploads when sending multiple files. + +## Bot Permission Checklist + +Ensure your bot has these permissions in the [Discord Developer Portal](https://discord.com/developers/applications): + +- [x] `Send Messages` +- [x] `Send Messages in Threads` +- [x] `Attach Files` + +## FAQ + +**Q: Can OpenAB relay files natively?** +A: Not currently. OpenAB streams text via ACP JSON-RPC. File sending is done out-of-band by the agent. + +**Q: What if the file is too large?** +A: Use the [Large Files & Enterprise Best Practice](#large-files--enterprise-best-practice) pattern — upload to S3/R2/Google Drive, generate a temporary link, and send the URL in the message. + +**Q: Does this work with Slack / Telegram / LINE?** +A: Same concept — call the platform's file upload API using the channel ID from `sender_context`. API details differ per platform. For Slack, use [`files.upload`](https://api.slack.com/methods/files.upload). For Telegram, use [`sendDocument`](https://core.telegram.org/bots/api#senddocument). diff --git a/docs/sendimages.md b/docs/sendimages.md new file mode 100644 index 00000000..cd2b92db --- /dev/null +++ b/docs/sendimages.md @@ -0,0 +1,132 @@ +# Sending Images Back to Discord + +OpenAB does **not** relay images from the agent to Discord — it only streams text. +To send an image back to the user, the agent must call the Discord API directly. + +## How It Works + +``` +Agent generates image → saves to local file + → reads thread_id from sender_context + → POST /channels/{thread_id}/messages with image attachment + → image appears in the Discord thread +``` + +## Step-by-Step + +### 1. Get the Target Channel from `sender_context` + +Every message from OpenAB includes a `` JSON block: + +```json +{ + "schema": "openab.sender.v1", + "sender_id": "845835116920307722", + "sender_name": "pahud.hsieh", + "display_name": "pahud.hsieh", + "channel": "discord", + "channel_id": "1490282656913559673", + "thread_id": "1499442140172910654", + "is_bot": false +} +``` + +Use **`thread_id`** as the target channel. If `thread_id` is absent, fall back to `channel_id`. + +### 2. Get the Bot Token + +The Discord Bot Token is available via the `DISCORD_BOT_TOKEN` environment variable +(same token OpenAB uses). Your agent code can read it from the environment. + +### 3. Upload the Image + +Use the Discord [Create Message](https://discord.com/developers/docs/resources/message#create-message) endpoint with a `multipart/form-data` body: + +``` +POST https://discord.com/api/v10/channels/{thread_id}/messages +Authorization: Bot {DISCORD_BOT_TOKEN} +Content-Type: multipart/form-data +``` + +#### curl example + +```bash +curl -X POST "https://discord.com/api/v10/channels/${THREAD_ID}/messages" \ + -H "Authorization: Bot ${DISCORD_BOT_TOKEN}" \ + -F "content=Here is the generated image" \ + -F "files[0]=@/path/to/image.png" +``` + +#### Python example + +```python +import os, requests + +def send_image(thread_id: str, image_path: str, message: str = ""): + url = f"https://discord.com/api/v10/channels/{thread_id}/messages" + headers = {"Authorization": f"Bot {os.environ['DISCORD_BOT_TOKEN']}"} + with open(image_path, "rb") as f: + requests.post(url, headers=headers, + data={"content": message}, + files={"files[0]": (os.path.basename(image_path), f)}) +``` + +#### Node.js example + +```javascript +const fs = require("fs"); +const FormData = require("form-data"); + +async function sendImage(threadId, imagePath, message = "") { + const form = new FormData(); + form.append("content", message); + form.append("files[0]", fs.createReadStream(imagePath)); + + await fetch(`https://discord.com/api/v10/channels/${threadId}/messages`, { + method: "POST", + headers: { Authorization: `Bot ${process.env.DISCORD_BOT_TOKEN}` }, + body: form, + }); +} +``` + +## Automated Sidecar Pattern + +If your agent generates images to a known directory (e.g. Codex writes to +`~/.codex/generated_images/`), you can run a **file-watcher sidecar** that +automatically uploads new images: + +1. Watch the output directory for new files. +2. Read the session metadata to find the originating `thread_id`. +3. Upload via the Discord API. +4. Track uploaded files in a state file to avoid duplicates. + +This is the pattern used by the community `discord-image-uploader` sidecar. + +## Security Considerations + +- **Never hardcode the bot token.** Read it from `$DISCORD_BOT_TOKEN` or a mounted secret. +- **Scope permissions.** The bot only needs `Send Messages` and `Attach Files` in the target channels. +- **Validate file paths.** If the agent constructs paths dynamically, sanitize them to prevent path traversal. +- **Rate limits.** Discord enforces rate limits on message creation. Space uploads if sending multiple images. + +## Bot Permission Checklist + +In the [Discord Developer Portal](https://discord.com/developers/applications), ensure your bot has: + +- [x] `Send Messages` +- [x] `Send Messages in Threads` +- [x] `Attach Files` + +These are typically already granted if your bot works with OpenAB. + +## FAQ + +**Q: Can OpenAB relay images natively?** +A: Not currently. OpenAB streams text via ACP JSON-RPC. Image/file sending is done out-of-band by the agent. + +**Q: Does this work with Slack / Telegram / LINE?** +A: The same concept applies — call the platform's file upload API using the channel ID from `sender_context`. The API details differ per platform. + +**Q: What image formats are supported?** +A: Discord supports PNG, JPEG, GIF, and WebP. Max file size is 25 MB (or higher with Nitro boost). From b9a1551a91bd89c97884dbba4afe633d5974812c Mon Sep 17 00:00:00 2001 From: chaodu-agent Date: Thu, 30 Apr 2026 16:14:56 +0000 Subject: [PATCH 2/8] docs: add ASCII architecture diagrams to sendimages and sendfiles --- docs/sendfiles.md | 43 +++++++++++++++++++++++++++++++++---------- docs/sendimages.md | 16 ++++++++++++---- 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/docs/sendfiles.md b/docs/sendfiles.md index c9887112..964c2fef 100644 --- a/docs/sendfiles.md +++ b/docs/sendfiles.md @@ -7,13 +7,41 @@ To send a file back to the user, the agent must call the Discord API directly. ## How It Works +### Direct Upload (small files) + +``` +┌──────────┐ text only ┌──────────┐ ACP stdio ┌──────────────┐ +│ Discord │◄────────────│ OpenAB │◄────────────│ Agent (CLI) │ +│ Thread │ └──────────┘ └──────┬───────┘ +│ │ │ +│ │ Discord REST API │ +│ │◄─────────────────────────────────────────────┘ +│ │ POST /channels/{thread_id}/messages +│ │ + multipart file attachment +└──────────┘ +``` + +### Enterprise / Large Files (presigned URL) + ``` -Agent produces file (code, PDF, CSV, zip, etc.) - → reads thread_id from sender_context - → POST /channels/{thread_id}/messages with file attachment - → file appears in the Discord thread +┌──────────┐ text only ┌──────────┐ ACP stdio ┌──────────────┐ +│ Discord │◄────────────│ OpenAB │◄────────────│ Agent (CLI) │ +│ Thread │ └──────────┘ └──────┬───────┘ +│ │ │ +│ │ send presigned URL as message │ upload file +│ │◄─────────────────────────────────────────────┤─────────────►┌─────┐ +│ │ POST /channels/{thread_id}/messages │ │ S3 │ +└─────┬────┘ │ │ R2 │ + │ │ │ GCS │ + │ user clicks link │ └──┬──┘ + └────────────────────────────────────────────────────────────────────►│ + presigned GET │ + ◄─────────────────────────────────────────────┘ ``` +OpenAB only streams text via ACP. To send a file, the agent calls the +Discord API directly using the `thread_id` from `sender_context`. + ## Step-by-Step ### 1. Get the Target Channel from `sender_context` @@ -109,12 +137,7 @@ For enterprise use or files exceeding Discord's upload limit, the recommended pa 2. **Generate a temporary link** — e.g. an [S3 presigned URL](https://docs.aws.amazon.com/AmazonS3/latest/userguide/ShareObjectPresignedURL.html) with a short TTL. 3. **Send the link back to Discord** — post the URL as a regular message in the thread. -``` -Agent produces large file - → uploads to S3 bucket - → generates presigned URL (e.g. expires in 1 hour) - → sends URL as a Discord message in the thread -``` +> See the [Enterprise / Large Files diagram](#enterprise--large-files-presigned-url) above for the full flow. #### Why this is better for enterprise diff --git a/docs/sendimages.md b/docs/sendimages.md index cd2b92db..7e8bf388 100644 --- a/docs/sendimages.md +++ b/docs/sendimages.md @@ -6,12 +6,20 @@ To send an image back to the user, the agent must call the Discord API directly. ## How It Works ``` -Agent generates image → saves to local file - → reads thread_id from sender_context - → POST /channels/{thread_id}/messages with image attachment - → image appears in the Discord thread +┌──────────┐ text only ┌──────────┐ ACP stdio ┌──────────────┐ +│ Discord │◄────────────│ OpenAB │◄────────────│ Agent (CLI) │ +│ Thread │ └──────────┘ └──────┬───────┘ +│ │ │ +│ │ Discord REST API │ +│ │◄─────────────────────────────────────────────┘ +│ │ POST /channels/{thread_id}/messages +│ │ + multipart file attachment +└──────────┘ ``` +OpenAB only streams text via ACP. To send an image, the agent calls the +Discord API directly using the `thread_id` from `sender_context`. + ## Step-by-Step ### 1. Get the Target Channel from `sender_context` From 6690c315ac70906fb9d05b4cec91d38fa18d2595 Mon Sep 17 00:00:00 2001 From: chaodu-agent Date: Thu, 30 Apr 2026 16:15:45 +0000 Subject: [PATCH 3/8] docs: add agent-facing header with example prompt and SKILL tip --- docs/sendfiles.md | 11 +++++++++++ docs/sendimages.md | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/docs/sendfiles.md b/docs/sendfiles.md index 964c2fef..94d0025c 100644 --- a/docs/sendfiles.md +++ b/docs/sendfiles.md @@ -1,5 +1,16 @@ # Sending Files Back to Discord +> **This doc is designed for your coding agent.** Share it with your agent so it learns how to send files back to Discord. +> +> Example prompt: +> ``` +> Read docs/sendfiles.md and send the report file back to my Discord thread. +> ``` +> +> 💡 **Tip:** If it works the first time, ask your agent to save this as a **SKILL** so it remembers how to do it next time without re-reading the doc. + +--- + OpenAB streams text only — it does **not** relay file attachments from the agent. To send a file back to the user, the agent must call the Discord API directly. diff --git a/docs/sendimages.md b/docs/sendimages.md index 7e8bf388..8d39e050 100644 --- a/docs/sendimages.md +++ b/docs/sendimages.md @@ -1,5 +1,16 @@ # Sending Images Back to Discord +> **This doc is designed for your coding agent.** Share it with your agent so it learns how to send images back to Discord. +> +> Example prompt: +> ``` +> Read docs/sendimages.md and send the generated image back to my Discord thread. +> ``` +> +> 💡 **Tip:** If it works the first time, ask your agent to save this as a **SKILL** so it remembers how to do it next time without re-reading the doc. + +--- + OpenAB does **not** relay images from the agent to Discord — it only streams text. To send an image back to the user, the agent must call the Discord API directly. From 1206d6c0001143ea828f90a0358328a699ba5954 Mon Sep 17 00:00:00 2001 From: chaodu-agent Date: Thu, 30 Apr 2026 16:18:10 +0000 Subject: [PATCH 4/8] docs: update example prompts to read from OpenAB GitHub --- docs/sendfiles.md | 2 +- docs/sendimages.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sendfiles.md b/docs/sendfiles.md index 94d0025c..0b144175 100644 --- a/docs/sendfiles.md +++ b/docs/sendfiles.md @@ -4,7 +4,7 @@ > > Example prompt: > ``` -> Read docs/sendfiles.md and send the report file back to my Discord thread. +> Read docs/sendfiles.md from OpenAB GitHub and send the file back to my Discord thread. > ``` > > 💡 **Tip:** If it works the first time, ask your agent to save this as a **SKILL** so it remembers how to do it next time without re-reading the doc. diff --git a/docs/sendimages.md b/docs/sendimages.md index 8d39e050..61c41fc4 100644 --- a/docs/sendimages.md +++ b/docs/sendimages.md @@ -4,7 +4,7 @@ > > Example prompt: > ``` -> Read docs/sendimages.md and send the generated image back to my Discord thread. +> Read docs/sendimages.md from OpenAB GitHub and send the image back to my Discord thread. > ``` > > 💡 **Tip:** If it works the first time, ask your agent to save this as a **SKILL** so it remembers how to do it next time without re-reading the doc. From 335a105227c915e7b1fa09d0d5d56a05eec6187e Mon Sep 17 00:00:00 2001 From: chaodu-agent Date: Thu, 30 Apr 2026 16:20:00 +0000 Subject: [PATCH 5/8] =?UTF-8?q?docs:=20fix=20bot=20token=20guidance=20?= =?UTF-8?q?=E2=80=94=20clarify=20env=20inheritance=20vs=20explicit=20confi?= =?UTF-8?q?g?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/sendfiles.md | 15 ++++++++++++++- docs/sendimages.md | 12 ++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/docs/sendfiles.md b/docs/sendfiles.md index 0b144175..990c82b2 100644 --- a/docs/sendfiles.md +++ b/docs/sendfiles.md @@ -70,7 +70,20 @@ Every message includes a `` JSON block: Use **`thread_id`** as the target. Fall back to `channel_id` if `thread_id` is absent. -### 2. Upload the File +### 2. Get the Bot Token + +The agent needs the Discord Bot Token to call the API. Two common approaches: + +- **Environment variable** — If `DISCORD_BOT_TOKEN` is set as a system-level env var (e.g. via Kubernetes Secret, Docker `-e`, or shell export), the agent subprocess inherits it automatically. +- **Explicit config** — Pass it to the agent via `[agent] env` in `config.toml`: + ```toml + [agent] + env = { DISCORD_BOT_TOKEN = "${DISCORD_BOT_TOKEN}" } + ``` + +> ⚠️ The token in `[discord] bot_token` is consumed by OpenAB itself and is **not** automatically forwarded to the agent subprocess. + +### 3. Upload the File ``` POST https://discord.com/api/v10/channels/{thread_id}/messages diff --git a/docs/sendimages.md b/docs/sendimages.md index 61c41fc4..3e0aea40 100644 --- a/docs/sendimages.md +++ b/docs/sendimages.md @@ -54,8 +54,16 @@ Use **`thread_id`** as the target channel. If `thread_id` is absent, fall back t ### 2. Get the Bot Token -The Discord Bot Token is available via the `DISCORD_BOT_TOKEN` environment variable -(same token OpenAB uses). Your agent code can read it from the environment. +The agent needs the Discord Bot Token to call the API. Two common approaches: + +- **Environment variable** — If `DISCORD_BOT_TOKEN` is set as a system-level env var (e.g. via Kubernetes Secret, Docker `-e`, or shell export), the agent subprocess inherits it automatically. +- **Explicit config** — Pass it to the agent via `[agent] env` in `config.toml`: + ```toml + [agent] + env = { DISCORD_BOT_TOKEN = "${DISCORD_BOT_TOKEN}" } + ``` + +> ⚠️ The token in `[discord] bot_token` is consumed by OpenAB itself and is **not** automatically forwarded to the agent subprocess. ### 3. Upload the Image From 98d8029b208a49a2d94b0419f66db5c581c059b3 Mon Sep 17 00:00:00 2001 From: chaodu-agent Date: Thu, 30 Apr 2026 16:25:42 +0000 Subject: [PATCH 6/8] docs: recommend dedicated bot token for file uploads, add security comparison table --- docs/sendfiles.md | 26 ++++++++++++++++++-------- docs/sendimages.md | 33 +++++++++++++++++++++++++-------- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/docs/sendfiles.md b/docs/sendfiles.md index 990c82b2..cbcbdfc9 100644 --- a/docs/sendfiles.md +++ b/docs/sendfiles.md @@ -72,16 +72,26 @@ Use **`thread_id`** as the target. Fall back to `channel_id` if `thread_id` is a ### 2. Get the Bot Token -The agent needs the Discord Bot Token to call the API. Two common approaches: +The agent needs a Discord Bot Token to call the API. Pass it via `[agent] env` in `config.toml`: -- **Environment variable** — If `DISCORD_BOT_TOKEN` is set as a system-level env var (e.g. via Kubernetes Secret, Docker `-e`, or shell export), the agent subprocess inherits it automatically. -- **Explicit config** — Pass it to the agent via `[agent] env` in `config.toml`: - ```toml - [agent] - env = { DISCORD_BOT_TOKEN = "${DISCORD_BOT_TOKEN}" } - ``` +```toml +[agent] +env = { DISCORD_BOT_TOKEN = "${DISCORD_BOT_TOKEN}" } +``` + +> ⚠️ The token in `[discord] bot_token` is consumed by OpenAB itself and is **not** automatically forwarded to the agent subprocess. You must explicitly pass it via `[agent] env`. + +#### Security: dedicated bot recommended + +For production, consider using a **separate bot token** with minimal permissions instead of sharing the main OAB bot token. See [sendimages.md — Security: dedicated bot recommended](sendimages.md#security-dedicated-bot-recommended) for the full comparison table. + +```toml +# Production: dedicated file-upload bot +[agent] +env = { DISCORD_FILE_BOT_TOKEN = "${DISCORD_FILE_BOT_TOKEN}" } +``` -> ⚠️ The token in `[discord] bot_token` is consumed by OpenAB itself and is **not** automatically forwarded to the agent subprocess. +For personal use or small teams, sharing the same token is fine — you already trust your agent. ### 3. Upload the File diff --git a/docs/sendimages.md b/docs/sendimages.md index 3e0aea40..d426af63 100644 --- a/docs/sendimages.md +++ b/docs/sendimages.md @@ -54,16 +54,33 @@ Use **`thread_id`** as the target channel. If `thread_id` is absent, fall back t ### 2. Get the Bot Token -The agent needs the Discord Bot Token to call the API. Two common approaches: +The agent needs a Discord Bot Token to call the API. Pass it via `[agent] env` in `config.toml`: -- **Environment variable** — If `DISCORD_BOT_TOKEN` is set as a system-level env var (e.g. via Kubernetes Secret, Docker `-e`, or shell export), the agent subprocess inherits it automatically. -- **Explicit config** — Pass it to the agent via `[agent] env` in `config.toml`: - ```toml - [agent] - env = { DISCORD_BOT_TOKEN = "${DISCORD_BOT_TOKEN}" } - ``` +```toml +[agent] +env = { DISCORD_BOT_TOKEN = "${DISCORD_BOT_TOKEN}" } +``` + +> ⚠️ The token in `[discord] bot_token` is consumed by OpenAB itself and is **not** automatically forwarded to the agent subprocess. You must explicitly pass it via `[agent] env`. + +#### Security: dedicated bot recommended + +For production, consider using a **separate bot token** with minimal permissions instead of sharing the main OAB bot token: + +| | Same token (simple) | Dedicated bot (recommended) | +|---|---|---| +| Setup | One bot, one token | Create a second bot in Discord Developer Portal | +| Agent permissions | Everything the OAB bot can do | Only `Send Messages` + `Attach Files` | +| Token leak impact | Full bot access exposed | Limited to file uploads | +| Audit trail | Cannot distinguish OAB vs agent messages | Separate bot identity in logs | + +```toml +# Production: dedicated file-upload bot +[agent] +env = { DISCORD_FILE_BOT_TOKEN = "${DISCORD_FILE_BOT_TOKEN}" } +``` -> ⚠️ The token in `[discord] bot_token` is consumed by OpenAB itself and is **not** automatically forwarded to the agent subprocess. +For personal use or small teams, sharing the same token is fine — you already trust your agent. ### 3. Upload the Image From b09478ff83cd5b5dc134838ec71a9f5c755bc0f5 Mon Sep 17 00:00:00 2001 From: chaodu-agent Date: Thu, 30 Apr 2026 16:27:25 +0000 Subject: [PATCH 7/8] docs: add File Deliverer bot architecture diagram and UX example --- docs/sendfiles.md | 4 ++-- docs/sendimages.md | 36 ++++++++++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/docs/sendfiles.md b/docs/sendfiles.md index cbcbdfc9..0ffcf3ab 100644 --- a/docs/sendfiles.md +++ b/docs/sendfiles.md @@ -83,10 +83,10 @@ env = { DISCORD_BOT_TOKEN = "${DISCORD_BOT_TOKEN}" } #### Security: dedicated bot recommended -For production, consider using a **separate bot token** with minimal permissions instead of sharing the main OAB bot token. See [sendimages.md — Security: dedicated bot recommended](sendimages.md#security-dedicated-bot-recommended) for the full comparison table. +For production, consider creating a **dedicated "File Deliverer" bot** with minimal permissions instead of sharing the main OAB bot token. See [sendimages.md — Security: dedicated bot recommended](sendimages.md#security-dedicated-bot-recommended) for the full architecture diagram and comparison table. ```toml -# Production: dedicated file-upload bot +# Production: dedicated file-upload bot (e.g. "File Deliverer") [agent] env = { DISCORD_FILE_BOT_TOKEN = "${DISCORD_FILE_BOT_TOKEN}" } ``` diff --git a/docs/sendimages.md b/docs/sendimages.md index d426af63..9d6466ca 100644 --- a/docs/sendimages.md +++ b/docs/sendimages.md @@ -65,7 +65,39 @@ env = { DISCORD_BOT_TOKEN = "${DISCORD_BOT_TOKEN}" } #### Security: dedicated bot recommended -For production, consider using a **separate bot token** with minimal permissions instead of sharing the main OAB bot token: +For production, consider creating a **dedicated "File Deliverer" bot** with minimal permissions instead of sharing the main OAB bot token: + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Discord Server │ +│ │ +│ ┌─────────────────┐ ┌──────────────────────────────┐ │ +│ │ OAB Bot │ │ File Deliverer Bot │ │ +│ │ (main bot) │ │ (dedicated, minimal perms) │ │ +│ │ │ │ │ │ +│ │ ✅ Read Messages │ │ ✅ Send Messages │ │ +│ │ ✅ Manage Threads│ │ ✅ Send Messages in Threads │ │ +│ │ ✅ Add Reactions │ │ ✅ Attach Files │ │ +│ │ ✅ Send Messages │ │ ❌ Read Messages │ │ +│ │ ✅ Attach Files │ │ ❌ Manage Threads │ │ +│ └────────┬────────┘ └──────────────┬───────────────┘ │ +│ │ │ │ +│ │ ACP stdio │ REST API │ +│ ▼ ▼ │ +│ ┌──────────────────────────────────────────────────────────┐ │ +│ │ Agent (kiro-cli / claude / codex) │ │ +│ │ │ │ +│ │ DISCORD_FILE_BOT_TOKEN ──► POST /channels/{id}/messages │ │ +│ └──────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +**What users see in the thread:** + +``` +超渡法師: 好的,我幫你生成報告... +File Deliverer: 📎 report.pdf +``` | | Same token (simple) | Dedicated bot (recommended) | |---|---|---| @@ -75,7 +107,7 @@ For production, consider using a **separate bot token** with minimal permissions | Audit trail | Cannot distinguish OAB vs agent messages | Separate bot identity in logs | ```toml -# Production: dedicated file-upload bot +# Production: dedicated file-upload bot (e.g. "File Deliverer") [agent] env = { DISCORD_FILE_BOT_TOKEN = "${DISCORD_FILE_BOT_TOKEN}" } ``` From 7aee1f7385d51d81e18d115b4ecf75923e42d2a9 Mon Sep 17 00:00:00 2001 From: chaodu-agent Date: Thu, 30 Apr 2026 16:29:29 +0000 Subject: [PATCH 8/8] docs: add cross-link from sendimages.md to sendfiles.md --- docs/sendimages.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/sendimages.md b/docs/sendimages.md index 9d6466ca..c8e48f8f 100644 --- a/docs/sendimages.md +++ b/docs/sendimages.md @@ -14,6 +14,8 @@ OpenAB does **not** relay images from the agent to Discord — it only streams text. To send an image back to the user, the agent must call the Discord API directly. +> For sending non-image files (PDF, CSV, logs, etc.), see [sendfiles.md](sendfiles.md). + ## How It Works ```