AI Decision System
Replayable, offline-verifiable records for AI-assisted go/no-go decisions: experiment promotions, typed model answers and human-approved actions.
코딩 에이전트를 위한 홈
A home for your coding agent. Claude Code shouldn't stop when your laptop sleeps — Open AgentHub gives your agent a secure, self-hosted place to live and work 24/7, with access to your repos, tools, a
개발 도구C# · JavaScriptGitHub @open-agenthub온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
A home for your coding agent. Claude Code shouldn't stop when your laptop sleeps — Open AgentHub gives your agent a secure, self-hosted place to live and work 24/7, with access to your repos, tools, and internal resources. You supervise from anywhere.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
A home for your coding agent. Be your own digital team lead.
Everybody uses coding agents — but only while their laptop is open. What about the other
16 hours of the day? The weekend? The time between meetings? Cloud chat AIs can't help
there: they have no access to your git workspaces, can't commit, can't run your tests,
can't reach company-internal resources.README 전문 보기 ↗A home for your coding agent. Be your own digital team lead.
Website · Quick start · Features · How it works · Security · Pricing
Everybody uses coding agents — but only while their laptop is open. What about the other 16 hours of the day? The weekend? The time between meetings? Cloud chat AIs can't help there: they have no access to your git workspaces, can't commit, can't run your tests, can't reach company-internal resources.
Open AgentHub is the missing piece: a secure place where your agent lives. Each agent runs 24/7 in an isolated Kubernetes pod with access to your work environment — your repos, your credentials, your tools. Kick off a research task before you go to bed. Answer your agent's questions from your phone between meetings. Schedule recurring jobs for the night shift.
Browser/Phone ──HTTPS/WSS──► Backend (C# / ASP.NET Core) ──K8s API──► Agent pod
Vue 3 + xterm.js - Auth (OIDC, any provider) - isolated, unprivileged
- Session orchestration - git + ssh + selected CLI
- WS terminal proxy - session-agent (PTY+WS)
- Claude Code, Codex, Cursor, OpenClaw, or OpenCode
- selected secrets/MCP mounted
Auto authentication. Migrated Claude sessions
may retain internal legacy Auto until explicitly changed; new sessions cannot select it.mcp/agenthub stdio server and a personal
API token; when enabled, in-session agents also get the built-in agenthub_sessions MCP.Prebuilt images come from ghcr.io/open-agenthub/open-agenthub/*; the chart from our
Helm repository:
helm repo add agenthub https://open-agenthub.github.io/open-agenthub
helm install agenthub agenthub/open-agenthub -n agenthub --create-namespace \
--set postgres.password=$(openssl rand -hex 16) \
--set ingress.host=hub.your-org.example
Keep the generated Postgres password: on a later helm upgrade pass --reuse-values (or
the same password) — Postgres keeps the password it was initialised with.
Object storage is strongly recommended. Without it the hub runs, but sessions cannot be resumed in a fresh pod, finished sessions keep no history, and uploaded session files and artifacts disappear with the agent pod. Either point
s3.*at a provider you already run, or let the chart deploy Garage — see object storage below. The quickstart scripts of Option B set this up automatically.
The all-in-one quickstart sets up a single-node cluster and deploys Open AgentHub with persistent Postgres and object storage (recommended: 4 vCPU / 6 GB RAM — good for up to ~6 users):
| Platform | Command | Cluster |
|---|---|---|
| Linux | curl -fsSL https://open-agenthub.github.io/install.sh | sh | installs k3s |
| macOS | curl -fsSL https://open-agenthub.github.io/install.sh | sh | k3d in Docker Desktop |
| Windows | iwr -useb https://open-agenthub.github.io/install.ps1 | iex | k3d in Docker Desktop |
The scripts are safe to re-run (generated passwords and storage keys are kept) and never
deploy into whatever cluster your current kubectl context points at. To deploy into an
existing cluster instead, set AGENTHUB_KUBE_CONTEXT=<context> (Linux/macOS). Object
storage can be skipped with AGENTHUB_OBJECT_STORAGE=0 — not recommended.
https://<your-host>. Without one (the quickstart
default): kubectl -n agenthub port-forward svc/agenthub-frontend 8080:80 →
http://localhost:8080 (the quickstart prints the command with the right --context).
The frontend proxies /api and /ws to the backend, so one port-forward is enough.agenthub-api-key; the UI asks for it once per browser session and it acts as the
admin user admin. helm status agenthub -n agenthub prints how to read it:
kubectl -n agenthub get secret agenthub-api-key -o jsonpath='{.data.api-key}' | base64 -d; echo
The backend refuses to start with no login configured at all; auth.insecureDevMode=true
turns the login off for local development only (docs/no-oidc-api-key.md).helm upgrade agenthub agenthub/open-agenthub -n agenthub --reuse-values \
--set oidc.authority=<issuer-url> \
--set oidc.clientId=<client-id> \
--set oidc.audience=<expected-audience>
codex login --device-auth, Cursor uses
agent login, OpenClaw uses openclaw models auth add, and OpenCode uses
opencode auth login (choose OpenCode Go and paste the console key).All configuration values (host, TLS issuer, images, S3, OIDC, resource limits) live in
helm/open-agenthub/values.yaml.
S3-compatible object storage is recommended for every installation: it enables session resume, history of finished sessions, persistent session files and artifact uploads. The quickstart scripts (Option B) deploy and bootstrap it automatically.
Point s3.* at a provider you already run, or let the chart deploy one: with
objectStorage.enabled=true it brings up a single-node Garage
(with PVCs) and wires s3.serviceUrl, s3.accessKey and s3.secretKey to it. Garage creates
neither a layout nor a bucket nor a key by itself, so that one-time bootstrap is a step of its
own:
AK=GK$(openssl rand -hex 12); SK=$(openssl rand -hex 32) # keep these for later upgrades
helm upgrade agenthub agenthub/open-agenthub -n agenthub --reuse-values \
--set objectStorage.enabled=true \
--set-string objectStorage.accessKey=$AK,objectStorage.secretKey=$SK \
--set-string objectStorage.rpcSecret=$(openssl rand -hex 32),objectStorage.adminToken=$(openssl rand -hex 16)
kubectl -n agenthub rollout status statefulset/garage
garage() { kubectl -n agenthub exec garage-0 -- /garage "$@"; }
garage layout assign -z dc1 -c 18GB "$(garage node id -q | cut -d@ -f1)"
garage layout apply --version 1
garage bucket create agenthub
garage key import --yes "$AK" "$SK" -n agenthub-key
garage bucket allow --read --write --owner agenthub --key agenthub-key
kubectl -n agenthub rollout restart deployment/agenthub-backend
setup-dev.sh / setup-dev.ps1 do the same for development (--with-object-storage,
-WithObjectStorage), generate the credentials, and skip whatever is already in place on a
redeploy.
Open AgentHub speaks standard OIDC: the frontend runs the Authorization Code Flow with
PKCE (public client, no secret), the backend validates the JWT access token against
oidc.authority / oidc.audience. The user's preferred_username claim is the tenant
key. Register the following in your provider:
https://<host>/auth/callbackhttps://<host>https://<host>agenthub, client type
OpenID Connect, Client authentication: Off (public), Standard Flow enabled,
PKCE method S256 (Advanced → Proof Key for Code Exchange).aud=agenthub: Client scopes →
agenthub-dedicated → Add mapper → Audience, included client audience: agenthub.helm upgrade agenthub agenthub/open-agenthub -n agenthub --reuse-values \
--set oidc.authority=https://keycloak.example.com/realms/myrealm \
--set oidc.clientId=agenthub \
--set oidc.audience=agenthub
agenthub, supported account types
as needed. Platform Single-page application with redirect URI
https://<host>/auth/callback (SPA platform = PKCE without secret).api://<application-client-id>,
scope name e.g. access. (Without your own scope, Entra issues access tokens for
Microsoft Graph, which Open AgentHub cannot validate.)helm upgrade agenthub agenthub/open-agenthub -n agenthub --reuse-values \
--set oidc.authority=https://login.microsoftonline.com/<tenant-id>/v2.0 \
--set oidc.clientId=<application-client-id> \
--set oidc.audience=api://<application-client-id> \
--set oidc.scope="openid profile email api://<application-client-id>/access"
Note: Entra ID puts the username into preferred_username (usually the UPN) — works
out of the box as the tenant key.
https://<host>,
authorized redirect URI https://<host>/auth/callback.helm upgrade agenthub agenthub/open-agenthub -n agenthub --reuse-values \
--set oidc.authority=https://accounts.google.com \
--set oidc.clientId=<client-id>.apps.googleusercontent.com \
--set oidc.audience=<client-id>.apps.googleusercontent.com
⚠️ Caveat: Google issues opaque access tokens (not JWTs); only its ID tokens are verifiable JWTs. Open AgentHub currently validates the access token, so Google login requires the backend to validate the ID token instead — tracked as an open issue. Use Keycloak or Entra ID for production today, or put Google behind Keycloak/Dex as an identity broker (Keycloak's "Identity Providers → Google" works out of the box).
# Build & push images (e.g. from a fork)
REG=registry.example.com/agenthub TAG=0.1.0
docker build -f backend/Dockerfile -t $REG/backend:$TAG .
docker build -t $REG/frontend:$TAG ./frontend
docker build -f agent-runtime/claude/Dockerfile -t $REG/agent-runtime-claude:$TAG ./agent-runtime
docker build -f agent-runtime/codex/Dockerfile -t $REG/agent-runtime-codex:$TAG ./agent-runtime
docker build -f agent-runtime/cursor/Dockerfile -t $REG/agent-runtime-cursor:$TAG ./agent-runtime
docker build -f agent-runtime/openclaw/Dockerfile -t $REG/agent-runtime-openclaw:$TAG ./agent-runtime
docker build -t $REG/browser:$TAG ./browser-runtime
docker push $REG/backend:$TAG && docker push $REG/frontend:$TAG
docker push $REG/agent-runtime-claude:$TAG && docker push $REG/agent-runtime-codex:$TAG
docker push $REG/agent-runtime-cursor:$TAG && docker push $REG/agent-runtime-openclaw:$TAG
docker push $REG/browser:$TAG
# image.registry/image.tag select all six defaults. Full runtime overrides are
# agent.images.claude, agent.images.codex, agent.images.cursor, and agent.images.openclaw. Browser uses its
# explicit repository override. For a private registry, create the pull secret in BOTH
# namespaces and set image.pullSecret.
helm upgrade --install agenthub helm/open-agenthub -n agenthub --create-namespace \
--set image.registry=$REG --set image.tag=$TAG \
--set browser.image.repository=$REG/browser --set browser.image.tag=$TAG \
--set postgres.password=<pw>
Plain manifests without Helm are available under k8s/ (namespaces, RBAC,
backend, network policies, dev Postgres) — fill in the secrets before applying.
Normally every tool a session wants to use raises a permission prompt — in the web app and, if configured, in your messenger. Auto approve answers those prompts with "allow" automatically, so the agent works without interruption.
It can be set two ways:
The last two apply immediately, no restart: the backend evaluates the flag per permission request. Switching it on also approves the prompts that are already waiting. While it is on, a banner above the terminal offers Turn off.
Recommended only for non-root containers. With Run as root the agent may run any command as root in that container, unattended — combine the two only for a container you would hand over anyway. Auto approve changes nothing about the pod's isolation: network policies, the unprivileged pod spec, and the per-user secret mounts all still apply, so the blast radius stays the session's own container.
What it does not change: the session's own container is still the boundary. Auto approve grants nothing outside it.
Telegram and Signal are community features (free, no license); Slack is part of the
Enterprise edition. All of them notify you when a session waits for input
or finishes, and let you reply and approve permission prompts from your phone. Long
answers are split across several messages; permission prompts expire after ~30 minutes
(answer in the web terminal then). Telegram and Signal require a single backend
replica (backend.replicas=1) — Telegram getUpdates and the Signal receive socket
allow only one consumer, and the chart refuses to render otherwise.
What reaches the chat depends on the runtime, because the thread is opened by a hook inside the session and only interactive sessions wait for anyone:
| Runtime | Waiting for input | Finished / failed | Replies from chat | Permission prompts |
|---|---|---|---|---|
| Claude | yes, with the agent's last message | yes | yes | yes |
| Codex | yes, at the end of every turn, with the agent's last message | yes | yes | yes |
| Cursor | yes, at the end of every turn (generic text — the CLI's stop hook carries no message) | yes | yes | no — Cursor decides approvals from its own allowlist, there is no hook to relay them |
| OpenClaw | no — OpenClaw has no per-turn hook, so no thread is ever opened | no | no | no |
| OpenCode | yes, at the end of every turn, with the agent's last message | yes | yes | yes — the policy plugin asks the hub like the Codex hook |
Autonomous and scheduled sessions never open a thread themselves: nobody is asked anything,
and "finished"/"failed" is posted only where a thread already exists. Details and what was
verified against the pinned CLIs: docs/chat-relay.md.
helm upgrade agenthub agenthub/open-agenthub -n agenthub --reuse-values \
--set chat.telegram.enabled=true --set chat.telegram.botToken=<token> \
--set backend.replicas=1
(Without Helm: env vars Chat__Telegram__Enabled=true, Chat__Telegram__BotToken.)/link <code> to the
bot directly.Per-session forum topics (optional): create a Telegram group, enable Topics, add
the bot as admin with the Manage topics permission, and send /link <code> in the
group — every session then gets its own topic. Note: everyone in a linked group can
reply to sessions and approve permission prompts.
Commands: /new [+repo …] <prompt> (start an autonomous session right from the chat —
leading +name, +group/name, +name#branch or +https://… tokens attach repositories),
/repos [query] (list your GitHub/GitLab projects), /sessions (list), /use <tag>
(route plain replies), !status. Plain messages are typed into the active session's
terminal. Only one backend replica may run Telegram long-polling (a second poller
conflicts on getUpdates).
helm upgrade agenthub agenthub/open-agenthub -n agenthub --reuse-values \
--set chat.signal.enabled=true --set-string chat.signal.number=+15551234567 \
--set backend.replicas=1
POST /v1/register/<number> +
/v1/register/<number>/verify/<token> (SMS/voice code), or link it as a secondary
device via QR code — the exact commands are in the comment block of
helm/open-agenthub/templates/signal-cli.yaml.Reply routing: quote a session message to answer that session; plain replies go to
the newest session (or the one picked with !use). React 👍/👎 on a permission prompt to
allow/deny; quote-reply always for allow-always. Commands: !new [+repo …] <prompt>
(start an autonomous session — leading +name tokens attach repositories),
!repos [query] (list your GitHub/GitLab projects), !sessions, !use <tag>, !status.
Desktop notifications (browser): a notification when a session waits for input or finishes — enable per device under Settings → Notifications.
For a local Kubernetes environment, the setup scripts build backend, frontend, Claude runtime, Codex runtime, Cursor runtime, OpenClaw runtime, OpenCode runtime, and browser images locally, deploy the agenthub-dev Helm release into the agenthub-dev control namespace, and use agenthub-dev-sessions for session pods. They refuse to run unless the active kubectl context is docker-desktop.
On Windows PowerShell:
.\setup-dev.ps1
Use .\setup-dev.ps1 -NoPortForward when you want the checks and deployment without a foreground port-forward. On Bash-compatible shells:
./setup-dev.sh
Use ./setup-dev.sh --no-port-forward for the same non-blocking behavior. The default command checks the backend and frontend, then serves the UI at http://localhost:8080 until you stop the port-forward. PostgreSQL uses ephemeral storage and a generated password for this development release.
The development profile enables header-based test identities so local integration tests can exercise owner, viewer, and collaborator behavior without an external identity provider. This authentication is local-only, guarded by the Development environment, and must not be enabled for a production deployment. The profile is defined in helm/open-agenthub/values-dev.yaml.
To inspect or remove the release:
kubectl -n agenthub-dev get pods
helm uninstall agenthub-dev -n agenthub-dev
kubectl delete namespace agenthub-dev-sessions
Backend: cd backend && dotnet run (uses ~/.kube/config). Frontend:
cd frontend && npm install && npm run dev (Vite proxies /api and /ws to
localhost:8080). Leave Oidc:Authority empty to run without auth — every request acts
as user dev.
| Path | Contents |
|---|---|
backend/ | ASP.NET Core: REST + WS proxy, K8s orchestration, JWT auth |
agent-runtime/ | Separate Claude, Codex, Cursor, OpenClaw, and OpenCode images sharing provider-neutral PTY/WS transport |
browser-runtime/ | Hardened Chromium, Xvfb, VNC, websockify, and cookie checkpoint supervisor |
frontend/ | Vue 3 + Vite + xterm.js, mobile-first |
helm/open-agenthub/ | Helm chart (recommended deployment) |
k8s/ | Plain manifests (namespaces, RBAC, backend, NetworkPolicies) |
ee/ | Enterprise features (commercial license, see below) |
~/.secrets, selected per project and narrowed per session; their values are
masked in uploaded scrollback, transcripts and chat relays (docs/session-secrets.md)./workspace/repo; optional MCP and structured policy configuration follows the
selected provider. A custom glibc image can receive the selected provider runtime by
init-container injection; bash, git, and curl are required.claude, codex, Cursor's agent, or openclaw under a PTY and
serves a WebSocket with scrollback — reconnecting from your phone replays the history.browser_start creates
one browser pod for that live session; no browser resources exist before the request.External clients (Cursor Desktop, Claude Desktop, and similar) can orchestrate sessions
through the stdio MCP under mcp/agenthub/: create, get, list, wait, and delete, authenticated
with a personal API token from Settings → API tokens. Configure AGENTHUB_URL (your
hub origin) and AGENTHUB_TOKEN, and until the package is published to npm run
node <path-to-repo>/mcp/agenthub/server.mjs. The Settings dialog shows a ready-to-paste
mcpServers snippet next to the remote curl examples.
When spawnMcpEnabled is true (Helm / AgentHub:SpawnMcpEnabled, default on), live agent
pods also receive the runtime-owned agenthub_sessions MCP so an in-session agent can spawn
and manage descendant sessions without mounting personal API tokens.
Sessions of one project form a fleet: agents_list, agent_send and agent_inbox let them
find and message each other. A message sent with priority is pushed into the running agent
instead of waiting for its inbox poll, and interrupt stops its current work first; the
session view has a "✉ Messages" panel that does the same for the owner and lists what arrived,
with a badge for the count, so incoming messages never cover the terminal. How a push reaches
the agent depends on the runtime (docs/priority-messages.md):
| Runtime | Priority delivery |
|---|---|
| Claude | the agenthub-fleet mod inside Claude Code submits it as the next prompt (also in chat UI and -p runs); a chat-UI session without the mod gets it over the stream-json pipe |
| Codex, Cursor, OpenClaw | typed into the interactive terminal as a queued prompt; autonomous runs: inbox only |
What could not be pushed stays in the inbox, and the sender is told (deliveredVia: inbox).
When a stored login hits its usage limit, the hub marks the account until the window resets,
moves a running session to another available account of the same provider (per session:
accountFailover: auto|off), and tells the session and the notifiers. New sessions avoid an
exhausted account. How the hub finds out depends on the runtime
(docs/account-limits.md):
| Runtime | Limit detection |
|---|---|
| Claude | the agenthub-fleet mod reads the rate-limit windows Claude Code reports and posts a window at 100 % (AGENTHUB_LIMIT_THRESHOLD) |
| Codex, OpenClaw | the session agent matches the CLI's own usage-limit notice in its output (strings verified against the pinned versions) |
| OpenCode | the same, for OpenCode's Go and free-tier notices; opencode run waits silently at a limit, so the policy plugin prints the notice in unattended sessions |
| Cursor | output patterns, conservative and unverified — the unpinned CLI prints the API's text verbatim |
account_status and account_switch (every MCP server) and PATCH /api/remote/sessions/{id}/credential
do the same by hand; a session may switch itself.
An agent that needs a secret calls secret_request (in-session agenthub_sessions server) rather than
asking in the conversation: the owner gets a question with a link to the pre-filled form, enters the
value in the web app, and the tool learns only that the secret is there and under which name
(docs/session-secrets.md). secrets_list names what the session has.
Agent and billing choices are independent for Interactive, Autonomous, and Scheduled
sessions. Subscription mode mounts only the selected provider's writable authentication
file; a background watcher persists valid login and refresh updates to that user's
provider-specific Secret. Claude login happens through its normal in-container flow;
Codex uses device-code authentication; Cursor uses agent login with
AGENT_CLI_CREDENTIAL_STORE=file; OpenClaw uses interactive auth under ~/.openclaw;
OpenCode uses opencode auth login, whose auth.json the watcher stores.
Open AgentHub does not copy a workstation's real Claude, Codex, Cursor, OpenClaw, or OpenCode
authentication files into the cluster.
API-key mode never mounts the subscription Secret. For provider authentication, Claude
scopes ANTHROPIC_API_KEY to the Claude process and its descendants. Codex
Autonomous/Scheduled runs scope CODEX_API_KEY to codex exec and its descendants, while
Interactive Codex creates an ephemeral file login from the key. Cursor scopes
CURSOR_API_KEY to the Cursor agent process and its descendants. OpenClaw ApiKey mode
injects only the selected existing key (ANTHROPIC_API_KEY, OPENAI_API_KEY, or
CURSOR_API_KEY). OpenCode scopes OPENCODE_API_KEY to the OpenCode process and its
descendants. The shared /shell
receives neither provider API key. This selected-only behavior makes the billing source
deterministic. Subscription avoids API-key billing, but it does not isolate credentials
from the running agent.
Autonomous and Scheduled sessions preflight the selected credential and fail before the
provider CLI starts when it is unavailable, with a non-secret diagnostic.
Automation policies default to deny and separately match built-in tools, MCP tool names,
and shell commands. Claude enforces exact structured shell commands through its native
allowed-tools mechanism plus AgentHub hooks; Codex matches normalized command prefixes with
a managed runtime-owned hook and workspace-write sandbox configuration; Cursor maps
structured policy into ~/.cursor/cli-config.json permission allowlists for Autonomous and
Scheduled runs. Interactive sessions retain their normal provider approval flow and the
existing out-of-band approval path. Provider allowlists and hooks are guardrails, not a
complete container sandbox or a secret-isolation boundary; pod, namespace, RBAC, and
NetworkPolicy isolation remain mandatory.
runAsNonRoot, UID 1000, allowPrivilegeEscalation: false,
readOnlyRootFilesystem, capabilities.drop: [ALL], seccompProfile: RuntimeDefault.
Root sessions are opt-in (per session; disable via agent.allowRootSessions=false):
UID 0 with a writable rootfs and default capabilities, but still no privileged, no
hostPath, no privilege escalation; namespace PSA is then baseline instead of restricted.owner label; users only see/delete their own sessions.automountServiceAccountToken: false).RuntimeClassName to gVisor/Kata (in appsettings/ConfigMap).Provider credentials and authentication files are accessible to code and tools running
as the same agent user. Claude, Codex, Cursor, OpenClaw, and OpenCode provider-process descendants may inherit
the selected ANTHROPIC_API_KEY, CODEX_API_KEY, CURSOR_API_KEY, or OPENAI_API_KEY, and subscription
sessions can read their selected provider auth file. Run only trusted repositories and
prompts when credentials are present. Use pod and network isolation to limit exposure and
blast radius. Writable collaborators can direct the selected session's capabilities and
are part of the same trust boundary.
Selected-only mounting reduces unnecessary exposure; it does not make provider credentials secret from the selected agent or its tools. Root sessions expand the same risk further. Policy hooks can reject unmatched actions but cannot provide credential isolation. Subscription authentication changes the billing source, not this limitation.
Agent session pods use no PVCs (only the bundled Postgres and the optional Garage do).
Results flow back via git push or as artifacts to S3. What is persisted:
claude-state.tgz, codex-state.tgz,
cursor-state.tgz, or openclaw-state.tgz), scrollback.log, transcript.jsonl (the
provider's own conversation file, where the runtime has one — see docs/transcripts.md),
browser-cookies.json, and
artifacts/.... State archives exclude provider authentication files; authentication restore
happens after state restore so stale state cannot replace the current per-user login.
Layout: sessions/{owner-hash}/{sessionId}/...curl. For
arbitrary artifacts the agent calls POST /internal/sessions/{id}/artifact-url?name=...
(token-authenticated). Without S3 configured, sessions still run — resume and history
are simply disabled.The Workspace composer accepts images and documents by file picker, paste, and drag-and-drop, and
an image pasted into the agent terminal is attached too: the file is uploaded to the session and
its path pasted into the CLI, which Claude Code, Codex, OpenCode and OpenClaw turn into an image of
their own (Cursor's TUI does the same, not verified end to end). In the shell, Ctrl+V pastes text
only (docs/terminal-clipboard.md).
Images, PDF, Markdown, plain text and video (MP4 with H.264/AAC, WebM) can be opened in Files
beside Workspace or Terminal; a video plays in the browser's own player and can be seeked.
SVG previews use an image element; arbitrary other file types upload and download without a preview.
See file type safety for the serving boundary and size limits. A managed files MCP gives every supported agent the same
provider-neutral tools: list_display_capabilities, list_files, read_file,
upload_file, present_file, and dismiss_presentation.
Sessions of the same project can read each other's files: list_project_files shows what the
other sessions of the project have made, and fetch_project_file copies one into the calling
session's workspace. Read-only, same owner and same project only, and not for a session that is
shared with someone — see docs/project-files.md.
With S3 configured, session files are persistent. Without S3, their content lives only in
the running agent pod and expires when that pod is gone; the capabilities endpoint reports
the active storage mode and every format that can be displayed graphically. Limits default
to five files per message, 20 MiB per image, 50 MiB per document/message, and 100 MiB per
video (files.maxVideoBytes; without S3 a video is held to the document limit). Videos are
checked by content, not by name — see docs/session-file-video.md.
DOCX, PPTX, and XLSX previews are optional, because they need a separate renderer pod that converts the document to PDF. Off by default; enable it with:
files:
officePreview:
enabled: true
Until it is enabled the UI offers those documents as a download and says so, rather than
appearing to have no opinion about them. PDFs, images, Markdown and plain text are previewed
without the renderer, and an agent can read them through its agenthub_files MCP tools.
The supplied NGINX Ingress allows upload bodies up to 55m via
nginx.ingress.kubernetes.io/proxy-body-size. Override it through
ingress.annotations when an installation needs a different controller-specific value.
Resume recreates the finished session resource with the same selected provider and
billing mode, restores only that provider's state, and then restores selected
authentication. Claude resumes its explicit conversation identifier. Codex resumes the
restored session-local thread and may fall back once to a fresh thread if state is absent
or invalid. Cursor resumes with --resume when a chat id is present and may fall back
once to a fresh launch if that chat is missing. OpenClaw resumes from restored
~/.openclaw state and/or an explicit session id when the CLI accepts one, with one
fresh-session fallback when state is absent. OpenCode resumes with --continue, which picks the
newest top-level session in the restored ~/.opencode database and starts fresh when there is none.
A finished or paused autonomous session can be continued interactively — from the
session page, POST /api/sessions/{id}/convert, the remote API, or the session_convert MCP
tool. Whether the conversation survives depends on the runtime:
| Runtime | Converted to interactive | Keeps the conversation |
|---|---|---|
| Claude | Workspace or terminal | yes — same fixed session id, --resume |
| Codex | TUI | yes — the thread id recorded in the state archive |
| Cursor | TUI | no — new conversation in the restored workspace |
| OpenClaw | TUI | no — new conversation in the restored workspace |
| OpenCode | TUI | yes — --continue resumes the newest top-level session in the restored ~/.opencode database, which is the run's |
Auto-approve is switched off by conversion unless asked to stay: somebody is now there to answer.
Details and the alternatives rejected: docs/session-mode-conversion.md.
Provider runtime hooks call the internal notification endpoint when supported; the
backend sets question_pending=true and fires the configured webhook. The UI shows a
blinking "waiting for your reply" dot.
Internal callback endpoints (/internal/...) use a per-session callback token (header
X-Agent-Token), no user auth, and are deliberately not routed through the ingress.
The NetworkPolicy only allows agent egress to the backend.
Browser configuration, trust boundaries, cookie handling, and diagnostics are documented in Browser operation and security.
Agents can request additional network ports at runtime (e.g. egress to Postgres 5432, or
browser→agent for app development) via the built-in agenthub_network MCP server; the
session owner approves each request and approved ports become per-session NetworkPolicies.
See Dynamic network port requests.
Agents can also start helper containers — a database, a queue, a service under test — with the
container_run/container_list/container_logs/container_stop tools of agenthub_sessions.
The hub builds each pod itself in a namespace of the session's own, with the session's security
context, Pod Security Admission restricted, a ResourceQuota and the session's egress policy;
sessionContainers.enabled switches it off. See Session containers.
AgentHub can also be driven as an MCP server: enable mcp.enabled and AI clients create and
steer sessions on behalf of a signed-in user, authenticated through an OAuth 2.1 server the
instance runs itself. Off by default. See Remote MCP server.
agenthub, claim preferred_username as the
tenant key.cli-config.json allowlists supplement Kubernetes isolation;
they do not replace it.ForcePathStyle.artifact-url + upload exist; a convenient
s3put <file> wrapper script is still missing.git push / artifacts; no file-level workspace
resume (only provider conversation resume through provider-separated state).pods/log).Everything outside ee/ is free forever (AGPL-3.0) and fully functional without a
license. The Enterprise edition adds features for teams — session sharing across your
org, org management, Slack integration — for €6 / user / month (excl. VAT) with a
3-month free trial. See pricing or the
ee/ README.
Contributions are welcome! Please read CONTRIBUTING.md — contributions require agreeing to our CLA (dual licensing under AGPL-3.0 and the commercial license keeps the open-core model possible).
Open AgentHub is an open-core project: the core (everything outside ee/) is free
software under the GNU AGPL-3.0 and fully functional without a license key,
while the code in ee/ is source-available under the commercial
Open AgentHub Enterprise License and powers the enterprise offering
(6 €/user/month excl. VAT, 3-month free trial). Contributions require agreeing to our Contributor
License Agreement — see CONTRIBUTING.md.
All five default agent runtime images include python3, pip and venv from distribution packages.
Create a virtual environment in the workspace for dependencies; see the decision and size impact.
skill-libraryupload_skill.tar.gzget_skillout_dir~/.claude/skillsagenthub_browser MCP starts one isolated
Chromium only when the agent needs it. The same desktop appears beside the chat through
noVNC, while idle sessions consume no browser CPU or memory. Copy and paste work between
your own machine and the remote page: Ctrl/Cmd+C, X and V over the browser pane carry
plain text both ways for anyone allowed to control it
(docs/browser-security.md).docs/session-expiry.md.agent login with a file-backed credential store; OpenClaw uses interactive auth under
~/.openclaw; OpenCode uses opencode auth login. Host authentication files are never
copied into the cluster by the setup scripts./new <prompt>) from your phone via Telegram or Signal (free,
community) — Slack is part of the Enterprise edition — plus browser desktop
notifications. Claude, Codex, Cursor and OpenCode sessions take part; OpenClaw has no
hook for it. Setup and per-runtime details below.