# Reasonix Guide
README
·
简体中文
·
Spec
> Day-to-day configuration and usage. For the engineering contract and internals
> (data types, registries, package layout, roadmap), see the **[Spec](./SPEC.md)**.
## Contents
- [Configuration](#configuration)
- [Billing and display currency](./BILLING.md)
- [CLI reference](./CLI.md)
- [Environment variables](#environment-variables)
- [Web frontend](#web-frontend)
- [Configuration paths](./CONFIG_PATHS.md)
- [Reasoning language](./REASONING_LANGUAGE.md)
- [Task contracts and pause policy](./TASK_CONTRACT.md)
- [Custom OpenAI-compatible providers](#custom-openai-compatible-providers)
- [Desktop hooks](#desktop-hooks)
- [Keyboard shortcuts](#keyboard-shortcuts)
- [Permissions & sandbox](#permissions--sandbox)
- [Capability diagnostics](#capability-diagnostics)
- [Plugins (MCP)](#plugins-mcp)
- [Slash commands](#slash-commands)
- [Embedded documentation retrieval](#embedded-documentation-retrieval)
- [@ references](#-references)
- [Two-model collaboration](#two-model-collaboration)
## Configuration
Resolution order: **flag > `./reasonix.toml` > the user config file >
built-in defaults**. Starting with **Reasonix v1.8.1**, the user config lives at
`~/.reasonix/config.toml` on macOS/Linux and
`%AppData%\reasonix\config.toml` on Windows; see
[Configuration paths](./CONFIG_PATHS.md) for migration and related data paths.
Fields marked user/global only are not overridden by `./reasonix.toml`.
Provider entries name secrets with `api_key_env`, while the secret values live in
Reasonix's global `/.env`, shared by CLI and desktop. Project
`.env`, home `.env`, inherited shell environment variables, legacy credentials,
and the OS keyring are not provider-key runtime fallbacks; legacy credentials are
only migration sources. Project `.env` still feeds workspace-scoped,
non-provider `${VAR}` expansion for MCP/plugin settings without importing
provider keys or Reasonix control variables. See
[Configuration paths](./CONFIG_PATHS.md) for the full `config.toml` and `.env`
structure.
For the desktop and CLI usage of visible reasoning language, see
[Reasoning language](./REASONING_LANGUAGE.md).
```toml
default_model = "deepseek-flash" # executor; set [agent].planner_model to add a planner
# language = "zh" # ui language; empty = auto-detect from $LANG / $REASONIX_LANG
[ui]
# shortcut_layout = "desktop" # classic|desktop; compatibility setting
# cursor_shape = "bar" # block|underline|bar; CLI/TUI text cursor
show_turn_usage = false # hide per-request token/cost receipts in the TUI; default true
[agent]
reasoning_language = "auto" # visible reasoning text: auto|zh|en
# plan_mode_read_only_commands = ["gh issue view"] # legacy compatibility only; Plan bash now uses Permissions
# planner_model = "deepseek-pro" # optional low-frequency planner
# subagent_model = "deepseek-pro" # optional default for runAs=subagent skills
# subagent_models = { review = "deepseek-pro", security_review = "deepseek-pro" }
# max_subagent_depth = 2 # nested delegation depth; set 1 for the old single-layer boundary
# max_subagent_concurrency = 6 # session-wide sub-agent concurrency (task/fleet/skills)
# max_parallel_writers = 3 # concurrent writers with non-overlapping write_paths
# compact_ratio = 0.80 # sole auto trigger; presets 0.70 / 0.80 / 0.85
# max_output_tokens = 0 # auto: official DeepSeek omits the field (server 384K) until the window is tight
# max_output_tokens = 32768 # optional cost cap; still clipped to physical remaining
# max_output_tokens = 65536 # optional cost cap
# max_output_tokens = -1 # force-omit the wire field; compact if the known auto budget no longer fits
# max_output_tokens never changes compact_ratio; 0 is the provider auto value, not "skip local checks"
[[providers]]
name = "deepseek-flash"
kind = "anthropic"
base_url = "https://api.deepseek.com/anthropic"
model = "deepseek-v4-flash"
api_key_env = "DEEPSEEK_API_KEY"
web_search = true
# also preset: deepseek-pro
[tools]
enabled = [] # omit/empty = all built-ins
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
mcp_call_timeout_seconds = 300 # default MCP call safety cap; per-plugin/tool overrides may raise it
[environment]
enabled = true # inject a stable startup summary of OS, shell, and common tools
offline = false # set true when outbound network access is unavailable; prevents futile retries
# [environment.tools]
# go = "/opt/homebrew/bin/go" # optional explicit trusted path; workspace-local paths are not auto-executed
[skills]
# paths = ["~/my-skills", "../shared/skills"] # extra custom skill roots
# excluded_paths = ["~/.agents/skills"] # hide convention roots without deleting folders
# disabled_skills = ["review"] # hide skills until /skill enable
[permissions]
mode = "ask" # writer fallback when no rule matches: ask|allow|deny
deny = ["Bash(rm -rf*)", "Bash(git push*)"] # hard-blocked in every mode
allow = ["Bash(go test:*)"] # never prompted
[sandbox]
# workspace_root = "" # file-writers confined here; empty = current dir
# allow_write = ["/tmp"] # extra dirs write_file/edit_file/multi_edit/move_file may touch
# forbid_read = ["${HOME}/.ssh"] # paths the agent must not read or list
[serve]
auth_mode = "none" # none|token|password; use auth before binding beyond localhost
# token = "" # optional fixed token; empty token mode generates one at startup
# password_hash = "" # bcrypt hash generated with reasonix serve --hash-password --password '...'
# behind_proxy = false # true only behind a trusted reverse proxy
[[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 } # optional raw MCP tool names
```
For the full schema and every field's contract, see [`SPEC.md` §5](./SPEC.md#5-configuration-toml).
Installed and project-configured MCP servers need no per-tool trust
list. The dedicated two-model Planner may use every non-destructive MCP tool,
even when the server omits `readOnlyHint`; strict read-only sub-agents still
require `readOnlyHint: true` and no `destructiveHint`.
`[agent].plan_mode_read_only_commands` is also retained for config round trips,
but the main Plan workflow no longer has a separate bash allowlist or trust
prompt. Bash classification and approval use the same Permissions rules in Plan
and Standard mode; the Sandbox remains the filesystem, process, and network
boundary. Dedicated planner and read-only subagent runners keep their own strict
read-only tool registry and foreground-command classifier.
### Environment variables
Most day-to-day settings belong in `config.toml` or the global Reasonix `.env`
described above. The variables below are process-level advanced switches; set
them before launching Reasonix. Project `.env` files are not a runtime source for
Reasonix control variables.
### CLI telemetry
The CLI can send a once-per-day anonymous active-install ping and bounded,
content-free event counters to `https://crash.reasonix.io`. Configure the
user-global policy with:
```bash
reasonix config telemetry # print the effective mode
reasonix config telemetry auto # default: local interactive TTY only
reasonix config telemetry on # also allow local headless `reasonix run`
reasonix config telemetry off # disable and delete pending counter files
```
On the first eligible release-build interactive session, Reasonix explains the
exact data boundary and asks once before any telemetry request. The prompt is
`[Y/n]`: pressing Enter, `y`, or `yes` stores `auto`; `n` or `no` stores `off`
and deletes pending counters. After the choice is saved, enabled reporting is
silent and the prompt is not shown again. If the preference cannot be saved,
nothing is uploaded.
Reporting is always disabled in CI, development builds, and when
`DO_NOT_TRACK` is set or `REASONIX_TELEMETRY=0`. Under `auto`, redirected/piped
or otherwise non-interactive sessions do not report. When no choice has been
saved yet, these ineligible sessions neither prompt nor report. Network failures
after consent are silent and never change stdout, stderr, or the process exit
code; unsent counters stay in a bounded local queue for a later invocation.
The ping contains a dedicated random 128-bit CLI install ID, CLI version, OS,
architecture, and the `cli` surface marker. Counter batches use that same ID for
daily active-install deduplication and contain only fixed buckets such as CLI
surface, permission/session mode, turn latency, finish reason, cache-hit
range, generic Provider/tool error class, compaction, recovery counters, and
normalized UI language. This ID is separate from the desktop install ID and is
not an account, hardware, repository, or session identifier.
Reasonix never uploads prompts, answers, reasoning, tool names/arguments/output,
paths, repositories/branches, session IDs, exact token or cost values,
Provider/model names, base URLs, or environment variables.
### CLI crash reports
An unhandled Go panic that reaches the CLI entrypoint is saved locally as a sanitized report under
`/cli-crash-reports`. Reasonix keeps at most 10 files with owner-only
permissions. The panic value is never serialized. Absolute source paths become
`/.go:`, function arguments are removed, and the same secret,
token, email, and long-identifier scrubbers run both when saving and immediately
before sending.
Crash reports are never uploaded automatically. Review and manage them with:
```bash
reasonix report # preview newest; prompt before sending on a TTY
reasonix report list # list local reports
reasonix report show [ID] # preview without sending
reasonix report send [ID] # explicit send; delete locally only after success
reasonix report delete [ID] # delete without sending
```
Piped or redirected `reasonix report` calls only preview and never prompt or
send. The CLI telemetry setting does not auto-send or auto-delete
these separately reviewed reports. Runtime fatal throws, operating-system kills,
and panics in unwrapped background goroutines cannot be recovered by Go and do
not produce this local report.
## Web frontend
For local use, `reasonix web` starts the browser UI and opens it in your default
browser. Inside an interactive CLI session, `/web` snapshots the current session,
restores the terminal, and opens an explicit `/sessions/#token=...` deep link.
Even a never-used session keeps its reserved ID without forcing an empty
transcript onto disk, so the first Web turn continues the same session identity.
```bash
cd your-project
reasonix web
```
Use `reasonix web --no-open` when you want to start the foreground Web server
and print its URL without opening a browser tab. The lower-level
`reasonix serve` command starts the same engine without opening a browser by
default. It remains the right entry point for remote development boxes,
supervisors, tunnels, reverse proxies, and shareable authenticated sessions.
`reasonix web` starts at `127.0.0.1:8787`, automatically tries 8788, 8789, and
so on when a port is busy (up to 100 retries), and defaults to a newly generated
token even when `[serve].auth_mode` is `none`. Each live process registers a
single-writer heartbeat file under `/server/instances/`; clean
shutdown removes its own file, while later instances lazily remove records whose
owner process is confirmed dead. Multiple Web instances can therefore share one
Reasonix home without overwriting registry state. The process stays attached to
the terminal; stop it with Ctrl-C.
An explicit `reasonix web --auth none` disables the default token and should be
used only when the listener is intentionally trusted. `reasonix serve` keeps its
backward-compatible, config-driven `auth_mode = "none"` default on
`127.0.0.1:8787`. If you bind Serve outside loopback, expose it through a tunnel,
or put it behind a reverse proxy, enable authentication before sharing the URL:
```bash
reasonix serve --auth token
reasonix serve --addr 0.0.0.0:8787 --auth token
reasonix serve --auth password --password 'temporary-password'
```
Token mode prints a share URL with `#token=...`; the Web page exchanges the
fragment for an HttpOnly cookie before starting API or SSE requests, keeping the
token out of request URLs, browser history, referrers, and access logs. Pass `--token` or set
`[serve].token` to reuse a stable token. Password mode requires either
`--password` at startup or a stored bcrypt hash:
```bash
reasonix serve --hash-password --password 'strong-password'
# /config.toml
[serve]
auth_mode = "password" # none|token|password
password_hash = "$2a$12$..."
behind_proxy = true # only behind a trusted reverse proxy
```
The web UI exposes chat, tool approvals, session history, rewind/fork/summarize,
model and reasoning-effort controls, Goal, a live todo panel fed by the
`todo_write` tool, extension status/card/form/notification surfaces, and
provider balance when configured. Extension-hosted providers appear in the
model picker. Run `/reload` while idle to fail-atomically reload extension
sidecars and the runtime generation without restarting Serve. Use `--model`,
`--max-steps`, or `--resume` for one-off launches; otherwise `serve` uses the
user-global `default_model`.
If the selected Provider has no saved API key, a loopback-bound Serve still
starts and shows a Provider setup page instead of failing before the browser can
connect. After authentication, enter the key there; Reasonix writes it to this
host's global credential file with restricted permissions, rebuilds the active
controller in the same process, and opens the normal UI. The credential-writing
endpoint is disabled for non-loopback listeners. For a remote SSH window,
"this host" means the remote host reached through the SSH tunnel; the key is
not copied from the desktop machine.
## Editor integrations over ACP
`reasonix acp` exposes Reasonix as an ACP v1 stdio agent for editors and other
host clients. The dedicated **[ACP editor integration](./ACP.md)** guide covers
startup, capability negotiation, session lifecycle, independent model/work/
collaboration/approval controls, client filesystem and terminal capabilities,
MCP servers, permission requests, and the Reasonix mid-turn steering extension.
## Remote SSH
The remote module runs Reasonix on a remote host and reaches it over your own
SSH connection — VS Code Remote-SSH style. It bootstraps a persistent headless
`reasonix serve` on the remote host, forwards a local loopback port to it, and
opens the existing serve web client through that tunnel. The agent, its tools,
and its files all live on the remote host at full fidelity; nothing runs through
a lossy file proxy. V1 supports Linux and macOS remote hosts.
Hosts live in a user-global `[remote]` section of `config.toml`. Like
`[secrets]`, a project `reasonix.toml` cannot inject or override remote hosts —
a cloned repo can never steer where Reasonix opens SSH connections. Credentials
follow the provider idiom: the host names an env var (`passphrase_env`,
`password_env`) whose value lives in Reasonix's global `.env`; key material
itself is never stored — `identity_file` is a path.
```toml
[remote]
[[remote.hosts]]
name = "gpu-box"
host = "203.0.113.7"
user = "dev"
identity_file = "~/.ssh/id_ed25519"
workspace = "~/projects/app"
serve_install = "auto" # Remote CLI: auto | npm | upload | never
[[remote.hosts.forwards]]
type = "local" # local (-L) | remote (-R)
bind = "127.0.0.1:5432"
target = "127.0.0.1:5432"
```
CLI:
```bash
reasonix remote add gpu-box dev@203.0.113.7 --workspace '~/projects/app'
reasonix remote import --all # import aliases; ssh -G resolves Include/Match rules when connecting
reasonix remote test gpu-box # dial + auth + host-key confirmation
reasonix remote connect gpu-box --open # bootstrap serve, tunnel, open the URL
reasonix remote serve status gpu-box
reasonix remote fs ls gpu-box:'~/projects/app'
```
Hosts with `use_ssh_config` enabled resolve the final effective configuration
through the local OpenSSH `ssh -G`, including `Include`, wildcard `Host`,
`Match` (including `Match exec`), repeated `IdentityFile`, `ProxyJump`, and
`IdentitiesOnly`. Import stores the original alias instead of a stale snapshot.
`connect` is a foreground supervisor (like `ssh -N` plus the serve bootstrap):
it keeps the tunnel and configured forwards alive, auto-reconnects with
exponential backoff if the link drops, and re-attaches forwards on reconnect.
Ctrl-C disconnects the local side only — the remote serve keeps running, so the
next `connect` reuses it. There is no background daemon in V1.
Host keys are verified against your OpenSSH `~/.ssh/known_hosts` (read-only)
plus a Reasonix-managed `~/.reasonix/remote/known_hosts`. A first-seen key
prompts for trust-on-first-use and is recorded in the managed file; a key that
contradicts a recorded one is a hard error that names the offending line and is
never auto-accepted.
Remote-side state lives under the remote host's `~/.reasonix/remote/`:
`serve-.json` (pid, bound loopback address, workspace),
`serve-.token` (0600; the auth token, passed to serve via `--token-file`
so it never appears in `ps`), and `serve-.log`.
In the desktop app, manage hosts under **Settings -> Remote SSH**, then use the
status-bar chip or the host row's **Remote explorer** button to browse and edit
files over SFTP, manage port forwards, and start/open the remote workspace.
Opening a workspace creates a separate native Reasonix window, similar to a
VS Code Remote SSH window. The primary window owns the SSH tunnel; the remote
window is an isolated, lightweight shell and does not restore or acquire local
conversation sessions. The remote web page uses the provider configuration and
API keys on the **remote** host — the desktop never exposes its own providers
to a remote host. If that host is missing the selected Provider's API key, the
window shows the authenticated setup page first, saves the key only in the
remote Reasonix credential file, and activates the Provider without restarting
the remote Serve process. A transient SSH outage keeps the remote window open;
the desktop reconnects in the background, re-attaches its loopback forward, and
reloads the window against the recovered Serve. An authentication or host-key
failure is terminal and closes the unusable remote window instead.
## Custom OpenAI-compatible providers
In the desktop app, open **Settings -> Model -> Access -> Add model service ->
Custom provider** for proxies, aggregators, or self-hosted services that speak
the OpenAI-compatible chat API or Anthropic-compatible Messages API.
For common providers, choose **Add model service -> Recommended preset** instead.
New official DeepSeek entries use the Anthropic-compatible Messages endpoint by
default and enable provider-side `web_search`; the same `DEEPSEEK_API_KEY` works
for both protocols. On startup, Reasonix upgrades unmodified legacy
`deepseek-flash` / `deepseek-pro` entries that still use the official endpoint
and standard key/model settings. Customized official Chat Completions entries
stay unchanged and show an **Upgrade protocol** action in Settings. Proxy
endpoints, custom headers, model lists, and capability overrides are never
migrated automatically. Existing
separately named `deepseek-anthropic` entries remain compatible, but that
redundant preset is no longer offered for new access. Reasonix can prefill editable custom-provider entries for Kimi CN,
Kimi Global,
Kimi Coding Plan, MiMo API, MiMo Anthropic, MiMo Token Plan CN/SGP/AMS and their
Anthropic-compatible variants, MiniMax CN/Global API, MiniMax CN/Global
Anthropic, GLM CN, Z.AI Global, GLM/Z.AI Coding Plan OpenAI-compatible and
Anthropic-compatible endpoints, OpenCode Go, OpenCode Go Anthropic, OpenCode Go
DeepSeek Anthropic, OpenCode Go DeepSeek Responses, OpenCode Zen
Anthropic, Qwen/DashScope CN/Global, Qwen Coding Plan CN/Global
OpenAI-compatible and Anthropic-compatible endpoints, StepFun OpenAI-compatible
and Anthropic-compatible endpoints, NovitaAI, GMI Cloud, Vercel AI Gateway,
HuggingFace Router, NVIDIA NIM, KiloCode, and Ollama Cloud. Plan names describe
the access/payment route; they include CN/Global only when the provider exposes
distinct regional endpoints. Kimi Coding Plan is therefore a dedicated plan
endpoint, while Kimi direct API is split into CN and Global. The preset path
usually needs only the provider API key: the key value is stored in Reasonix home
`.env`, while `config.toml` stores the endpoint, model list, key
environment-variable name, context window, vision model metadata, proxy bypass
for China-only endpoints, MiniMax `reasoning_split`, GLM/MiniMax thinking
heuristics, Anthropic-compatible Bearer auth where needed, Ollama Cloud
max-effort support, and OpenCode Go per-model reasoning overrides. The dedicated
OpenCode Go DeepSeek Anthropic and DeepSeek Responses presets expose the verified
Flash routes and enable provider-side `web_search` by default; the Responses
variant uses stateless context replay. The existing mixed OpenCode Go Anthropic
preset remains scoped to Qwen and MiniMax so server tools are not sent to
unverified models. DeepSeek Pro remains on the Chat Completions preset because
live Anthropic and Responses requests currently fail in the OpenCode Go upstream
conversion. The OpenCode Go preset includes its native `kimi-k3` subscription
route with image input,
`high`/`max` reasoning effort, and a 1,048,576-token context window. Existing untouched
OpenCode Go preset installs are upgraded automatically; edited model catalogs
are preserved. The Kimi CN and Kimi Global direct-API presets also include
`kimi-k3` with image input, a 1,048,576-token context window, and the official
`low`/`high`/`max` effort scale (default `max`). For the official K3 endpoints,
Reasonix preserves complete assistant messages across turns, sends output limits
as `max_completion_tokens`, and omits K3's fixed sampling parameters. Untouched
legacy Kimi direct-API catalogs are upgraded automatically without changing the
default model; custom catalogs and endpoints are preserved. After adding a
preset, open its provider card if you need to change models, headers, endpoint,
or compatibility settings.
Fill **API address** with the provider endpoint that should receive the standard
chat path. In this mode Reasonix previews and sends chat requests to:
```text
/chat/completions
```
Enable **Full URL** when the service gives you a complete request URL, for
example `https://gateway.example.com/v1/chat/completions`. Reasonix then sends
chat requests directly to that URL and does not append `/chat/completions`. The
preview under the field shows the exact request URL that will be used.
Model discovery uses the API address to try likely model-list URLs such as
`/models` and `/v1/models`. If the gateway requires a separate model-list
endpoint, open **Compatibility settings** and set `models_url`, for example
`https://gateway.example.com/v1/models`. If discovery is not available, fill the
model list manually.
**Full URL** still uses the OpenAI-compatible chat request body. It does not
switch the request schema to the OpenAI Responses API.
### Compatibility settings
The **Compatibility settings (usually leave unchanged)** section is for gateways
whose authentication, model-list endpoint, or reasoning/thinking request shape
differs from the normal OpenAI-compatible defaults. Leave these fields at their
defaults unless the provider documentation or a proxy error tells you otherwise.
For Anthropic-compatible services, such as some coding-plan endpoints, choose
**Anthropic-compatible** as the connection protocol before saving.
| Field | What it controls | When to change it |
| --- | --- | --- |
| `api_key_env` | The environment-variable name used for this provider's API key. Desktop-saved key values are stored in Reasonix home `.env` under this name; the TOML config stores only the name. | Change it when several providers need distinct keys, or leave it blank for a service that does not require an API key. |
| `models_url` | The URL used only for model discovery. Chat requests still use the API address or Full URL above. | Set it when `/models` or `/v1/models` is not where the gateway exposes its model list. |
| Extra request headers | Static HTTP headers, one `Header: value` per line. | Use for gateways such as OpenRouter that require `HTTP-Referer`, `X-Title`, or similar site headers. Keep bearer/API keys in the key field instead of duplicating them here. |
| Extra request body | A JSON object merged into the top-level chat request body. | Use only for provider-specific flags such as `{"enable_thinking": true}`. Reasonix still owns core fields such as `model`, `messages`, `tools`, `stream`, and `thinking`, and null values are rejected. |
| Authorization: Bearer | For Anthropic-compatible providers, sends the saved API key as `Authorization: Bearer ` instead of `x-api-key`. | Enable it only when the gateway documents Bearer auth, such as MiniMax Global or Vercel AI Gateway. |
| Model capability mode | Which reasoning request protocol Reasonix should use for this provider. | Keep **Auto-detect** unless the gateway is misdetected or the model docs require a specific reasoning format. |
| Thinking override | Provider-specific override for `thinking.type`. | Keep **Auto** unless the backend documents `enabled`, `disabled`, or `adaptive`. Unsupported values can make some OpenAI-compatible gateways reject the request. |
| Balance URL | Optional endpoint for wallet/balance lookup. | Set it when the provider exposes a balance endpoint and you want the desktop status bar to show it. |
| Context window | The provider-wide token budget Reasonix uses for automatic context cleanup. `0` disables automatic compaction. | Set it to the provider's model context limit; use a per-model override below when selected models differ. |
Each selected model also has an optional **Context window** input. Leave it blank
to inherit the provider-wide value, or enter a positive token count to override
that value for this model. This avoids premature compaction for long-context
models and provider errors for shorter-context models sharing the same endpoint.
Use the context-window limit from the model documentation, not the maximum output
tokens. For example, 128K commonly means `128000`; if the provider documents
`131072`, use that exact value. Values below 16384 show a non-blocking warning
because they can trigger frequent compaction and reduce cache hit rates.
Model capability mode options:
| Option | Effect |
| --- | --- |
| Auto-detect (recommended) | Reasonix chooses the request shape from model capability metadata and endpoint detection. |
| DeepSeek thinking | Uses DeepSeek-style thinking control, including `thinking.type` and DeepSeek-supported reasoning depth. |
| OpenAI reasoning | Uses the standard OpenAI-compatible `reasoning_effort` levels. |
| Plain chat | Sends no reasoning or thinking control fields. Use this for text-only proxies that reject reasoning parameters. |
Thinking override options:
| Option | Effect |
| --- | --- |
| Auto (provider default) | Does not write an explicit provider-level `thinking` override. Reasonix uses the provider/model default behavior. |
| Enabled | Sends `thinking.type = "enabled"` for compatible providers. |
| Disabled | Sends `thinking.type = "disabled"` for compatible providers. On DeepSeek-style providers this also avoids sending a reasoning depth hint. |
| Adaptive (self-adjusting) | Sends or preserves `thinking.type = "adaptive"` only for providers that document adaptive thinking, such as MiniMax-M3-style endpoints. |
Some OpenAI-compatible gateways require non-standard top-level request body
fields. Add them with `extra_body` on the provider entry:
```toml
[[providers]]
name = "spark"
kind = "openai"
base_url = "https://maas-coding-api.cn-huabei-1.xf-yun.com/v2"
models = ["xopglm52"]
api_key_env = "SPARK_API_KEY"
extra_body = { enable_thinking = true }
```
`extra_body` is merged into the chat JSON request body. Reasonix keeps core
fields such as `model`, `messages`, `tools`, `stream`, and `thinking` under its
own control.
## Desktop hooks
Desktop hooks run local commands at lifecycle events such as `SessionStart`,
`UserPromptSubmit`, `PreToolUse`, and `PreCompact`. A successful `SessionStart`
hook may write plain text to stdout, or return JSON with
`hookSpecificOutput.additionalContext`; Reasonix injects that text once into the
next real user turn as `...`.
This is intended for plugin or workflow bootstrap context, including
Superpowers-style startup instructions, without baking that workflow into
Reasonix's system prompt.
Plugin packages can provide this startup context through
`hooks/session-start-codex` or a plugin-root `CLAUDE.md`. Claude-style
`.claude/settings.json` command hooks are also mapped to matching Reasonix hook
events.
The injected hook context is dynamic current-turn context. It does not change
the stable system prompt, memory prefix, or tool schema, though dynamic content
can still reduce cache reuse for that turn. The detailed desktop hook schema and
loading model are documented in [the Chinese desktop hooks guide](./DESKTOP_HOOKS.zh-CN.md).
## Keyboard shortcuts
Shortcuts are documented by client because users usually look for the keys that
work in the surface they are using. Desktop keeps its Plan toggle, while the CLI
cycles Ask, Auto, and Plan with `Shift+Tab`. Desktop uses `Cmd+Y` on macOS or
`Ctrl+Y` elsewhere for YOLO by default. If YOLO is rebound on Windows/Linux,
`Ctrl+Y` becomes the standard composer redo fallback. Desktop paste stays on the
platform paste key; in the CLI, terminal-native text paste and
application-owned image paste use separate shortcuts.
`[ui].shortcut_layout` is still accepted for old configs, but the shortcut
behavior below is unified across layouts.
For CLI/TUI text input, `[ui].cursor_shape` accepts `underline`, `block`, or
`bar`. The default is `bar`: it remains easy to locate without covering
double-width CJK characters in mixed-language input. Set it to `block` for a
traditional terminal cursor or `underline` for a lower-profile cursor. This
setting does not change desktop or web text fields.
### Desktop GUI
Desktop shortcuts are managed from **Settings → Shortcuts**. Pick a configurable
row, press a new key combination, and Reasonix saves it for the desktop app.
Standard editing shortcuts such as Undo and Redo are shown as locked rows because
the WebView's native text history uses those platform chords. Conflicting
bindings are rejected so one shortcut never triggers two actions. Press `?` or
use the help button in the topic bar to open the shortcuts sheet; it is generated
from the same shortcut registry, so it reflects any custom bindings.
Global shortcuts:
| Key or control | What it does | Notes |
| --- | --- | --- |
| `Cmd+K` on macOS, `Ctrl+K` on Windows/Linux | Toggles the command palette | The palette focuses search when it opens; `Esc` closes it. |
| `Cmd+,` on macOS, `Ctrl+,` on Windows/Linux | Opens Settings | Use **Shortcuts** in Settings to customize desktop bindings. |
| `Cmd+W` on macOS, `Ctrl+W` on Windows/Linux | Closes the active top tab | The last tab is kept by the normal close-tab guard. |
| `Cmd+B` / `Ctrl+B` | Shows or hides the left sidebar | Same action as clicking the sidebar toggle. |
| `Cmd+Shift+B` / `Ctrl+Shift+B` | Expands or collapses the most recent shell output | Same action as clicking the collapsed shell-output hint. |
| `Cmd+1`-`Cmd+9` on macOS, `Ctrl+1`-`Ctrl+9` elsewhere | Jumps to the matching visible chat in the sidebar | Hold `Cmd`/`Ctrl` briefly to reveal the numbered badges. Existing custom shortcuts that already use the same key take precedence. |
| `Cmd++`, `Cmd+-`, `Cmd+0` on macOS; `Ctrl++`, `Ctrl+-`, `Ctrl+0` elsewhere | Increases, decreases, or resets text size | `=` is accepted for the plus key on keyboards that report it that way. |
| `?` | Opens the keyboard shortcuts sheet | The sheet shows the current effective desktop bindings. |
Composer shortcuts:
| Key or control | What it does | Notes |
| --- | --- | --- |
| `Enter` | Sends the current message | IME composition confirmation is left alone. |
| `Shift+Enter` | Inserts a newline | The composer keeps focus. |
| `Shift+Tab` | Toggles Plan on/off | Plan changes the workflow instruction; built-in writers keep the active Ask/Auto/YOLO and Sandbox boundary, while MCP writer/destructive targets stay hard-blocked for the whole planning phase. |
| `Cmd+Z` on macOS, `Ctrl+Z` on Windows/Linux | Undoes the latest composer edit | Native typing stays in the WebView history; Reasonix-managed paste, cut, folded blocks, and structured tokens are restored as complete transactions. |
| `Cmd+Shift+Z` on macOS, `Ctrl+Shift+Z` on Windows/Linux | Redoes the latest composer edit | On Windows/Linux, `Ctrl+Y` is also accepted after the YOLO shortcut has been rebound. |
| `Cmd+Y` / `Ctrl+Y` (default) | Toggles YOLO on/off | Turning YOLO off restores the previous Ask/Auto base when known. The current binding is shown in **Settings → Shortcuts**. |
| `Cmd+V` on macOS, `Ctrl+V` on Windows/Linux | Pastes clipboard content | Clipboard images are attached; images can also be dropped into the composer. |
| Plain `Up` / `Down` at the prompt boundary | Recalls older or newer submitted prompts | Modified arrows and native text navigation stay with the textarea. |
| `Esc` while a turn is running | Cancels the running turn | If the turn has not produced a response yet, the draft is restored. |
Menus and controls:
| Key or control | What it does | Notes |
| --- | --- | --- |
| `Up` / `Down` in slash, `@`, or past-chat menus | Moves the highlighted item | Past-chat search uses the same navigation keys. |
| `Enter` / `Tab` in those menus | Accepts the highlighted item | Directory-like entries can keep the menu open for the next level. |
| `Esc` in those menus | Closes the current menu or returns from past-chat search | Regular typing continues after the menu closes. |
| Ask / Auto / YOLO approval controls | Picks the tool approval posture directly | Clicking these controls is unchanged by keyboard shortcuts. |
| Tool approval card | `Left` / `Right`, `Enter`, `1`-`4`, `Esc` | Move the highlighted action, confirm it, pick a numbered action, or deny. The default highlighted action is Allow once. |
| Plan approval card | `Left` / `Right`, `Enter`, `1`-`3`, `Esc` | Move between Revise plan, Start execution, and Exit plan. The default highlighted action is Start execution. |
| Plan control | Toggles Plan on/off | Same mode as `Shift+Tab`. |
| Goal item in the collaboration menu | Starts, views, or clears Goal | Goal is not in any keyboard cycle. |
### CLI / TUI
The composer uses theme-coloured top and bottom borders and a slim bar cursor by
default. Long drafts grow to the available maximum height; once they overflow,
wheel events inside the composer scroll the draft without moving the insertion
cursor, while wheel events in the transcript keep scrolling the conversation.
Use `/theme auto|light|dark` to select the background mode, or `/theme