# yaml-language-server: $schema=https://schema.zeabur.app/template.json
apiVersion: zeabur.com/v1
kind: Template
metadata:
    name: OpenAB Kiro
spec:
    description: |
        Open Agent Broker — a lightweight Rust harness that bridges Discord and Slack to any ACP-compatible coding CLI (Claude Code, Codex, Gemini, Kiro) over stdio JSON-RPC. This template uses the Kiro CLI as the agent backend.
        Source: https://github.com/openabdev/openab
    coverImage: https://cdn-console.zeabur.com/f/Xp0H6/openab-cover.webp
    icon: https://cdn-console.zeabur.com/f/0Ewi6/openab-icon.webp
    variables:
        - key: DISCORD_BOT_TOKEN
          type: STRING
          name: Discord Bot Token
          description: Token from https://discord.com/developers/applications
        - 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. Example: 123456789012345678,234567890123456789'
        - 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 in the allowed channels.
        - key: OPENAB_ALLOW_BOT_MESSAGES
          type: STRING
          name: Allow Bot Messages (optional)
          description: Optional. Set to 'on' to allow messages from bots/webhooks to trigger the agent. Leave empty to disable (default).
        - key: KIRO_API_KEY
          type: STRING
          name: Kiro API Key (optional, Pro+)
          description: Optional. API key for Kiro Pro/Pro+/Power subscribers. Leave empty to authenticate via device flow after deployment (free tier).
        - 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 adapter.
        - 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_MAX_SESSIONS
          type: STRING
          name: Max Concurrent Sessions (optional)
          description: 'Optional. Maximum number of concurrent agent sessions (default: 10). Oldest idle session is evicted when the limit is reached.'
    tags:
        - AI
        - Developer Tools
        - Discord
        - Slack
    readme: |
        # OpenAB Kiro

        [OpenAB](https://github.com/openabdev/openab) is a lightweight, open-source Rust harness that bridges Discord to any [Agent Client Protocol](https://github.com/anthropics/agent-protocol)-compatible coding CLI over stdio JSON-RPC.

        This template deploys the Kiro variant using the base `openab` image with `kiro-cli` as the agent backend.

        ## Important Notes

        - **Image tag:** This template uses a pinned version (`0.8.0`). To upgrade, change the image tag in Zeabur Dashboard → Service → Settings. Available tags: [GitHub Packages](https://github.com/openabdev/openab/pkgs/container/openab).
        - **Persistent storage:** `/home/agent` is mounted as a persistent volume. Plugins, settings, config, and credentials survive restarts.
        - **Config ownership:** The container runs directly as `agent` user (uid 1000). If you encounter permission issues on the persistent volume, restart the service.

        ## Setup

        ### 1. Get a Discord Bot Token

        1. Go to https://discord.com/developers/applications and click **New Application**
        2. Navigate to **Bot** tab → click **Reset Token** → copy the token
        3. On the same page, scroll down and enable **Message Content Intent** under Privileged Gateway Intents
        4. 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
        5. Copy the generated URL and open it in your browser to invite the bot to your server

        ### 2. Get Discord Channel IDs

        1. Open Discord → go to **User Settings** (gear icon) → **Advanced** → enable **Developer Mode**
        2. Right-click the channel where you want the bot to respond → **Copy Channel ID**
        3. For multiple channels, separate IDs with commas: `123456789012345678,234567890123456789`

        ### 3. Get a Kiro API Key (Pro/Pro+/Power only)

        If you have a paid Kiro subscription, go to [kiro.dev](https://kiro.dev) → Settings → API Keys → create a key and paste it into the `KIRO_API_KEY` variable. This lets the bot authenticate automatically — no post-deploy steps needed.

        Free tier users can leave `KIRO_API_KEY` empty and authenticate after deployment (see step 5).

        ### 4. Deploy

        Fill in the variables and click deploy. The service connects to Discord automatically.

        ### 5. Authenticate Kiro via Device Flow (Free tier only)

        Skip this step if you set `KIRO_API_KEY` in step 3.

        After the service is running, open the service terminal in Zeabur Dashboard and run:

        ```
        HOME=/home/agent kiro-cli login --use-device-flow
        ```

        > ⚠️ Must run as `agent`. Running as `root` writes credentials to `/root/` which is not persisted; they will be lost on restart.

        Follow the on-screen URL and code to complete device flow authorization in your browser. Restart the service after login completes.

        ## Slack Setup (Optional)

        OpenAB supports Slack via Socket Mode — no public URL needed.

        1. Go to https://api.slack.com/apps → **Create New App** → **From scratch**
        2. **Socket Mode** → Enable → generate an App-Level Token with scope `connections:write` → copy the `xapp-...` token (`SLACK_APP_TOKEN`)
        3. **Event Subscriptions** → Enable Events → add bot events: `app_mention`, `message.channels`, `message.groups`
        4. **OAuth & Permissions** → Bot Token Scopes → add: `app_mentions:read`, `chat:write`, `channels:history`, `groups:history`, `channels:read`, `groups:read`, `reactions:write`, `files:read`, `users:read`
        5. **Install App** → Install to Workspace → copy the `xoxb-...` token (`SLACK_BOT_TOKEN`)
        6. In each Slack channel you want the bot in, run `/invite @YourAppName`

        Set `SLACK_BOT_TOKEN` and `SLACK_APP_TOKEN` in the template variables before deploying. Both Discord and Slack can run simultaneously.

        ## Usage

        - **@mention the bot** in an allowed channel or Slack channel to start a conversation
        - OpenAB creates a **thread** for multi-turn conversations — no @mention needed for follow-ups
        - Each thread maps to a persistent Kiro session (24h TTL)

        ## GitHub Integration (Optional)

        The agent can use `gh` (GitHub CLI) to review PRs, create issues, comment, merge, etc. Since the container is headless, authentication uses device flow:

        1. Ask the bot in Discord: **"log in to GitHub"**
        2. The bot will reply with a one-time code and a URL (e.g. `https://github.com/login/device`)
        3. Open the URL on your phone or computer, enter the code, and authorize
        4. The bot confirms login — `gh` is now authenticated for this session

        See [gh-auth-device-flow.md](https://github.com/openabdev/openab/blob/main/docs/gh-auth-device-flow.md) for technical details.

        ## Customization

        | File | Description |
        |------|-------------|
        | `/home/agent/.config/openab/config.toml` | OpenAB config (sessions, reactions, STT, etc.) |

        `config.toml` is created from a built-in template on first boot. After that, edit the file directly — environment variables are only used for initial setup. To reset to defaults, delete the file and restart: `rm /home/agent/.config/openab/config.toml`

        For config options, see the [OpenAB documentation](https://github.com/openabdev/openab).

        ## Disabling

        Leave `Discord Bot Token` empty. The service sleeps instead of crashing.

        ## Links

        - [OpenAB GitHub](https://github.com/openabdev/openab)
        - [Agent Client Protocol](https://github.com/anthropics/agent-protocol)
    resourceRequirement:
        minConfig:
            cpu: 2
            ram: 4
        recommendedConfig:
            cpu: 4
            ram: 8
    services:
        - name: openab
          icon: https://cdn-console.zeabur.com/f/0Ewi6/openab-icon.webp
          template: PREBUILT_V2
          spec:
            id: openab
            source:
                image: ghcr.io/openabdev/openab:0.8.0
                command:
                    - /bin/sh
                    - -c
                    - /opt/start-openab.sh
            volumes:
                - id: agent-home
                  dir: /home/agent
            env:
                DISCORD_BOT_TOKEN:
                    default: ${DISCORD_BOT_TOKEN}
                KIRO_API_KEY:
                    default: ""
                OPENAB_ALLOW_BOT_MESSAGES:
                    default: ""
                OPENAB_ALLOWED_CHANNELS:
                    default: ""
                OPENAB_ALLOWED_USERS:
                    default: ""
                OPENAB_MAX_SESSIONS:
                    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" ]; then
                      echo "openab: neither DISCORD_BOT_TOKEN nor SLACK_BOT_TOKEN set — sleeping"
                      exec sleep infinity
                    fi

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

                    # Generate config.toml on first boot only
                    # To regenerate, delete the file and restart
                    if [ ! -f "$CONFIG_FILE" ]; then
                      cp /opt/config.toml.template "$CONFIG_FILE"

                      # Add [discord] section if token provided
                      if [ -n "$DISCORD_BOT_TOKEN" ]; then
                        printf '\n[discord]\nbot_token = "${DISCORD_BOT_TOKEN}"\n' >> "$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_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

                      # Add [slack] section if tokens provided
                      if [ -n "$SLACK_BOT_TOKEN" ] && [ -n "$SLACK_APP_TOKEN" ]; then
                        printf '\n[slack]\nbot_token = "${SLACK_BOT_TOKEN}"\napp_token = "${SLACK_APP_TOKEN}"\n' >> "$CONFIG_FILE"
                      fi

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

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

                    exec openab run "$CONFIG_FILE"
                  permission: 493
                  envsubst: null
                - path: /opt/config.toml.template
                  template: |
                    [agent]
                    command = "kiro-cli"
                    args = ["acp", "--trust-all-tools"]
                    working_dir = "/home/agent"
                  permission: null
                  envsubst: null
