# yaml-language-server: $schema=https://schema.zeabur.app/template.json
apiVersion: zeabur.com/v1
kind: Template
metadata:
    name: OpenAB Pi
spec:
    description: |
        Deploy OpenAB with the Pi coding agent as a Discord/Slack bot. Pi is a minimal coding agent (4 tools: read/write/edit/bash) with native subscription auth — Claude Pro/Max, ChatGPT Plus/Pro, or any API key. Supports 15+ LLM providers via mid-session model switching.
        Source: https://github.com/openabdev/openab
    coverImage: https://raw.githubusercontent.com/openabdev/openab/main/images/banner.jpg
    icon: https://avatars.githubusercontent.com/u/274127192?v=4
    variables:
        - key: DISCORD_BOT_TOKEN
          type: STRING
          name: Discord Bot Token (optional)
          description: Optional. Token from https://discord.com/developers/applications. Leave empty if using Slack only.
        - key: OPENAB_ALLOWED_CHANNELS
          type: STRING
          name: Discord Channel IDs (optional)
          description: Optional. Comma-separated Discord channel IDs where the bot listens. Leave empty to allow all channels.
        - key: OPENAB_ALLOWED_USERS
          type: STRING
          name: Discord User IDs (optional)
          description: Optional. Comma-separated Discord user IDs allowed to interact with the bot. Leave empty to allow everyone.
        - key: SLACK_BOT_TOKEN
          type: STRING
          name: Slack Bot Token (optional)
          description: Optional. Bot User OAuth Token (xoxb-...) from Slack App settings. Leave empty to disable Slack.
        - key: SLACK_APP_TOKEN
          type: STRING
          name: Slack App Token (optional)
          description: Optional. App-Level Token (xapp-...) for Socket Mode. Required when Slack Bot Token is set.
        - key: OPENAB_ALLOW_BOT_MESSAGES
          type: STRING
          name: Allow Bot Messages (optional)
          description: Optional. Set to 'on' or 'mentions' to allow messages from bots/webhooks. Leave empty to disable.
        - key: OPENAB_TRUSTED_BOT_IDS
          type: STRING
          name: Trusted Bot IDs (optional)
          description: Optional. Comma-separated Discord bot IDs trusted to send messages. Leave empty to trust all bots.
        - key: OPENAB_MAX_SESSIONS
          type: STRING
          name: Max Concurrent Sessions (optional)
          description: 'Optional. Maximum number of concurrent agent sessions (default: 5).'
    tags:
        - AI
        - Discord Bot
        - Developer Tools
    readme: |
        # OpenAB Pi

        One-click deployment of [OpenAB](https://github.com/openabdev/openab) with the [Pi coding agent](https://github.com/earendil-works/pi-coding-agent) as the AI backend. Uses the `pi-acp` Node.js adapter to bridge ACP JSON-RPC ↔ Pi CLI.

        ## Why Pi?

        - **Native subscription auth** — Claude Pro/Max and ChatGPT Plus/Pro via `pi /login`. No auth-proxy sidecar needed.
        - **Minimal tool surface** — 4 tools only (read / write / edit / bash). Maximum context window for actual code.
        - **Multi-provider** — switch models mid-session. Supports Anthropic, OpenAI, Google, and any OpenAI-compatible endpoint (DeepSeek, Groq, Together, Ollama, etc.).
        - **Branching sessions** — Pi saves history as trees; explore multiple approaches from one decision point.

        ## Important Notes

        - **Image tag:** This template tracks the `beta` tag. To pin a specific version, change the image tag in Zeabur Dashboard → Service → Settings.
        - **Persistent storage:** `/home/node` is mounted as a persistent volume. Config, auth tokens (`~/.pi/`), and session trees survive restarts.
        - **Config location:** `config.toml` is generated at `/home/node/.config/openab/config.toml` on first boot. Edit it directly after that — env vars are only used for initial setup.
        - **User home:** Pi runs as the `node` user (UID 1000) — different from other agent templates that use `agent`. Paths in this template all start with `/home/node`.

        ## Setup

        ### 1. Create a Discord Bot

        1. Go to [Discord Developer Portal](https://discord.com/developers/applications)
        2. Create a new application and add a Bot
        3. Enable **Message Content Intent** under Privileged Gateway Intents
        4. Copy the bot token and paste it as `DISCORD_BOT_TOKEN`
        5. Go to **OAuth2 → URL Generator** → check scope `bot` → check permissions: Send Messages, Send Messages in Threads, Create Public Threads, Read Message History, Add Reactions, Manage Messages
        6. Invite the bot to your server with the generated URL

        ### 2. Authenticate Pi

        Pi authentication is interactive. After deployment, open the **Exec** tab in Zeabur Dashboard and run:

        ```bash
        pi
        ```

        Inside Pi's interactive UI, type:

        ```
        /login
        ```

        Choose your provider and follow the OAuth flow in your browser. Tokens persist in `/home/node/.pi/`.

        **For pay-per-token API keys** instead of subscription:

        ```bash
        pi
        # then inside Pi:
        /set OPENAI_API_KEY sk-...
        # or
        /set ANTHROPIC_API_KEY sk-ant-...
        ```

        ### 3. Configure Channels (Optional)

        Set `OPENAB_ALLOWED_CHANNELS` to restrict which channels the bot responds in. Leave empty to allow all channels.

        ## Slack Setup (Optional)

        1. Go to https://api.slack.com/apps → Create New App → From scratch
        2. Enable Socket Mode → generate App-Level Token with scope `connections:write`
        3. Enable Event Subscriptions → add bot events: `app_mention`, `message.channels`, `message.groups`
        4. OAuth & Permissions → add scopes: `app_mentions:read`, `chat:write`, `channels:history`, `groups:history`, `channels:read`, `groups:read`, `reactions:write`, `files:read`, `users:read`
        5. Install App → copy `xoxb-...` token and `xapp-...` token

        ## Customization

        | File | Description |
        |------|-------------|
        | `/home/node/.config/openab/config.toml` | OpenAB config (sessions, reactions, etc.) |
        | `/home/node/.pi/` | Pi configuration and auth tokens |
        | `/home/node/.pi/sessions/` | Pi session history trees |
        | `/home/node/AGENTS.md` | Project-level steering for Pi (loaded into context) |
        | `/home/node/.pi/APPEND_SYSTEM.md` | Append to Pi's system prompt |
        | `/home/node/.pi/SYSTEM.md` | Replace Pi's system prompt entirely |

        To reset OpenAB config: `rm /home/node/.config/openab/config.toml` and restart.

        ## Limitations

        - **No streaming** — `pi-acp` returns the full response at once; intermediate output is buffered.
        - **Cancel is best-effort** — `session/cancel` may not interrupt mid-generation; Pi CLI runs to completion.

        ## Links

        - [OpenAB GitHub](https://github.com/openabdev/openab)
        - [Pi Coding Agent](https://github.com/earendil-works/pi-coding-agent)
        - [Pi Setup Guide](https://github.com/openabdev/openab/blob/main/docs/pi.md)
        - [Agent Client Protocol](https://github.com/anthropics/agent-protocol)
    services:
        - name: openab-pi
          icon: https://avatars.githubusercontent.com/u/274127192?v=4
          template: PREBUILT_V2
          spec:
            id: openab-pi
            source:
                image: ghcr.io/openabdev/openab-pi:beta
                command:
                    - tini
                    - --
                    - /bin/sh
                    - -c
                    - /opt/start-openab.sh
                runAsUserID: 1000
            volumes:
                - id: agent-home
                  dir: /home/node
            env:
                DISCORD_BOT_TOKEN:
                    default: ${DISCORD_BOT_TOKEN}
                GATEWAY_PLATFORM:
                    default: ""
                GATEWAY_URL:
                    default: ""
                OPENAB_ALLOW_BOT_MESSAGES:
                    default: ""
                OPENAB_ALLOWED_CHANNELS:
                    default: ""
                OPENAB_ALLOWED_USERS:
                    default: ""
                OPENAB_MAX_SESSIONS:
                    default: ""
                OPENAB_TRUSTED_BOT_IDS:
                    default: ""
                SLACK_APP_TOKEN:
                    default: ""
                SLACK_BOT_TOKEN:
                    default: ""
            configs:
                - path: /opt/start-openab.sh
                  template: |
                    #!/bin/sh
                    set -e

                    if [ -z "$DISCORD_BOT_TOKEN" ] && [ -z "$SLACK_BOT_TOKEN" ] && [ -z "$GATEWAY_URL" ]; then
                      echo "openab: no adapter configured (set DISCORD_BOT_TOKEN, SLACK_BOT_TOKEN, or GATEWAY_URL) — sleeping"
                      exec sleep infinity
                    fi

                    CONFIG_DIR=/home/node/.config/openab
                    CONFIG_FILE=$CONFIG_DIR/config.toml
                    mkdir -p "$CONFIG_DIR"

                    if [ ! -f "$CONFIG_FILE" ]; then
                      cp /opt/config.toml.template "$CONFIG_FILE"

                      if [ -n "$DISCORD_BOT_TOKEN" ]; then
                        printf '\n[discord]\nbot_token = "%s"\n' "$DISCORD_BOT_TOKEN" >> "$CONFIG_FILE"
                        if [ -n "$OPENAB_ALLOW_BOT_MESSAGES" ]; then
                          printf 'allow_bot_messages = "%s"\n' "$OPENAB_ALLOW_BOT_MESSAGES" >> "$CONFIG_FILE"
                        fi
                        if [ -n "$OPENAB_TRUSTED_BOT_IDS" ]; then
                          IFS=','; bots=""; for id in $OPENAB_TRUSTED_BOT_IDS; do id=$(echo "$id" | tr -d ' '); [ -n "$id" ] && bots="${bots}\"${id}\","; done; unset IFS
                          printf 'trusted_bot_ids = [%s]\n' "$(echo "$bots" | sed 's/,$//')" >> "$CONFIG_FILE"
                        fi
                        if [ -n "$OPENAB_ALLOWED_CHANNELS" ]; then
                          IFS=','; channels=""; for id in $OPENAB_ALLOWED_CHANNELS; do id=$(echo "$id" | tr -d ' '); [ -n "$id" ] && channels="${channels}\"${id}\","; done; unset IFS
                          printf 'allowed_channels = [%s]\n' "$(echo "$channels" | sed 's/,$//')" >> "$CONFIG_FILE"
                        fi
                        if [ -n "$OPENAB_ALLOWED_USERS" ]; then
                          IFS=','; users=""; for id in $OPENAB_ALLOWED_USERS; do id=$(echo "$id" | tr -d ' '); [ -n "$id" ] && users="${users}\"${id}\","; done; unset IFS
                          printf 'allowed_users = [%s]\n' "$(echo "$users" | sed 's/,$//')" >> "$CONFIG_FILE"
                        fi
                      fi

                      if [ -n "$SLACK_BOT_TOKEN" ] && [ -n "$SLACK_APP_TOKEN" ]; then
                        printf '\n[slack]\nbot_token = "%s"\napp_token = "%s"\n' "$SLACK_BOT_TOKEN" "$SLACK_APP_TOKEN" >> "$CONFIG_FILE"
                      fi

                      if [ -n "$GATEWAY_URL" ]; then
                        printf '\n[gateway]\nurl = "%s"\nplatform = "%s"\nallow_all_channels = true\nallow_all_users = true\n' "$GATEWAY_URL" "${GATEWAY_PLATFORM:-telegram}" >> "$CONFIG_FILE"
                      fi

                      if [ -n "$OPENAB_MAX_SESSIONS" ]; then
                        printf '\n[pool]\nmax_sessions = %s\n' "$OPENAB_MAX_SESSIONS" >> "$CONFIG_FILE"
                      fi

                      echo "openab: config.toml generated at $CONFIG_FILE"
                    else
                      echo "openab: using existing config.toml (delete to regenerate)"
                    fi

                    exec openab run --config "$CONFIG_FILE"
                  permission: 493
                  envsubst: null
                - path: /opt/config.toml.template
                  template: |
                    [agent]
                    command = "pi-acp"
                    args = []
                    working_dir = "/home/node"

                    [reactions]
                    enabled = true
                  permission: null
                  envsubst: null
localization:
    zh-CN:
        description: |
            部署 OpenAB 搭配 Pi coding agent 作为 Discord/Slack 机器人。Pi 是轻量 coding agent（仅 4 个工具：read/write/edit/bash），原生支持订阅认证——Claude Pro/Max、ChatGPT Plus/Pro 或任何 API key。支持 15+ LLM 提供者，可于对话中切换模型。
            来源：https://github.com/openabdev/openab
        variables:
            - key: DISCORD_BOT_TOKEN
              type: STRING
              name: Discord 机器人 Token（选填）
              description: 选填。从 Discord Developer Portal 获取的 Token。仅使用 Slack 时可留空。
            - key: OPENAB_ALLOWED_CHANNELS
              type: STRING
              name: Discord 频道 ID（选填）
              description: 选填。Bot 监听的 Discord 频道 ID，以逗号分隔。留空则允许所有频道。
            - key: OPENAB_ALLOWED_USERS
              type: STRING
              name: Discord 用户 ID（选填）
              description: 选填。以逗号分隔的 Discord 用户 ID。留空则允许所有人。
            - key: SLACK_BOT_TOKEN
              type: STRING
              name: Slack Bot Token（选填）
              description: 选填。Slack App 的 Bot User OAuth Token（xoxb-...）。留空则禁用 Slack。
            - key: SLACK_APP_TOKEN
              type: STRING
              name: Slack App Token（选填）
              description: 选填。Socket Mode 用的 App-Level Token（xapp-...）。设置 Slack Bot Token 时必填。
            - key: OPENAB_ALLOW_BOT_MESSAGES
              type: STRING
              name: 允许 Bot 消息（选填）
              description: 选填。设为 'on' 或 'mentions' 以允许 bot 消息触发。留空则禁用。
            - key: OPENAB_TRUSTED_BOT_IDS
              type: STRING
              name: 信任的 Bot ID（选填）
              description: 选填。以逗号分隔的信任 Bot ID。留空则信任所有 bot。
            - key: OPENAB_MAX_SESSIONS
              type: STRING
              name: 最大并行 Session 数（选填）
              description: 选填。最大并行 agent session 数量（默认：5）。
        readme: |
            # OpenAB Pi

            一键部署 [OpenAB](https://github.com/openabdev/openab) 搭配 [Pi coding agent](https://github.com/earendil-works/pi-coding-agent) 作为 AI 后端。

            ## 为什么选 Pi？

            - **原生订阅认证** — Claude Pro/Max 与 ChatGPT Plus/Pro 通过 `pi /login`，无需 auth-proxy sidecar
            - **极简工具** — 仅 4 个工具（read / write / edit / bash）
            - **多模型** — 支持 15+ LLM 提供者，可于对话中切换

            ## 注意事项

            - **镜像标签：** 本模板追踪 `beta` 标签。
            - **持久化存储：** `/home/node` 挂载为持久化磁盘。Config 与认证 Token（`~/.pi/`）会在重启后保留。
            - **使用者目录：** Pi 以 `node` 用户（UID 1000）运行——与其他 agent 模板的 `agent` 用户不同。

            ## 设置

            1. 前往 [Discord Developer Portal](https://discord.com/developers/applications) 创建 Bot
            2. 启用 **Message Content Intent**
            3. 部署后在 **Exec** 分页运行 `pi`，进入互动界面后输入 `/login` 完成 OAuth 认证

            或使用 API key：

            ```bash
            pi
            # 在 Pi 中：
            /set OPENAI_API_KEY sk-...
            ```

            ## 限制

            - **不支持流式** — `pi-acp` 一次返回完整响应
            - **取消为尽力而为** — `session/cancel` 可能无法中断生成
    zh-TW:
        description: |
            部署 OpenAB 搭配 Pi coding agent 作為 Discord/Slack 機器人。Pi 是輕量 coding agent（僅 4 個工具：read/write/edit/bash），原生支援訂閱認證——Claude Pro/Max、ChatGPT Plus/Pro 或任何 API key。支援 15+ LLM 提供者，可於對話中切換模型。
            來源：https://github.com/openabdev/openab
        variables:
            - key: DISCORD_BOT_TOKEN
              type: STRING
              name: Discord 機器人 Token（選填）
              description: 選填。從 Discord Developer Portal 取得的 Token。僅使用 Slack 時可留空。
            - key: OPENAB_ALLOWED_CHANNELS
              type: STRING
              name: Discord 頻道 ID（選填）
              description: 選填。Bot 監聽的 Discord 頻道 ID，以逗號分隔。留空則允許所有頻道。
            - key: OPENAB_ALLOWED_USERS
              type: STRING
              name: Discord 用戶 ID（選填）
              description: 選填。以逗號分隔的 Discord 用戶 ID。留空則允許所有人。
            - key: SLACK_BOT_TOKEN
              type: STRING
              name: Slack Bot Token（選填）
              description: 選填。Slack App 的 Bot User OAuth Token（xoxb-...）。留空則停用 Slack。
            - key: SLACK_APP_TOKEN
              type: STRING
              name: Slack App Token（選填）
              description: 選填。Socket Mode 用的 App-Level Token（xapp-...）。設定 Slack Bot Token 時必填。
            - key: OPENAB_ALLOW_BOT_MESSAGES
              type: STRING
              name: 允許 Bot 訊息（選填）
              description: 選填。設為 'on' 或 'mentions' 以允許 bot 訊息觸發。留空則停用。
            - key: OPENAB_TRUSTED_BOT_IDS
              type: STRING
              name: 信任的 Bot ID（選填）
              description: 選填。以逗號分隔的信任 Bot ID。留空則信任所有 bot。
            - key: OPENAB_MAX_SESSIONS
              type: STRING
              name: 最大並行 Session 數（選填）
              description: 選填。最大並行 agent session 數量（預設：5）。
        readme: |
            # OpenAB Pi

            一鍵部署 [OpenAB](https://github.com/openabdev/openab) 搭配 [Pi coding agent](https://github.com/earendil-works/pi-coding-agent) 作為 AI 後端。透過 `pi-acp` Node.js 適配器橋接 ACP JSON-RPC ↔ Pi CLI。

            ## 為什麼選 Pi？

            - **原生訂閱認證** — Claude Pro/Max 與 ChatGPT Plus/Pro 透過 `pi /login`，無需 auth-proxy sidecar。
            - **極簡工具** — 僅 4 個工具（read / write / edit / bash），最大化 context window。
            - **多模型** — 支援 Anthropic / OpenAI / Google 與任何 OpenAI-compatible endpoint（DeepSeek、Groq、Together、Ollama 等），可於對話中切換模型。
            - **分支 session** — Pi 將 history 存為樹狀，可從同一決策點探索多個方向。

            ## 注意事項

            - **映像標籤：** 本模板追蹤 `beta` 標籤。若要 pin 特定版本，請至 Zeabur Dashboard → 服務 → 設定修改映像標籤。
            - **持久化儲存：** `/home/node` 掛載為持久化磁碟。Config、認證 Token（`~/.pi/`）與 session 樹會在重啟後保留。
            - **Config 位置：** 首次啟動時生成於 `/home/node/.config/openab/config.toml`。之後直接編輯即可。
            - **使用者目錄：** Pi 以 `node` 使用者（UID 1000）執行——與其他 agent 模板的 `agent` 使用者不同。本模板所有路徑皆以 `/home/node` 開頭。

            ## 設定

            ### 1. 建立 Discord Bot

            1. 前往 [Discord Developer Portal](https://discord.com/developers/applications) 建立應用程式並加上 Bot
            2. 在 Privileged Gateway Intents 啟用 **Message Content Intent**
            3. 複製 bot token 貼到 `DISCORD_BOT_TOKEN`
            4. **OAuth2 → URL Generator** → scope 勾 `bot`、權限勾 Send Messages、Read Message History、Add Reactions 等
            5. 用產生的網址邀請 bot 到伺服器

            ### 2. 認證 Pi

            Pi 認證採互動式介面。部署後於 Zeabur Dashboard → **Exec** 分頁執行：

            ```bash
            pi
            ```

            在 Pi 互動介面中輸入：

            ```
            /login
            ```

            選擇你的 provider 並依瀏覽器 OAuth 流程完成。Token 會存於 `/home/node/.pi/`。

            **若要用 API key**（pay-per-token）取代訂閱：

            ```bash
            pi
            # 在 Pi 中：
            /set OPENAI_API_KEY sk-...
            # 或
            /set ANTHROPIC_API_KEY sk-ant-...
            ```

            ### 3. 設定頻道（選填）

            設定 `OPENAB_ALLOWED_CHANNELS` 限制 bot 回應的頻道；留空則允許所有頻道。

            ## Slack 設定（選填）

            1. https://api.slack.com/apps → Create New App
            2. 啟用 Socket Mode → 產生 App-Level Token（scope `connections:write`）
            3. 啟用 Event Subscriptions → bot events: `app_mention`、`message.channels`、`message.groups`
            4. OAuth & Permissions → scopes: `app_mentions:read`、`chat:write`、`channels:history` 等
            5. 安裝 App → 複製 `xoxb-...` 與 `xapp-...` token

            ## 自訂

            | 檔案 | 說明 |
            |------|------|
            | `/home/node/.config/openab/config.toml` | OpenAB 設定（sessions、reactions 等） |
            | `/home/node/.pi/` | Pi 設定與認證 Token |
            | `/home/node/.pi/sessions/` | Pi session 樹 |
            | `/home/node/AGENTS.md` | 專案層級的 Pi steering 檔案（注入到 context） |
            | `/home/node/.pi/APPEND_SYSTEM.md` | 附加到 Pi 預設 system prompt |
            | `/home/node/.pi/SYSTEM.md` | 完全取代 Pi 預設 system prompt |

            重置 OpenAB config：`rm /home/node/.config/openab/config.toml` 後重啟。

            ## 限制

            - **不支援串流** — `pi-acp` 一次回傳完整回應；中間輸出會被緩衝。
            - **取消為盡力而為** — `session/cancel` 可能無法中斷生成中的回應；Pi CLI 會執行到完成。

            ## 連結

            - [OpenAB GitHub](https://github.com/openabdev/openab)
            - [Pi Coding Agent](https://github.com/earendil-works/pi-coding-agent)
            - [Pi 設定指南](https://github.com/openabdev/openab/blob/main/docs/pi.md)
            - [Agent Client Protocol](https://github.com/anthropics/agent-protocol)
