# 🔧 Configuration Guide ## 1. LLM Credentials (`.env`) > [!NOTE] > Create `openspace/.env` from [`../.env.example`](../.env.example) and set at least one LLM API key. Resolution priority (first match wins): | Priority | Source | Example | |----------|--------|---------| | **Tier 1** | `OPENSPACE_LLM_*` env vars | `OPENSPACE_LLM_API_KEY=sk-xxx` | | **Tier 2** | Provider-native env vars | `OPENROUTER_API_KEY=sk-or-xxx` | | **Tier 3** | Host agent config | `~/.nanobot/config.json` / `~/.openclaw/openclaw.json` | > [!IMPORTANT] > Tier 2 blocks Tier 3 — if `.env` has a provider key, host agent config is skipped. ```bash # Provider-native — litellm reads automatically OPENROUTER_API_KEY=sk-or-v1-xxx # Or: OpenSpace-native — higher priority, same effect OPENSPACE_LLM_API_KEY=sk-or-v1-xxx ``` ## 2. Environment Variables Set via `.env`, MCP config `env` block, or system environment. Set `OPENSPACE_SKIP_DOTENV=1` in the process environment before startup to ignore local `.env` files; it cannot be enabled from `.env` itself. | Variable | Description | Default | |----------|-------------|---------| | `OPENSPACE_MODEL` | LLM model | `openrouter/anthropic/claude-sonnet-4.5` | | `OPENSPACE_SKIP_DOTENV` | Disable automatic `openspace/.env` and CWD `.env` loading | `false` | | `OPENSPACE_LLM_API_KEY` | LLM API key (Tier 1 override) | — | | `OPENSPACE_LLM_API_BASE` | LLM API base URL | — | | `OLLAMA_API_BASE` | Local Ollama endpoint for `ollama/*` models | `http://127.0.0.1:11434` | | `OLLAMA_API_KEY` | Placeholder key for Ollama-compatible clients | `ollama` | | `OPENSPACE_LLM_EXTRA_HEADERS` | Extra LLM headers (JSON) | — | | `OPENSPACE_LLM_CONFIG` | Arbitrary litellm kwargs (JSON) | — | | `OPENSPACE_CLOUD_MODE` | Cloud mode, either `off` or `live` | `off` | | `OPENSPACE_CLOUD_BASE_URL` | Cloud service root URL; do not include `/api`, `/api/v1`, or `/api/v2` | `https://open-space.cloud` | | `OPENSPACE_CLOUD_API_KEY` | Cloud agent API key (`X-API-Key`) | — | | `OPENSPACE_CLOUD_TELEMETRY_MODE` | Cloud telemetry mode, either `off` or `outbox` | `off` | | `OPENSPACE_MAX_ITERATIONS` | Max agent iterations per task | `20` | | `OPENSPACE_BACKEND_SCOPE` | Enabled backends (comma-separated) | `shell,mcp,meta` | | `OPENSPACE_HOST_SKILL_DIRS` | Agent skill directories (comma-separated) | — | | `OPENSPACE_CAPTURE_SKILL_DIR` | Directory where CAPTURED evolution writes newly authored skills; falls back to the first host skill dir, then `/.openspace/skills` | — | | `OPENSPACE_WORKSPACE` | Project root for logs/workspace | — | | `OPENSPACE_SHELL_CONDA_ENV` | Conda env for shell backend | — | Provision cloud credentials with `openspace-cloud-auth bootstrap-agent-key --email you@example.com --agent-name openspace-local-agent`. The command writes `OPENSPACE_CLOUD_MODE=live`, `OPENSPACE_CLOUD_BASE_URL`, and `OPENSPACE_CLOUD_API_KEY` locally without printing the raw key. | `OPENSPACE_SHELL_WORKING_DIR` | Working dir for shell backend | — | | `OPENSPACE_CONFIG_PATH` | Custom grounding config JSON | — | | `OPENSPACE_MCP_SERVERS_JSON` | MCP server definitions (JSON) | — | | `ANTHROPIC_API_KEY` | Optional Anthropic key for `web_search` server-side search | — | | `TAVILY_API_KEY` / `BRAVE_SEARCH_API_KEY` / `SERPAPI_API_KEY` | Optional fallback search provider keys | — | | `OPENSPACE_WEB_FETCH_MODEL` | Optional model override for applying prompts to fetched pages | — | | `OPENSPACE_ENABLE_RECORDING` | Record execution traces | `true` | | `OPENSPACE_MAX_OUTPUT_TOKENS_RECOVERY_LIMIT` | Number of no-tool max-output recovery nudges before stopping a turn | `3` | | `OPENSPACE_FORCE_TOOL_ON_MAX_OUTPUT_RECOVERY` | Force `tool_choice=required` on max-output recovery calls when tools are available | `false` | | `OPENSPACE_DISABLE_REASONING_ON_REQUIRED_TOOL_CHOICE` | Suppress provider reasoning controls only on required-tool calls | `false` | | `OPENSPACE_OPENROUTER_DISABLE_REASONING_ON_REQUIRED_TOOL_CHOICE` | OpenRouter-specific version of required-tool reasoning suppression | `false` | | `OPENSPACE_BENCH_FINALIZE_NUDGE_ENABLED` | Enable a benchmark-only best-artifact finalization nudge during long single-task runs | `false` | | `OPENSPACE_BENCH_FINALIZE_NUDGE_AFTER_SEC` | Seconds before the benchmark finalization nudge may be injected; `0` disables time-based triggering | `0` | | `OPENSPACE_BENCH_FINALIZE_NUDGE_AFTER_ITERATION` | Model iteration before the benchmark finalization nudge may be injected; `0` disables iteration-based triggering | `0` | | `OPENSPACE_BENCH_FINALIZE_NUDGE_MAX` | Maximum benchmark finalization nudges per turn | `1` | | `OPENSPACE_BENCH_FINALIZE_STOP_AFTER_ITERATIONS` | Stop a benchmark turn this many iterations after a finalization nudge so external verifiers can score the best artifact; `0` disables | `0` | | `OPENSPACE_BENCH_FINALIZE_STOP_AFTER_SEC` | Stop a benchmark turn this many seconds after a finalization nudge; `0` disables | `0` | | `OPENSPACE_BENCH_STRICT_NO_TOOL_FINAL` | After a benchmark finalization nudge, require a later tool action before accepting a no-tool final response; retry with the configured fallback model when available | `false` | | `OPENSPACE_BENCH_NO_TOOL_FINAL_MAX_NUDGES` | Number of tool-backed finalization nudges before switching to fallback model or stopping as unresolved | `2` | | `OPENSPACE_EVOLUTION_STORAGE_ROOT` | Root used to resolve `.openspace/openspace.db`, `.openspace/evidence.db`, staging, and backups | workspace | | `OPENSPACE_SKILL_STORE_DB_PATH` | Explicit SkillStore SQLite path; also anchors the evolution storage root when no storage root is set | — | | `OPENSPACE_EVOLUTION_EVIDENCE_DB_PATH` | Explicit evidence SQLite path; takes precedence over storage-root resolution for evidence | — | | `OPENSPACE_EVOLUTION_EVIDENCE_ENABLED` | Enable durable evolution evidence collection | `true` | | `OPENSPACE_EVOLUTION_TRIGGERS_ENABLED` | Enable durable TriggerJob creation from evidence checkpoints; set `false` to keep evidence ingest but pause trigger jobs | `true` | | `OPENSPACE_EVOLUTION_ENGINE_ENABLED` | Enable TriggerJob processing through decision, admission, staged authoring, validation, and commit | `true` | | `OPENSPACE_EVOLUTION_MODE` | Evolution mode: `audit_only` audits only, `fix_only` commits explicit direct FIX only, `autonomous` allows all validated admitted actions | `autonomous` | | `OPENSPACE_EVOLUTION_ALLOW_SINGLE_OBSERVATION_CAPTURE` | Allow a validated CAPTURED proposal, and DERIVED proposal with clear divergence, to persist as a provisional skill from its origin observation. When disabled, automatic proposals remain audit-only candidates; recurrence never promotes them | `true` | | `OPENSPACE_EVOLUTION_CAPTURE_SEMANTIC_VALIDATION_ENABLED` | Run one independent semantic review per staged CAPTURED proposal; approval requires exact validation-ref binding, no unsupported executable claims, reusable scope, and no incomplete high-impact safeguard | `true` | | `OPENSPACE_EVOLUTION_CAPTURE_SEMANTIC_VALIDATION_MAX_TOKENS` | Maximum output tokens for the independent CAPTURED semantic review | `2048` | | `OPENSPACE_SKILL_TRUST_PROMOTION_MIN_INDEPENDENT_SUCCESSES` | Independent successful observations required to promote a provisional skill to trusted; a CAPTURED origin counts only when its source-validation contract passes admission | `2` | | `OPENSPACE_EVOLUTION_FINAL_DRAIN_LIMIT` | Number of open post-execution evolution jobs to retry before a short-lived runtime exits; `0` disables the extra drain | `0` | ## 3. Task Runtime Context Defaults These are `OpenSpaceConfig` / JSON config fields rather than environment variables. They are useful for benchmark adapters that need a narrower task-solving surface while keeping normal interactive OpenSpace defaults unchanged. | Field | Description | Default | |-------|-------------|---------| | `active_tool_names` | Optional hard allowlist of tool names exposed to the agent for a turn | — | | `capture_skill_dir` | Directory where post-execution CAPTURED skills should be staged and committed for this runtime | — | | `execution_analyzer_max_tokens` | Optional ExecutionAnalyzer-only output budget; `OPENSPACE_EXECUTION_ANALYZER_MAX_TOKENS` provides the equivalent environment override | inherit LLM default | | `skill_evolver_max_tokens` | Optional SkillEvolver-only output budget; `OPENSPACE_SKILL_EVOLVER_MAX_TOKENS` provides the equivalent environment override | inherit LLM default | | `policy_deferred_tool_names` | Optional tool names kept behind `tool_search`; use `[]` to avoid deferred-tool discovery | — | | `skills_disabled` | Hide Skill Protocol tools and skill prompt guidance from the task-solving agent | `false` | | `memory_mode` | Optional memory mode override for the task context | — | | `OPENSPACE_EVOLUTION_FINAL_DRAIN_ROUNDS` | Maximum final-drain rounds to run | `1` | | `OPENSPACE_EVOLUTION_FINAL_DRAIN_TIMEOUT_S` | Per-round timeout for the final evolution drain; `0` disables the timeout wrapper | `0` | | `OPENSPACE_EVOLUTION_STARTUP_RETRYABLE_DRAIN_LIMIT` | Number of persisted `failed_retryable` evolution jobs to explicitly retry during startup after stale-job recovery; `0` disables startup retryable drain | `0` | | `OPENSPACE_EVOLUTION_STARTUP_RETRYABLE_DRAIN_ROUNDS` | Maximum startup retryable-drain rounds to run | `1` | | `OPENSPACE_EVOLUTION_STARTUP_RETRYABLE_DRAIN_TIMEOUT_S` | Per-round timeout for startup retryable drain; `0` disables the timeout wrapper | `0` | | `OPENSPACE_EVOLUTION_STARTUP_RETRYABLE_DRAIN_STATUSES` | Comma-separated TriggerJob statuses eligible for startup drain, useful for controlled replay runs that should continue copied `pending` jobs | `failed_retryable` | | `OPENSPACE_EVOLUTION_RECOVERY_STALE_JOB_TIMEOUT_S` | Age in seconds before startup recovery resets a `running` TriggerJob to retryable/failed; lower it when intentionally replaying a freshly interrupted evidence DB | `1800` | | `OPENSPACE_EVOLUTION_BEHAVIOR_EVAL_REQUIRE_REPLAY_RUNNER` | Require an external replay runner before behavior eval can approve replay-backed skill changes. Keep enabled for strict autonomous evolution; set `false` in harnesses that only have deterministic/routing eval available | `true` | | `OPENSPACE_POST_EXECUTION_TIMEOUT_S` | Hard timeout for inline/background post-execution analysis and evolution drain; `0` disables the timeout. If a claimed evolution job is cancelled by this timeout, it is marked retryable instead of being left `running` | `0` | | `OPENSPACE_EVOLUTION_ALLOWED_READ_ROOTS` | Extra evidence file-read roots, separated by the platform path separator | — | | `OPENSPACE_DEFAULT_MAX_RESULT_SIZE_CHARS` | Per-tool result size threshold before persisting large outputs to disk | `50000` | | `OPENSPACE_MAX_TOOL_RESULTS_PER_MESSAGE_CHARS` | Aggregate tool-result text budget kept in the model conversation before replacing large old results with persisted-output previews | `200000` | | `OPENSPACE_TOOL_RESULT_PREVIEW_CHARS` | Preview size included in persisted-output wrappers | `2000` | | `OPENSPACE_LOG_LEVEL` | Log level | `INFO` | ## 3. User Settings (`settings.json`) Use user/project settings for runtime preferences that should persist across runs. These are separate from `openspace/config/*.json`, which configures backend implementation details. Load order, later entries override earlier ones: | Source | Path | Use for | |--------|------|---------| | User settings | `~/.openspace/settings.json` or `$OPENSPACE_CONFIG_HOME/settings.json` | Personal defaults | | Project settings | `/.openspace/settings.json` | Team/project defaults that may be committed | | Local settings | `/.openspace/settings.local.json` | Machine-local overrides, gitignored | | Environment | `OPENSPACE_*` | CI, temporary overrides, deployment | | Runtime | CLI/TUI updates | Current session state | Settings are grouped by stability: | Group | Keys | |-------|------| | Stable engine | `model`, `alwaysThinkingEnabled`, `autoCompactEnabled`, `autoMemoryEnabled`, `autoDream.*`, `memory.*`, `permissions.*`, `todoFeatureEnabled`, `fileCheckpointingEnabled`, `language` | | Stable UI | `theme`, `editorMode`, `verbose`, `preferredNotifChannel`, `showTurnDuration`, `terminalProgressBarEnabled` | | Experimental | `teammateMode`, `outputStyle`, `attachments.todoReminderEnabled` | Example: ```json { "model": "openrouter/qwen/qwen3.6-plus", "alwaysThinkingEnabled": true, "autoCompactEnabled": true, "permissions": { "defaultMode": "default", "allow": ["Bash(git status:*)"] }, "autoDream": { "enabled": true, "minHours": 12, "minSessions": 3 }, "memory": { "mode": "daily_log" }, "theme": "dark", "attachments": { "todoReminderEnabled": true } } ``` Notes: - Use `autoDream.enabled`; the old `autoDreamEnabled` alias is not part of the runtime settings schema. - Only `attachments.todoReminderEnabled` is currently public. Future attachment gates will be added only when the runtime feature is actually wired. - OpenSpace does not currently expose `flagSettings` or `policySettings`; enterprise policy sources will be modeled only when there is a real backend. - There is no published SchemaStore URL yet, so do not add `$schema: "https://json.schemastore.org/openspace-settings.json"`. You can inspect or update settings with slash commands: ```text /settings /settings model openrouter/qwen/qwen3.6-plus /settings autoDream.enabled true /settings permissions.defaultMode plan ``` ## 4. MCP Servers (`config_mcp.json`) Register external MCP servers that OpenSpace connects to as a **client** (e.g. GitHub, Slack, databases): ```bash cp openspace/config/config_mcp.json.example openspace/config/config_mcp.json ``` ```json { "mcpServers": { "github": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-github"], "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}" } } } } ``` ## 5. Execution Mode The shell backend supports only local execution. This keeps Bash sandbox decisions, foreground/background tasks, `TaskGet`, and `TaskStop` in one process-level runtime. The GUI backend still supports local and server modes. | Backend | Supported Modes | Notes | |---|---|---| | `shell` | `"local"` only | `asyncio.subprocess` in-process with runtime task lifecycle | | `gui` | `"local"` or `"server"` | Server mode uses the private `local_server` transport | > [!TIP] > Do not set `shell.mode` to `"server"`. The HTTP local server does not expose the shell spawn/status/tail/kill contract required by the runtime. ## 6. Config Files (`openspace/config/`) Layered system — later files override earlier ones: | File | Purpose | |------|---------| | `config_grounding.json` | Backend settings, smart tool retrieval, tool quality, skill discovery | | `config_agents.json` | Agent definitions, backend scope, max iterations | | `config_mcp.json` | MCP servers OpenSpace connects to as a client | | `config_security.json` | Security policies, blocked commands, sandboxing | | `config_dev.json` | Dev overrides — copy from `config_dev.json.example` (highest priority) | | `config_communication.json` | Communication gateway settings for WhatsApp and Feishu. Use `agent` for per-message OpenSpace execution and `sessions` for queue/history limits. LLM model stays in `openspace/.env`. | ### Agent config (`config_agents.json`) ```json { "agents": [{ "name": "GroundingAgent", "backend_scope": ["shell", "mcp", "web"], "max_iterations": 30 }] } ``` | Field | Description | Default | |-------|-------------|---------| | `backend_scope` | Enabled backends | `["gui", "shell", "mcp", "meta", "web"]` | | `max_iterations` | Max execution cycles | `20` | ### Backend & tool config (`config_grounding.json`) | Section | Key Fields | Description | |---------|-----------|-------------| | `shell` | `mode`, `timeout`, `conda_env`, `working_dir` | `"local"` only, command timeout (default: `60`s) | | `web.search` | `search_model`, `search_api_key`, `search_base_url`, `max_searches_per_call`, `fallback_search_provider` | Web search settings; uses provider server-side search when configured, then provider fallback | | `web.fetch` | `summarize_model`, `max_content_length`, `request_timeout`, `user_agent`, `preapproved_domains` | Web fetch settings; fetches URLs locally and applies a secondary model when needed | | `gui` | `mode`, `timeout`, `driver_type`, `screenshot_on_error`, `enable_visual_analysis`, `visual_analysis_mode`, `visual_analysis_timeout`, `visual_analysis_model` | Local/server mode, automation driver, GUI visual analysis fallback policy | | `mcp` | `timeout`, `sandbox`, `eager_sessions` | Request timeout (`30`s), E2B sandbox, lazy/eager server init | | `tool_search` | `search_mode`, `max_tools`, `enable_llm_filter` | `"hybrid"` (semantic + LLM), max tools to return (`40`), embedding cache | | `tool_quality` | `enabled`, `enable_persistence`, `enable_quality_ranking` | Quality tracking for ranking and reporting | | `skills` | `enabled`, `skill_dirs`, `listing_enabled`, `discovery_enabled`, `discovery_max_results`, `post_tool_query_builder_*` | Skill exposure uses lightweight listing/discovery plus explicit `Skill` invocation. | ### Security config (`config_security.json`) | Field | Description | Default | |-------|-------------|---------| | `allow_shell_commands` | Enable shell execution | `true` | | `blocked_commands` | Platform-specific blacklists (common/linux/darwin/windows) | `rm -rf`, `shutdown`, `dd`, etc. | | `sandbox_enabled` | Enable sandboxing for all operations | `false` | | Per-backend overrides | Shell, MCP, GUI, Web each have independent security policies | Inherit global | ## 7. Communication Gateway The tracked communication config is safe-by-default: loopback-only, channels disabled, and deny-by-default access control. Copy the example config, fill in credentials and `allowed_users`, then explicitly enable the channels you want. The gateway model is not configured here; it inherits `OPENSPACE_MODEL` from `openspace/.env`. `config_communication.json` accepts only the canonical top-level `agent` and `sessions` sections for execution and queue/history settings. The old `openspace` and `runtime` root keys are rejected instead of being mapped silently. ```bash cp openspace/config/config_communication.json.example openspace/config/config_communication.json ``` Install the Feishu SDK extra when you need Feishu support: ```bash pip install -e '.[communication]' ``` Start the gateway: ```bash openspace-gateway --config openspace/config/config_communication.json ``` Check health: ```bash openspace-gateway health --config openspace/config/config_communication.json ``` Notes: - The tracked `config_communication.json` now stays local-only and deny-by-default. Keep credentials out of git and populate them from a private working copy or environment variables. - Set `server.host` to `0.0.0.0` only when Feishu needs to reach the webhook from outside the machine, and pair that with a populated allowlist plus webhook verification secrets. - Feishu now supports both `webhook` and `websocket` modes. `websocket` matches nanobot's long-connection setup and does not require a public webhook URL. - WhatsApp requires Node.js and npm. The bundled bridge installs its dependencies on first start when `auto_install_dependencies` is enabled. - Set `feishu.bot_open_id` if you want strict group mention gating and automatic bot identity discovery is unavailable in your deployment. - Group chats are gated by `group_policy`. `reply_or_mention` is the default and only accepts messages that mention the bot or reply to a prior assistant message. - `allowed_users` is enforced when `allow_all_users` is `false`. The secure default is deny-by-default until you populate the allowlist. - Attachment caching is limited by `sessions.max_attachment_bytes` and `sessions.max_session_attachment_bytes` to bound disk usage per file and per session.