config.json Reference
This is the reference for ~/.open-ace/config.json, the application-configuration file of the Open ACE server. It covers every field of the current sample (config/config.json.sample) and the behavior notes from the former config/CONFIG_GUIDE.md (absorbed here).
Location and Precedence
- Default path:
~/.open-ace/config.json. The directory can be moved with theOPENACE_CONFIG_DIRenvironment variable (the Kubernetes manifests set it to/home/open-ace/.open-ace, a mounted PVC). - Configuration priority: environment variables > config.json > built-in defaults. Verified consumers:
DATABASE_URL(or the split setDB_HOST/DB_PORT/DB_NAME/DB_USER/DB_PASSWORD) overrides anydatabase.*setting in config.json — the docker entrypoint andscripts/shared/config.pyboth resolve the database URL in that order.SECRET_KEYset in the environment wins over thesecret_keyfield.DATA_FETCH_INTERVAL/DATA_FETCH_ENABLEDoverride thedata_fetchsection.
- In Docker, the entrypoint generates config.json on first start from the environment (
PORTbecomesserver.web_port,SERVER_IPbuildsserver.server_url, secrets are auto-generated and persisted). The container itself always listens on 19888;PORTonly maps the host port. - Division of labor with ENV_REFERENCE.md: environment variables own deployment-level concerns (ports, database, security mode, secrets — see
.env.examplefor Docker Compose), while config.json owns application behavior (workspace, alerts, integrations, feature switches). This document is the authoritative field table for config.json. - Application readers cache config.json for up to 60 seconds (
app/utils/config.py), so most edits take effect within a minute without restart. Exceptions that require a restart: the autonomous scheduler is started once at boot (autonomous.enabled).
Top-Level Fields
| Field | Description | Example / default |
|---|---|---|
host_name | Host identity used to attribute data from different machines. This is the only hostname field — all tools' data is attributed to it; do not duplicate hostnames under tools.*. | localhost, server-01 |
secret_key | Flask session-signing key. The SECRET_KEY environment variable takes precedence. Rotate with care — rotation invalidates all logged-in sessions. | random string |
server.*
| Field | Description | Default |
|---|---|---|
server.upload_auth_key | Upload authentication key, used to authenticate data uploaded by remote machines (the X-Auth-Key header of /api/upload/batch) | random string |
server.server_url | Server address; remote machines must be configured with it | http://192.168.1.100:19888 |
server.web_port | Web service port | 19888 |
server.web_host | Web bind address | 0.0.0.0 |
server.events_ingest_key | Shared secret for the scheduler → web SSE event ingest (autonomous activity panel). Must be at least 32 characters; shorter values are ignored | "" |
server.events_ingest_url | Ingest URL the scheduler forwards autonomous SSE events to | "" |
server.events_ingest_trusted_sources | List of trusted source specifications allowed to post ingest events | [] |
database.*
| Field | Description | Default |
|---|---|---|
database.type | Database type: sqlite or postgresql | sqlite |
database.path | SQLite database path (SQLite only) | ~/.open-ace/ace.db |
database.url | PostgreSQL connection URL (PostgreSQL only) | null |
Note: the DATABASE_URL environment variable takes precedence over the config file. If DATABASE_URL is set, the database settings in config.json are ignored.
SQLite example:
{
"database": {
"type": "sqlite",
"path": "~/.open-ace/ace.db"
}
}
PostgreSQL example:
{
"database": {
"type": "postgresql",
"url": "postgresql://user:password@localhost:5432/ace"
}
}
workspace.*
| Field | Description | Default |
|---|---|---|
workspace.enabled | Enable the workspace feature | false |
workspace.url | Workspace service address | http://localhost:8080 |
workspace.isolation | Isolation between users: {"level": ..., "backend": ...}, see the table below and WORKSPACE_ISOLATION.md | {"level": "none", "backend": "shared"} |
workspace.port_range_start | First port of the per-user webui port pool | 3100 |
workspace.port_range_end | Last port of the per-user webui port pool | 3200 |
workspace.max_instances | Maximum concurrently running webui instances | 30 |
workspace.idle_timeout_minutes | Auto-shutdown time for idle instances (minutes) | 30 |
workspace.cleanup_interval_minutes | Cleanup sweep interval for idle instances | 5 |
workspace.token_secret | Token-signing secret (use a strong random string) | "" |
workspace.webui_path | Explicit path to the qwen-code-webui installation (auto-detected when empty) | "" |
In multi-user mode, Open ACE starts an independent qwen-code-webui process for each user, running as that user's system_account. This ensures:
- Each user only sees their own qwen projects and conversation history
- User actions are recorded in the qwen logs under the correct identity
- Data isolation and audit traceability in multi-user environments
workspace.isolation: level and backend (each backend belongs to exactly one level; a mismatched pair, or any removed legacy key multi_user_mode / required_isolation_level / os_user_confinement / sandbox_tier / confinement_*, makes the server refuse to start and names the replacement):
| level | backend | What it needs | Available in the Docker install |
|---|---|---|---|
none | shared | Nothing (default) | ✅ |
os_user | plain | Per-user system accounts + the openace-webui-launch wrapper (provided by the install script) | ✅ (root overlay) |
os_user | bwrap | Linux + systemd + bubblewrap >= 0.8 + webui_callback_url + the confinement wrapper | ❌ |
sandboxed | local-gvisor | Same as bwrap + Docker + the gVisor runtime + the local-gvisor section of the root policy file | ❌ |
sandboxed | local-kata | Same as bwrap + Docker + /dev/kvm + Kata >= 3.32 + the local-kata section of the root policy file | ❌ |
sandboxed | opensandbox | OpenSandbox on Kubernetes + webui_image from sandbox-backends.json + webui_callback_url | ✅ |
Optional keys: tier (opensandbox only); limits (memory / cpu_percent / tasks) and egress_allow (bwrap / local-gvisor / local-kata only); container_webui (local-gvisor / local-kata only).
Single-user example:
{
"workspace": {
"enabled": true,
"url": "http://localhost:8080",
"isolation": {"level": "none", "backend": "shared"}
}
}
Multi-user example:
{
"workspace": {
"enabled": true,
"url": "http://localhost",
"isolation": {"level": "os_user", "backend": "plain"},
"port_range_start": 3100,
"port_range_end": 3200,
"max_instances": 30,
"idle_timeout_minutes": 30,
"token_secret": "generate-a-strong-random-secret-key-here"
}
}
Other Sections
| Field | Description | Default |
|---|---|---|
data_fetch.interval | Data fetch interval in seconds (minimum 60) | 300 |
data_fetch.enabled | Enable the in-app data fetch scheduler | true |
quota_enforcement.interval | Quota enforcement sweep interval in seconds | 60 |
quota_enforcement.enabled | Enable quota enforcement | true |
autonomous.enabled | Enable the AI autonomous development feature (restart required) | true |
autonomous.acceptance_verification_enabled | Enable post-merge acceptance verification in the autonomous workflow | true |
run_timeline.enabled | Persist remote-session run timelines | false |
model_gateway.enabled | Enable the LiteLLM-compatible model gateway | false |
policy.enabled | Enable the central policy & approval feature | false |
policy.approval_ttl_seconds | Default lifetime of a policy approval (a rule may override it) | 3600 |
insights.temperature / insights.max_tokens | Sampling parameters for insight generation | 0.3 / 4096 |
data_fetch.* and quota_enforcement.* can be overridden by the DATA_FETCH_INTERVAL / DATA_FETCH_ENABLED and QUOTA_ENFORCEMENT_INTERVAL / QUOTA_ENFORCEMENT_ENABLED environment variables, following the precedence above.
alerts.*
| Field | Description | Default |
|---|---|---|
alerts.allow_private_webhook_urls | Whether alert webhooks may target private-network / loopback / link-local addresses. Off by default, blocking SSRF risk. | false |
alerts.dingtalk_webhook_secret | Global signing secret for DingTalk custom robots. Empty sends as a plain webhook; when set, timestamp / sign are appended before sending. Users may also set their own secret in "alert preferences" (stored encrypted in the webhook URL as openace_dingtalk_secret=<secret>), which takes precedence over this global value. | "" |
alerts.webhook_secret | HMAC-SHA256 shared secret for generic (non-Feishu, non-DingTalk) webhooks. When set, request bodies are signed and the signature is sent in the X-OpenACE-Signature header so receivers can verify origin; empty means no signing. | "" |
By default, alert webhooks only allow publicly reachable
http(s)URLs. Feishu / Lark and DingTalk group-robot webhooks work directly; if you really need to push to an intranet address, explicitly turn onalerts.allow_private_webhook_urlsand control access at the network layer.
tools.*
| Field | Description | Default |
|---|---|---|
tools.openclaw.enabled | Enable OpenClaw | true |
tools.openclaw.token_env | Environment variable name for the OpenClaw API token | OPENCLAW_TOKEN |
tools.openclaw.gateway_url | OpenClaw Gateway address | http://localhost:18789 |
tools.claude.enabled | Enable Claude | true |
tools.qwen.enabled | Enable Qwen | true |
feishu.* and dingtalk.*
Both integrations support user/group name resolution in imported sessions, manual or scheduled organization-structure sync, and (DingTalk) alert-center robot pushes. Neither includes Feishu SSO login. The full field tables, setup steps, and troubleshooting live in the dedicated guides:
- Feishu:
feishu.app_id,feishu.app_secret,feishu.org_sync_enabled(defaultfalse),feishu.org_sync_tenant_id(default1),feishu.org_sync_interval_minutes(default60) — see FEISHU_CONFIG.md - DingTalk:
dingtalk.app_key,dingtalk.app_secret,dingtalk.org_sync_enabled(defaultfalse),dingtalk.org_sync_tenant_id(default1),dingtalk.org_sync_interval_minutes(default60),dingtalk.org_sync_root_dept_id(default"1") — see DINGTALK_CONFIG.md
Getting Started
-
Copy the sample configuration file:
cp config/config.json.sample ~/.open-ace/config.json -
Edit
~/.open-ace/config.json:- Set
host_nameto the machine's hostname - Generate a random
upload_auth_key - Configure other optional parameters as needed
- Set
-
Start the service:
python3 server.py