Butter is a workspace-aware AI agent orchestration service built on the Butterfly framework and powered by Google ADK. It runs configurable agent workflows, exposes them through HTTP/RPC and chat channels, and provides a dashboard-oriented backend for operating agents across workspaces.
- Orchestrates LLM, sequential, parallel, and loop-style agent workflows.
- Scopes agents, model providers, channels, cron jobs, tokens, sessions, and execution history by workspace.
- Connects agents to MCP servers, remote agents, chat channels, and daemon workers.
- Persists sessions, memory, auth, workspace data, cron jobs, and invocation history with MongoDB.
- Uses Redis for dashboard auth sessions and runtime channel selections.
- Supports streaming chat, scheduled runs, object storage, tracing, and optional Langfuse integration.
- Go 1.25+
- MongoDB
- Redis
- buf CLI when regenerating protobuf code
- Optional S3-compatible storage for uploaded assets and ADK artifacts
Copy the environment template and point it at the YAML config you want to run:
cp .env.example .envThe sample .env.example uses BUTTERFLY_CONFIG_FILE_PATH=./config/butter.yaml.
You can either place your runtime config there or change the variable to an
existing file such as ./config.yaml.
Most service settings live in the YAML config, including auth bootstrap,
storage, tracing, and the optional root apiToken. Workspace-scoped agent,
MCP, remote agent, channel, model provider, cron, API token, and daemon
configuration is stored through the runtime config repository.
go mod tidy
export $(grep -v '^#' .env | xargs)
go run ./cmd/butterVerify the service is up:
curl http://127.0.0.1:8080/pingExpected response:
{"service":"butter","message":"pong"}When auth or API tokens are enabled, application endpoints require an
Authorization: Bearer <token> header. Workspace-scoped requests should also
send X-Workspace-ID: <workspace-id>.
Butter can delegate work to daemon-backed remote agents. Start a daemon client with:
go run ./cmd/butter-daemon --url http://localhost:8081/api --token bt_daemon_runtime_secretThe main HTTP/dashboard API continues to listen on :8080. The daemon worker
uses the h2c listener on :8081 so bidirectional ConnectRPC streams can run over
cleartext HTTP/2.
For container deployments, --url and --token can also be supplied through
environment variables:
docker run -d \
--name butter-daemon \
--restart unless-stopped \
-e BUTTER_DAEMON_URL=http://host.docker.internal:8081/api \
-e BUTTER_DAEMON_TOKEN=bt_daemon_runtime_secret \
-v /tmp/butter-daemon-workdirs:/tmp/butter-daemon-workdirs \
ghcr.io/orvice/butter-daemon:mainSee docs/daemon.md for the full daemon setup and deployment guide.
Before starting a worker, create a workspace-scoped DaemonRuntime, then issue
a runtime token for it. The token is a dedicated API_TOKEN_KIND_DAEMON token
with daemon:connect scope; it is accepted only by the daemon gRPC endpoint and
cannot call the HTTP API. The token determines the authoritative workspace and
daemon runtime id during registration.
Daemon-backed remote agents choose a runtime plus an ACP runtime (opencode or
codex). The server sends that choice in each task. The daemon has built-in ACP
profiles for opencode acp and codex-acp; custom local config can override or
extend those profiles:
executors:
acp:
- runtime: opencode
command: opencode
args: ["acp"]
permission_policy: deny
fs:
read: true
write: true
terminal: true
shell:
work_dir: /path/to/repowork_dir is currently created by the server per session under /tmp and sent
as an absolute path for ACP tasks. In this interim model, the daemon must run on
the same host/container filesystem as the server, or both processes must mount a
shared volume at the same absolute path, otherwise the local ACP process will not
be able to chdir into the server-created directory. Legacy
executors.opencode config and capability in ACP profiles are still accepted,
but new configs should use executors.acp[].runtime.
The dashboard frontend lives in front. For local development, the
recommended setup is to keep VITE_API_BASE_URL empty and let the Vite dev
server proxy /api and /ping to the backend using VITE_DEV_PROXY_TARGET:
VITE_API_BASE_URL=
VITE_DEV_PROXY_TARGET=http://localhost:8080Then run:
cd front
cp .env.example .env.local
npm install
npm run devSee front/README.md for the full local proxy behavior and direct API call alternative.
Run tests:
go test ./...Regenerate protobuf code when proto definitions change:
buf generateThe Makefile also provides:
make build
make buf- docs/app.md - product and capability overview
- docs/architecture.md - system architecture
- docs/api.md - API reference
- docs/storage.md - object storage, static assets, and artifacts
- docs/project-structure.md - repository layout
See LICENSE for details.