Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ jobs:
- { suffix: "-copilot", dockerfile: "Dockerfile.copilot", artifact: "copilot" }
- { suffix: "-opencode", dockerfile: "Dockerfile.opencode", artifact: "opencode" }
- { suffix: "-cursor", dockerfile: "Dockerfile.cursor", artifact: "cursor" }
- { suffix: "-hermes", dockerfile: "Dockerfile.hermes", artifact: "hermes" }
platform:
- { os: linux/amd64, runner: ubuntu-latest }
- { os: linux/arm64, runner: ubuntu-24.04-arm }
Expand Down Expand Up @@ -135,6 +136,7 @@ jobs:
- { suffix: "-copilot", artifact: "copilot" }
- { suffix: "-opencode", artifact: "opencode" }
- { suffix: "-cursor", artifact: "cursor" }
- { suffix: "-hermes", artifact: "hermes" }
runs-on: ubuntu-latest
permissions:
contents: read
Expand Down Expand Up @@ -185,6 +187,7 @@ jobs:
- { suffix: "-copilot" }
- { suffix: "-opencode" }
- { suffix: "-cursor" }
- { suffix: "-hermes" }
runs-on: ubuntu-latest
permissions:
contents: read
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/docker-smoke-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ jobs:
- { dockerfile: Dockerfile.copilot, suffix: "-copilot", agent: "copilot", agent_args: "--acp" }
- { dockerfile: Dockerfile.opencode, suffix: "-opencode", agent: "opencode", agent_args: "acp" }
- { dockerfile: Dockerfile.cursor, suffix: "-cursor", agent: "cursor-agent", agent_args: "acp" }
- { dockerfile: Dockerfile.hermes, suffix: "-hermes", agent: "hermes-acp", agent_args: "" }
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/pr-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ on:
- copilot
- cursor
- gemini
- hermes
- opencode
default: 'default'

Expand Down
52 changes: 52 additions & 0 deletions Dockerfile.hermes
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# --- Build stage ---
FROM rust:1-bookworm AS builder
WORKDIR /build
COPY Cargo.toml Cargo.lock ./
RUN mkdir src && echo 'fn main() {}' > src/main.rs && cargo build --release && rm -rf src
COPY src/ src/
RUN touch src/main.rs && cargo build --release

# --- Runtime stage ---
FROM python:3.12-slim-bookworm

# Create agent user first so WORKDIR gets correct ownership
RUN useradd -m -u 1000 agent

RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates curl procps ripgrep tini git ffmpeg xz-utils && \
rm -rf /var/lib/apt/lists/*

# Install Hermes Agent — pinned to known commit with checksum verification
# Root install uses FHS layout: binary at /usr/local/bin/hermes, code at /usr/local/lib/hermes-agent
# HERMES_HOME points to agent user's data dir for OAuth tokens and config
ARG HERMES_INSTALL_COMMIT=cc07e30f45267c00fac97ea5569c606aca5a1ffb
ARG HERMES_INSTALL_SHA256=cb94b83b96cc924716bd1651411955da7495912ef68affe6788840e6cf147d41
RUN curl -fsSL "https://raw.githubusercontent.com/NousResearch/hermes-agent/${HERMES_INSTALL_COMMIT}/scripts/install.sh" \
-o /tmp/install-hermes.sh && \
echo "${HERMES_INSTALL_SHA256} /tmp/install-hermes.sh" | sha256sum -c - && \
HERMES_HOME=/home/agent/.hermes bash /tmp/install-hermes.sh && \
rm /tmp/install-hermes.sh && \
chmod -R a+rX /root/.local/share/uv && \
chmod a+rx /root /root/.local /root/.local/share && \
ln -sf /usr/local/lib/hermes-agent/venv/bin/hermes-acp /usr/local/bin/hermes-acp

# Install gh CLI
RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
-o /usr/share/keyrings/githubcli-archive-keyring.gpg && \
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
> /etc/apt/sources.list.d/github-cli.list && \
apt-get update && apt-get install -y --no-install-recommends gh && \
rm -rf /var/lib/apt/lists/*

ENV HOME=/home/agent
WORKDIR /home/agent

COPY --from=builder --chown=1000:1000 /build/target/release/openab /usr/local/bin/openab

RUN chown -R agent:agent /home/agent

USER agent
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD pgrep -x openab || exit 1
ENTRYPOINT ["tini", "--"]
CMD ["openab", "run", "-c", "/etc/openab/config.toml"]
29 changes: 15 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,23 @@

![OpenAB banner](images/banner.jpg)

A lightweight, secure, cloud-native ACP harness that bridges **Discord, Slack**, and any [Agent Client Protocol](https://github.com/anthropics/agent-protocol)-compatible coding CLI (Kiro CLI, Claude Code, Codex, Gemini, OpenCode, Copilot CLI, etc.) over stdio JSON-RPC — delivering the next-generation development experience. **Telegram, LINE, Feishu/Lark, Google Chat**, and other webhook-based platforms are supported via the standalone [Custom Gateway](gateway/).
A lightweight, secure, cloud-native ACP harness that bridges **Discord, Slack**, and any [Agent Client Protocol](https://github.com/anthropics/agent-protocol)-compatible coding CLI (Kiro CLI, Claude Code, Codex, Gemini, OpenCode, Copilot CLI, Hermes, etc.) over stdio JSON-RPC — delivering the next-generation development experience. **Telegram, LINE, Feishu/Lark, Google Chat**, and other webhook-based platforms are supported via the standalone [Custom Gateway](gateway/).

🪼 **Join our community!** Come say hi on Discord — we'd love to have you: **[🪼 OpenAB — Official](https://discord.gg/DmbhfDZjQS)** 🎉

```
┌──────────────┐ Gateway WS ┌──────────────┐ ACP stdio ┌──────────────┐
│ Discord │◄─────────────►│ │──────────────►│ coding CLI │
│ User │ │ openab │◄── JSON-RPC ──│ (acp mode) │
├──────────────┤ Socket Mode │ (Rust) │ ──────────────
│ Slack │◄─────────────►│ │
│ User │ └──────┬───────┘
├──────────────┤ │ WebSocket (outbound)
│ Telegram │◄──webhook──┐ │
│ User │ │ │
├──────────────┤ ▼ ▼
│ LINE │◄──webhook──┌──────────────────┐
│ User │ │ Custom Gateway │
┌──────────────┐ Gateway WS ┌──────────────┐ ACP stdio ┌──────────────────
│ Discord │◄─────────────►│ │──────────────►│ coding CLI
│ User │ │ openab │◄── JSON-RPC ──│ (acp mode)
├──────────────┤ Socket Mode │ (Rust) │ ──────────────────┤
│ Slack │◄─────────────►│ │ │ kiro-cli acp │
│ User │ └──────┬───────┘ │ claude-agent-acp │
├──────────────┤ │ WebSocket │ codex-acp │
│ Telegram │◄──webhook──┐ │ (outbound) │ gemini --acp │
│ User │ │ │ │ copilot --acp │
├──────────────┤ ▼ ▼ │ hermes-acp │
│ LINE │◄──webhook──┌──────────────────┐ │ opencode acp │
│ User │ │ Custom Gateway │ └──────────────────┘
├──────────────┤ │ (standalone) │
│ Feishu/Lark │◄───WS──────│ │
│ User │ │ │
Expand All @@ -38,7 +38,7 @@ A lightweight, secure, cloud-native ACP harness that bridges **Discord, Slack**,

- **Multi-platform** — supports Discord and Slack, run one or both simultaneously
- **Custom Gateway** — extend to Telegram, LINE, Feishu/Lark, Google Chat, MS Teams via standalone [gateway](gateway/)
- **Pluggable agent backend** — swap between Kiro CLI, Claude Code, Codex, Gemini, OpenCode, Copilot CLI via config
- **Pluggable agent backend** — swap between Kiro CLI, Claude Code, Codex, Gemini, OpenCode, Copilot CLI, Hermes via config
- **@mention trigger** — mention the bot in an allowed channel to start a conversation
- **Thread-based multi-turn** — auto-creates threads; no @mention needed for follow-ups
- **Multi-agent collaboration** — bot-to-bot messaging for coordinated workflows ([docs/multi-agent.md](docs/multi-agent.md))
Expand Down Expand Up @@ -168,6 +168,7 @@ The bot creates a thread. After that, just type in the thread — no @mention ne
| OpenCode | `opencode acp` | Native | [docs/opencode.md](docs/opencode.md) |
| Copilot CLI ⚠️ | `copilot --acp --stdio` | Native | [docs/copilot.md](docs/copilot.md) |
| Cursor | `cursor-agent acp` | Native | [docs/cursor.md](docs/cursor.md) |
| Hermes Agent | `hermes-acp` | Native | [docs/hermes.md](docs/hermes.md) |

> 🔧 Running multiple agents? See [docs/multi-agent.md](docs/multi-agent.md)

Expand Down
21 changes: 21 additions & 0 deletions charts/openab/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,27 @@ agents:
# storageClass: ""
# size: 1Gi
# image: "ghcr.io/openabdev/openab-cursor:latest"
# hermes:
# command: hermes-acp
# discord:
# enabled: true
# allowedChannels:
# - "YOUR_CHANNEL_ID"
# allowedUsers: []
# allowBotMessages: "off"
# trustedBotIds: []
# workingDir: /home/agent
# env: {}
# envFrom: []
# secretEnv: []
# pool:
# maxSessions: 10
# sessionTtlHours: 24
# persistence:
# enabled: true
# storageClass: ""
# size: 1Gi
# image: "ghcr.io/openabdev/openab-hermes"
image: ""
command: kiro-cli
args:
Expand Down
7 changes: 7 additions & 0 deletions config.toml.example
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,13 @@ working_dir = "/home/agent"
# working_dir = "/home/agent"
# env = {} # Auth via: kubectl exec -it <pod> -- cursor-agent login

# [agent]
# command = "hermes-acp"
# working_dir = "/home/agent"
# # Auth via: kubectl exec -it <pod> -- hermes auth add xai-oauth
# # Supports 30+ providers (xAI Grok OAuth, Anthropic, OpenAI Codex, Gemini, etc.)
# # Provider switching: kubectl exec -it <pod> -- hermes model

[pool]
max_sessions = 10
session_ttl_hours = 24
Expand Down
5 changes: 5 additions & 0 deletions docs/config-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@ working_dir = "/home/node"
command = "cursor-agent"
args = ["acp", "--model", "auto", "--workspace", "/home/agent"]
working_dir = "/home/agent"

# Hermes Agent
[agent]
command = "hermes-acp"
working_dir = "/home/agent"
```

---
Expand Down
137 changes: 137 additions & 0 deletions docs/hermes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Hermes Agent

[Hermes Agent](https://github.com/NousResearch/hermes-agent) by Nous Research supports ACP natively via the `hermes acp` subcommand (or the `hermes-acp` binary).

Hermes acts as a multi-provider inference gateway — it handles OAuth token lifecycle, credential storage, and provider routing so OAB agents don't need to manage auth directly.

## Docker Image

```bash
docker build -f Dockerfile.hermes -t openab-hermes:latest .
```

The image installs Hermes Agent via the official install script.

## Helm Install

```bash
helm install openab openab/openab \
--set agents.kiro.enabled=false \
--set agents.hermes.discord.enabled=true \
--set agents.hermes.discord.botToken="$DISCORD_BOT_TOKEN" \
--set-string 'agents.hermes.discord.allowedChannels[0]=YOUR_CHANNEL_ID' \
--set agents.hermes.image=ghcr.io/openabdev/openab-hermes:latest \
--set agents.hermes.command=hermes-acp \
--set agents.hermes.workingDir=/home/agent
```

> Set `agents.kiro.enabled=false` to disable the default Kiro agent.

## Manual config.toml

```toml
[agent]
command = "hermes-acp"
working_dir = "/home/agent"
```

## Authentication

Hermes supports 30+ providers. Authenticate inside the pod:

```bash
kubectl exec -it <pod> -- hermes auth add xai-oauth # xAI Grok (SuperGrok $30/mo)
kubectl exec -it <pod> -- hermes auth add nous # Nous Portal
kubectl exec -it <pod> -- hermes model # Interactive provider picker
```

### xAI Grok OAuth (Recommended)

> ⚠️ **Requires an active [SuperGrok paid subscription](https://x.ai/grok) ($30/mo).** Auth will succeed without one, but the API silently returns empty responses — the bot appears to work but never replies.

xAI Grok OAuth uses a loopback redirect flow — the callback listener binds `127.0.0.1:56121` inside the pod. You need a port-forward so your browser's redirect reaches the pod:

```bash
# Terminal 1: port-forward
kubectl port-forward deployment/<your-deployment> 56121:56121

# Terminal 2: run auth
kubectl exec -it deployment/<your-deployment> -- hermes auth add xai-oauth --no-browser
```

1. Copy the printed authorize URL → open in your local browser
2. Approve access on accounts.x.ai
3. Browser redirects to `127.0.0.1:56121/callback` → port-forward delivers it to the pod
4. Terminal shows "Login successful!"

After auth, set the default model:

```bash
kubectl exec <pod> -- hermes config set model.provider xai-oauth
kubectl exec <pod> -- hermes config set model.default grok-4.3
```

> **Note:** Tokens are stored in `~/.hermes/auth.json` and auto-refresh in the background.

### Providers That Don't Need Port-Forward

| Provider | Auth Method |
|----------|-------------|
| Anthropic (Claude Pro/Max) | Paste-the-code flow |
| OpenAI Codex (ChatGPT Plus/Pro) | Device code flow |
| MiniMax, Nous Portal | Device code flow |
| xAI Grok, Spotify | Loopback OAuth (port-forward required) |

### Supported Providers (via OAuth)

| Provider | Auth Command | Cost Model |
|----------|-------------|------------|
| xAI Grok | `hermes auth add xai-oauth` | SuperGrok subscription ($30/mo) |
| OpenAI Codex | `hermes model` → OpenAI Codex | ChatGPT subscription |
| GitHub Copilot | `hermes model` → GitHub Copilot | Copilot subscription |
| Google Gemini | `hermes model` → Google Gemini (OAuth) | Free tier available |
| Anthropic | `hermes model` → Anthropic | Claude Max + extra credits |
| Nous Portal | `hermes auth add nous` | Nous subscription |

### Supported Providers (via API Key)

Any provider can also be configured with an API key via environment variables:

```toml
[agent]
command = "hermes-acp"
working_dir = "/home/agent"
env = { XAI_API_KEY = "${XAI_API_KEY}" }
```

## Provider Switching

Switch providers without restarting the pod:

```bash
kubectl exec -it <pod> -- hermes model
```

## Credential Persistence

Hermes stores OAuth tokens in `~/.hermes/`. The OpenAB Helm chart's default persistence covers this automatically (PVC mounted at `workingDir`).

If deploying manually (without the Helm chart), mount persistent storage at `/home/agent` or `/home/agent/.hermes`:

```yaml
volumes:
- name: hermes-credentials
persistentVolumeClaim:
claimName: hermes-credentials-pvc
volumeMounts:
- name: hermes-credentials
mountPath: /home/agent/.hermes
```

## Advantages

- **Cost**: SuperGrok $30/mo flat rate vs pay-per-token API pricing
- **Multi-provider**: 30+ providers accessible through one agent
- **Zero auth complexity**: Hermes handles OAuth + token refresh
- **Multi-modal**: TTS, image gen, video gen via the same OAuth token
- **Fallback chains**: Auto-switch providers on failure
Loading