codex's config.toml held nine live API keys inline under
[mcp_servers.*.env] -- deepseek, gemini, kimi, mimo, qwen, glm, cursor,
an OpenAI key and a Home Assistant token -- so it could not be tracked
as it stood. TOML env tables take literal values only, with no ${VAR}
indirection or env_file, so the keys cannot simply be named there.
Move them to ~/.codex/secrets.env (0600, ignored) and route the four
affected servers through mcp-with-secrets.sh, which sources that file
and execs the real command. Doing it in the wrapper rather than relying
on exported shell vars means it does not depend on how codex handles
environment inheritance, and works on ssh-only boxes with no keychain or
1Password agent, which is why this was preferred over a chezmoi
template.
Adds configs for claude, codex, pi, grok, kimi, kimi-code and reasonix,
and extends .chezmoiignore so credentials, session logs, local state and
.bak files stay out even if a directory is ever added whole.
Held back for still containing live keys: opencode.json (bailian), and
reasonix config.json and .env.
242 lines
11 KiB
TOML
242 lines
11 KiB
TOML
# Reasonix configuration.
|
|
# Resolution order: flag > ./reasonix.toml > ~/.reasonix/config.toml > built-in defaults.
|
|
# Fields marked user/global only are not overridden by ./reasonix.toml.
|
|
# Secrets are named via api_key_env and stored in Reasonix's global .env; never put keys here.
|
|
|
|
config_version = 5 # schema marker for diagnostics; old versions may ignore it
|
|
default_model = "deepseek-flash/deepseek-v4-flash"
|
|
language = "EN" # ui/model language; empty = auto-detect from $LANG / $REASONIX_LANG
|
|
credentials_store = "auto" # legacy compatibility; provider keys are saved in Reasonix's global .env
|
|
|
|
[ui]
|
|
theme = "auto" # auto|dark|light; CLI colors only; REASONIX_THEME can override per run
|
|
# theme_style = "graphite" # graphite|aurora|slate|carbon|nocturne|amber and legacy aliases
|
|
# shortcut_layout = "desktop" # classic|desktop; compatibility setting; Shift+Tab toggles Plan, Ctrl+Y toggles YOLO
|
|
# cursor_shape = "bar" # block|underline|bar; text input cursor shape
|
|
# show_reasoning = true # CLI: show thinking text by default; false = collapsed (toggle with Ctrl+O)
|
|
|
|
[desktop]
|
|
language = "en" # desktop UI language; empty/auto = browser/OS auto-detect
|
|
# currency = "USD" # official pricing currency: CNY|USD; empty/auto follows language
|
|
layout_style = "workbench" # desktop layout: classic|workbench|creation
|
|
theme = "auto" # desktop only: auto|dark|light
|
|
terminal_theme = "auto" # integrated terminal: auto|dark|light; auto follows the desktop app
|
|
# theme_style = "graphite" # graphite|aurora|slate|carbon|nocturne|amber and legacy aliases
|
|
# external_opener = "vscode" # desktop Open control: installed application id
|
|
close_behavior = "background" # desktop: quit|background when the window close button is clicked
|
|
status_bar_style = "text" # desktop: icon|text metric labels in the bottom status bar
|
|
status_bar_items = ["model", "workspace", "git_branch", "cache", "cache_avg", "session_tokens", "turn_tokens", "turn_cost", "session_turns", "context", "compact", "cost", "balance"] # desktop: ordered visible bottom status bar items
|
|
default_tool_approval_mode = "auto" # desktop: Ask/Auto/YOLO default for newly-created sessions
|
|
check_updates = true # desktop: check for new versions on startup
|
|
telemetry = true # desktop: anonymous launch ping + scrubbed next-launch native crash diagnostics; never content
|
|
metrics = true # desktop: aggregate quality/lifecycle metrics (anonymous signal/bucket counts); never content
|
|
expand_thinking = false # desktop: show reasoning text expanded by default; false = collapsed
|
|
display_mode = "standard" # desktop: standard|compact transcript display mode
|
|
|
|
[telemetry]
|
|
cli_metrics = "auto" # CLI content-free usage metrics: auto|on|off; auto requires a local interactive terminal
|
|
|
|
[notifications]
|
|
enabled = false # system notifications for CLI and desktop turns; default off
|
|
turn_done = true # notify when a turn finishes
|
|
approval_request = true # notify when a tool approval is waiting
|
|
ask_request = true # notify when a question is waiting
|
|
|
|
[network]
|
|
proxy_mode = "auto" # auto|env|custom|off; auto currently uses env proxy
|
|
# proxy_url = "socks5://127.0.0.1:7890" # optional custom override
|
|
# no_proxy = "localhost,127.0.0.1,.local" # honored for proxy_mode = "custom"
|
|
|
|
[network.proxy]
|
|
type = "socks5" # http|https|socks5|socks5h
|
|
# server = "127.0.0.1"
|
|
# port = 7890
|
|
# username = ""
|
|
# password = "${REASONIX_PROXY_PASSWORD}" # optional; supports ${VAR} expansion
|
|
|
|
[environment]
|
|
enabled = true # inject a stable startup environment summary into the model prompt
|
|
# [environment.tools]
|
|
# go = "/opt/homebrew/bin/go" # trusted executable path; workspace-local paths are not auto-executed
|
|
|
|
[agent]
|
|
# system_prompt = """...""" # omit to use the built-in prompt for this version
|
|
# system_prompt_file = "prompts/system.md" # project paths stay in <workspace>; user paths may fall back to <reasonix home>
|
|
temperature = 0.0
|
|
# recovery_model = "deepseek-pro" # optional; falls back to guardian then main model
|
|
# reasoning_language = "zh" # visible reasoning language: auto|zh|en
|
|
soft_compact_ratio = 0.5 # notice only; keeps cache-first prefix intact
|
|
tool_result_snip_ratio = 0.6 # snip stale tool results at this fraction before summary compaction
|
|
compact_ratio = 0.8 # try compacting when prompt reaches this fraction
|
|
compact_force_ratio = 0.9 # force compacting at this high-water mark
|
|
# keep = ["errors"] # compaction keep policy: errors, user_marked
|
|
# recent_keep = 2 # minimum recent messages kept verbatim
|
|
cold_resume_prune = true # elide stale tool results when reopening a session past the provider cache window
|
|
# plan_mode_read_only_commands = ["gh issue view"] # legacy compatibility only; Plan bash uses Permissions
|
|
# planner_model = "deepseek-pro" # optional: enable two-model collaboration
|
|
# subagent_model = "deepseek-pro" # optional default for runAs=subagent skills
|
|
# subagent_models = { review = "deepseek-pro", security_review = "deepseek-pro" } # per-skill overrides
|
|
# subagent_effort = "high" # optional default effort for subagents
|
|
# subagent_efforts = { review = "max", task = "high" } # per-tool/skill effort overrides
|
|
# max_subagent_depth = 2 # nested subagent delegation depth; set 1 to disable nested delegation
|
|
# max_subagent_concurrency = 6 # session-wide sub-agent concurrency (task/fleet/skills)
|
|
# max_parallel_writers = 3 # concurrent writers with non-overlapping write_paths
|
|
# output_style = "explanatory" # explanatory | learning | concise | custom; empty = default
|
|
|
|
[[providers]]
|
|
name = "deepseek-flash"
|
|
kind = "openai"
|
|
base_url = "https://api.deepseek.com"
|
|
model = "deepseek-v4-flash"
|
|
api_key_env = "DEEPSEEK_API_KEY"
|
|
balance_url = "https://api.deepseek.com/user/balance" # optional; wallet-balance endpoint shown in the status bar
|
|
context_window = 1000000 # tokens; compaction triggers near this limit
|
|
price = { cache_hit = 0.0028, input = 0.14, output = 0.28, currency = "$" } # provider-wide fallback, per 1M tokens
|
|
|
|
[[providers]]
|
|
name = "deepseek-pro"
|
|
kind = "openai"
|
|
base_url = "https://api.deepseek.com"
|
|
model = "deepseek-v4-pro"
|
|
api_key_env = "DEEPSEEK_API_KEY"
|
|
balance_url = "https://api.deepseek.com/user/balance" # optional; wallet-balance endpoint shown in the status bar
|
|
context_window = 1000000 # tokens; compaction triggers near this limit
|
|
price = { cache_hit = 0.003625, input = 0.435, output = 0.87, currency = "$" } # provider-wide fallback, per 1M tokens
|
|
|
|
[tools]
|
|
enabled = [] # empty = all built-in tools
|
|
bash_timeout_seconds = 120 # foreground safety cap; set 0 for no tool-local cap
|
|
mcp_startup_timeout_seconds = 30 # background initialize + tools/list safety cap; per-plugin overrides may raise it
|
|
mcp_call_timeout_seconds = 300 # default MCP call safety cap; per-plugin/tool overrides may raise it
|
|
|
|
[tools.background_jobs]
|
|
stalled_warning_seconds = 900 # warn once per background job after this many quiet seconds; 0 disables
|
|
|
|
[tools.shell]
|
|
# prefer = "auto" # auto|bash|powershell|pwsh; empty/default = auto-detect
|
|
# path = "/opt/homebrew/bin/bash" # absolute path to the shell executable; empty = PATH lookup
|
|
|
|
[lsp]
|
|
enabled = true # language server tools; servers launch lazily when used
|
|
# [lsp.servers.go]
|
|
# command = "gopls"
|
|
# args = []
|
|
# extensions = [".go"]
|
|
|
|
[skills]
|
|
# paths = ["~/my-skills", "../shared/skills"] # extra custom skill roots
|
|
# excluded_paths = ["~/.agents/skills"] # hide convention roots without deleting folders
|
|
# max_depth = 3 # nested scan depth; set 1 for legacy root-only discovery
|
|
# disabled_skills = ["review"] # hide noisy or unwanted skills
|
|
|
|
[permissions]
|
|
# Per-call gating. mode = writer fallback when no rule matches: ask|allow|deny.
|
|
# Readers always default to allow. Precedence: deny > ask > allow > fallback.
|
|
# Rules are "Tool" or "Tool(specifier)"; e.g. Bash(go test:*), Edit(src/**).
|
|
mode = "ask"
|
|
# allow_dynamic_bash = false # advanced opt-in; deny/ask and exact rules still take precedence
|
|
# deny = ["Bash(rm -rf*)", "Bash(git push*)"] # hard-blocked in every mode
|
|
# allow = ["Bash(go test:*)", "Bash(git status:*)"] # never prompted
|
|
# ask = ["Edit(src/**)"] # force a prompt even if otherwise allowed
|
|
|
|
[sandbox]
|
|
# Confine tool blast radius. File-writers (write_file/edit_file/multi_edit/move_file)
|
|
# may only write under workspace_root (empty = current dir) and allow_write extras.
|
|
# bash = "enforce" jails each command in an OS sandbox when available;
|
|
# without one, bash execution is refused. Empty defaults to enforce on macOS/Linux.
|
|
# Windows has no OS-level Bash sandbox and fixes bash = "off".
|
|
# network allows sandboxed bash egress.
|
|
# workspace_root = "" # default: current working directory
|
|
# allow_write = ["/tmp"] # extra dirs writers may also modify
|
|
# forbid_read = [] # dirs the agent cannot read or list
|
|
bash = "enforce"
|
|
network = true
|
|
|
|
[statusline]
|
|
# A custom status line: a command whose first stdout line replaces the built-in
|
|
# data row. It receives {"model","contextUsed","contextWindow","cwd"} as JSON on stdin.
|
|
# command = "my-statusline.sh"
|
|
|
|
# Bot gateway: multi-channel IM bot for QQ, Feishu/Lark, and WeChat.
|
|
[bot]
|
|
enabled = false
|
|
# model = "" # empty = default_model
|
|
tool_approval_mode = "ask" # ask|auto|yolo; yolo skips tool approvals only
|
|
max_steps = 25
|
|
debounce_ms = 1500
|
|
queue_mode = "steer" # steer|followup|collect|interrupt
|
|
queue_cap = 20
|
|
queue_drop = "summarize" # summarize|old|new
|
|
ignore_self_messages = true # ignore bot echo by returned message_id and configured self user ids
|
|
|
|
[bot.self_user_ids]
|
|
qq = []
|
|
feishu = []
|
|
weixin = []
|
|
|
|
[bot.control]
|
|
enabled = false # local loopback HTTP API for status/send; requires Bearer token
|
|
addr = "127.0.0.1:37913"
|
|
token_env = "REASONIX_BOT_CONTROL_TOKEN"
|
|
|
|
[bot.pairing]
|
|
enabled = true
|
|
request_ttl_minutes = 60
|
|
max_pending_per_platform = 3
|
|
|
|
[bot.allowlist]
|
|
enabled = true
|
|
allow_all = false
|
|
qq_users = []
|
|
feishu_users = []
|
|
weixin_users = []
|
|
qq_approvers = []
|
|
feishu_approvers = []
|
|
weixin_approvers = []
|
|
qq_admins = []
|
|
feishu_admins = []
|
|
weixin_admins = []
|
|
qq_groups = []
|
|
feishu_groups = []
|
|
weixin_groups = []
|
|
|
|
[bot.qq]
|
|
enabled = false
|
|
app_id = ""
|
|
app_secret_env = "QQ_BOT_APP_SECRET"
|
|
sandbox = false
|
|
|
|
[bot.feishu]
|
|
enabled = false
|
|
app_id = ""
|
|
domain = "feishu"
|
|
app_secret_env = "FEISHU_BOT_APP_SECRET"
|
|
verification_token = ""
|
|
mode = "webhook"
|
|
webhook_port = 8080
|
|
require_mention = true
|
|
|
|
[bot.weixin]
|
|
enabled = false
|
|
account_id = "default"
|
|
token_env = "WEIXIN_BOT_TOKEN"
|
|
api_base = "https://ilinkai.weixin.qq.com"
|
|
|
|
[secrets] # credential protection; user/global only, ./reasonix.toml cannot override
|
|
# filter_subprocess_env = false # opt-in; stripping tokens breaks gh, HTTPS git push, npm publish
|
|
# protect_sensitive_files = false # opt-in; hiding credential files can break legitimate edit workflows
|
|
|
|
# External MCP servers. type: "stdio" (default, a subprocess) | "http" | "sse".
|
|
# ${VAR} / ${VAR:-default} are expanded from the environment in command/args/env/url/headers.
|
|
# [[plugins]]
|
|
# name = "example"
|
|
# command = "reasonix-plugin-example"
|
|
# startup_timeout_seconds = 60 # optional initialize + tools/list cap
|
|
# call_timeout_seconds = 600 # optional per-server MCP call timeout
|
|
# tool_timeout_seconds = { "generate_video" = 1800 } # raw MCP tool names
|
|
# [[plugins]] # a remote server over Streamable HTTP
|
|
# name = "stripe"
|
|
# type = "http"
|
|
# url = "https://mcp.stripe.com"
|
|
# headers = { Authorization = "Bearer ${STRIPE_KEY}" }
|