CLI and config
Flags, exit codes, config keys, environment variables, modes, and workflows.
Usage
summonr groksummonr anthropicsummonr kimi -p "What is in Cargo.toml?"A single word that is not a command, endpoint, or prompt flag but looks like a mistyped command (summonr sesions) is refused with a suggestion; use -p to send it as a prompt.
summonr starts on the first endpoint and model that applies: the endpoint and --model flags, then SUMMONR_ENDPOINT and SUMMONR_MODEL, then the last endpoint and model you picked or used, then the default (default and default_model in config.toml), then the first endpoint that is set up. The last-used seat lives in ~/.summonr/recent.json and changes when you pick a model and after a turn succeeds. A default or last-used endpoint that no longer exists or has no key prints one note, and summonr falls back to the next rule. Only an endpoint named on the command line is a hard error. alt+d in the /model picker sets the selected row as the default, and alt+d on the default row clears it. The header shows which rule chose the endpoint, for example (default) or (last used), until you switch.
Add your own OpenAI-compatible server from the command line:
summonr login local --url http://127.0.0.1:8080/v1summonr logout local --removesummonr login NAME --url URL adds the endpoint. When the server lists exactly one model, summonr picks it; otherwise pass --model NAME. The same command with an existing name updates that endpoint in place. summonr login NAME --model M changes the model of an endpoint you added without --url; on a built-in endpoint, --model needs --default. summonr login NAME --default sets default and default_model for any endpoint that is set up; it signs in first when the endpoint is not set up, and --model M picks the model it saves. summonr login NAME --help prints the help for login; logout, diff, profile, install, export, doctor, classify, worktrees, and mcp do the same. A built-in name is refused. summonr logout NAME --remove deletes the endpoint and forgets its key; when default named it, default and default_model are cleared. An unknown endpoint name suggests the closest name, or summonr login NAME --url URL.
Or add the host in ~/.summonr/config.toml:
[endpoint.local] base_url = "http://127.0.0.1:8080/v1" model = "whatever-the-server-calls-it" Then summonr local. A local server needs no api_key. When a local built-in such as ollama or lmstudio is not running, the error says so and names the preset's start command (ollama serve, lms server start). With no model set, the hint lists the models the server has. effort = "low" on an endpoint (or --effort LEVEL, /effort in the interface) sets the reasoning effort for that endpoint. /effort and tab are remembered per endpoint. An endpoint with no effort set, and none remembered, uses high when the model catalog says the model reasons, and sends no effort otherwise. Reasoning effort below lists the levels each model accepts. price = { input, output, cached, cache_write } in USD per million tokens (cache_write defaults to input) prices every round in the footer. A workflow role keeps its own endpoint's effort and price; --effort and /effort set the driving endpoint and any role whose endpoint does not set them. summonr endpoints lists the endpoints that are set up, from files on disk and with no network call; with none set up, it lists them all. --all adds the endpoints that are not set up, and --check asks each listed endpoint for its models through GET /models. A server you added that has no cached model list is asked on a plain listing too. The model count comes from the last listing in ~/.summonr/models.json and reads stale after models_listing_secs (a day); a host that serves its model list away from its chat base sets models_url (perplexity does: chat at /chat/completions, models at /v1/models). Each row shows the key state and where the key comes from (key: ANTHROPIC_API_KEY, key: file, key: keychain, signed in, or no key needed); --check adds key rejected, rate limited, offline, or error. summonr login NAME prompts for an API key. On an endpoint that needs no key, it says so and reports the endpoint ready, or names the missing model. summonr login prints one line per endpoint with its state and label, and summonr endpoints one row per endpoint; both size each column to its longest value, and a row with no model shows only its URL; endpoints that are set up come first in each group. A keyless built-in with no model reads needs model. grant = "device_code" runs a device login, and grant = "authorization_code" runs a browser sign-in with PKCE (S256). Ollama gives a model only a 4k context below 24 GiB of VRAM and cuts longer prompts silently, which loses summonr's tools, and its OpenAI API cannot raise it; start it with OLLAMA_CONTEXT_LENGTH=65536 ollama serve, the command summonr names when Ollama is not running.
summonr endpoints --check and the /model picker download the models.dev catalog (https://models.dev/api.json, about 350 KB) to fill in model names, context windows, reasoning and vision support, and prices. They fetch it even when every endpoint is local. The copy is cached in ~/.summonr/models-dev.json and fetched again at most once every models_catalog_secs (an hour), with If-None-Match. -p runs, interface start, and a plain summonr endpoints do not fetch it. The picker shows cached models at once and asks an endpoint again only when its list is missing or stale. Without a cached copy, summonr uses a snapshot built into the binary. SUMMONR_MODELS_URL sends the fetch to another URL, such as a mirror you host, and models_catalog = false in config.toml turns the fetch off.
The browser flow picks its return path from redirect_uri:
- A loopback
redirect_uri, or none at all, opens a local port, catches the provider's redirect, and closes. Omit it and summonr picks a free port; set it when the provider registered a fixed one. Port0keeps the provider's path and lets summonr pick the port. - When the redirect carries a
client_id, summonr stores it with the token and uses it for every refresh and the next sign-in. This is how a provider that registers the app on first sign-in hands out its id. - Any other
redirect_uriswitches to paste-back: summonr asks for the code the browser shows and accepts thecode#stateform. No port opens.
Endpoints carry the rest of what a provider needs, so a new provider is config, not code:
token_style = "json"when the token endpoint takes a JSON body instead of a form.schemesets the carrier for the token:bearer(the default for every login),api_key, orgoogle_key.pkce = trueadds a PKCE challenge to a device login.[…auth.authorize_params]and[…auth.token_params]add provider parameters to the two requests.[…auth.claim_headers]maps a header name to a claim read from the token, so an account id travels on every request.
config.example.toml carries ready endpoints for other subscriptions.
The claude endpoint runs a Claude Pro or Max plan through your own Claude Code. summonr starts claude for each turn and speaks the Agent SDK protocol to it, so the sign-in stays in Claude Code (claude auth login) and summonr never reads the token. Claude Code's own tools are off: the model calls summonr's tools through an in-process MCP server, under summonr's policy and checks. The next turn in the same summonr process resumes the Claude Code session; a new process, a switch from another endpoint, or a failed turn starts a new session that gets the earlier turns as text. A prompt typed after a cancelled tool call starts a fresh run instead of finishing the abandoned one. Claude Code runs with your environment, so CLAUDE_CONFIG_DIR, proxies, and CA settings apply, and summonr's system prompt reaches it through a temporary file (--system-prompt-file) with --system-prompt-snapshot off, so a changed prompt applies on resumed turns too. Claude Code may call only summonr's tools: a permission request for any of its own built-in tools, such as EndConversation, is refused. Turns on one session run one at a time. base_url names the program, so [endpoint.claude] base_url = "/path/to/claude" picks another install, and summonr never starts Claude Code just to list models: summonr endpoints --check looks for the program and says when it is missing, and the /model picker shows the models Claude Code offered in its last session, or the Anthropic models from the catalog before the first one.
An endpoint can offer both a sign-in and a key. summonr login NAME then asks which one; --key skips the question. A stored sign-in wins over any key, and summonr logout NAME returns the endpoint to its key. auth.label names the subscription in that question.
openai offers Sign in with ChatGPT (Plus or Pro) next to OPENAI_API_KEY, and runs on the subscription's usage through the Responses API. The first sign-in registers summonr with OpenAI and stores the issued client id; ~/.summonr/host-id holds the install id that OpenAI asks for on every sign-in. OpenAI caps each app per week in ChatGPT settings → Usage; when the cap is reached, the error names that page after the standard retry policy. The subscription path rejects max_output_tokens, sampling fields, and hosted tools; on a subscription token summonr sends the session id as prompt_cache_key and in a session-id header for cache affinity, and groups its tools in one namespace, as that route requires. A sign-in that does not grant chatgpt.tokens.use.direct is refused, so the endpoint never shows signed in without subscription usage.
grok offers a SuperGrok or X Premium+ sign-in next to XAI_API_KEY, through the device flow at auth.x.ai.
Keys live in ~/.summonr/credentials.toml, a plain TOML file with mode 0600, written through a rename. Only your account can read it. A sealed file from an earlier build is decrypted with its credentials.wrap key and rewritten as plain TOML the first time summonr reads it; after that, credentials.wrap is no longer used. The key prompt disables echo and stores the key; summonr login NAME --key skips the method question on a row that offers both, and storing a key signs that row out of its plan. summonr logout NAME forgets the key and any login token, says what it removed (Signed out of NAME for a sign-in token, Removed the stored key for NAME for a key, or that nothing was stored; on an endpoint that needs no key, it says nothing was stored), and names the key that applies next. A plaintext api_key in config.toml is moved into that file the first time summonr runs, and it says so once. Resolution order is the host's environment variable, the store, api_key in config.toml, then the built-in default. An endpoint with no key fails with the missing-key message; only local and keyless endpoints run without one. --key is refused on a row that only signs in, such as copilot.
If you want the OS store instead, set secrets = "keychain" in config.toml (or SUMMONR_SECRETS=keychain). On macOS that is one Keychain entry holding every secret, read and written through /usr/bin/security, so the one-time "Always Allow" is granted to Apple's signed tool and survives every rebuild of summonr; Windows uses Credential Manager and Linux the Secret Service, one entry per secret. A locked keychain is reported, never worked around with a file, and the two modes never fall back to each other.
Built-ins are providers: anthropic, openai, gemini, grok, deepseek, zai, alibaba, kimi, minimax, tencent-plan, volcengine-plan, copilot, openrouter, together, groq, cerebras, mistral, muse, opencode, fireworks, deepinfra, siliconflow, nvidia, huggingface, cohere, ollama, lmstudio, and ollama-cloud. The whole list is one data table, src/endpoint/presets.toml: each [[preset]] row is a route with its base URL, env keys, wire, and reasoning quirks, and a row summonr cannot honor fails startup by name. A provider with several routes tags each one with provider, region (intl or cn), and its access (a coding plan or an API key):
Prompt caching follows each host's documented session hint: OpenAI, xAI, Mistral, and DeepSeek-style rows send the session id as prompt_cache_key, OpenRouter gets it in x-session-id, Fireworks in x-session-affinity, and xAI in x-grok-conv-id, so a session's requests reach a warm cache. DashScope pay-as-you-go rows mark cache_control breakpoints, Alibaba's explicit cache, which its implicit cache does not guarantee.
GPT-5, GPT-6, and Codex models see an apply_patch tool instead of edit and write, because OpenAI trains them on that patch format; it runs through the same edit engine. Every other model sees edit and write.
| Provider | Routes |
|---|---|
zai | zai-intl (coding plan, international), zai-cn (coding plan, China), zai-api (API key, international), zai-cn-api (API key, China) |
alibaba | qwen-plan, qwen-plan-cn (coding plan), dashscope, dashscope-cn (API key) |
kimi | kimi-cn (Kimi Code, China), kimi-intl (Kimi Code, international) |
minimax | minimax-api, minimax-cn (API key), minimax-plan, minimax-cn-plan (coding plan, Anthropic wire) |
siliconflow | siliconflow-intl (international), siliconflow-cn (China) |
anthropic | anthropic-api (API key), claude (Claude plan through Claude Code) |
opencode | opencode-zen (pay-as-you-go), go (OpenCode Go subscription) |
/login lists each provider once. On a provider with routes, the detail pane shows the region and the choice between the coding plan and the API key as buttons; click one; the choice is saved as [provider.NAME] region = "cn" and access = "plan" in config.toml. With no choice saved, summonr takes the first route whose key is set (in config.toml, the environment, or the store), else the first route. summonr NAME takes a provider or a route name, so summonr zai-cn runs the China plan. No route shares its provider's name, so a provider name always follows the saved choice (with the plan picked, summonr anthropic runs Claude Code) and a route name always runs that route (summonr anthropic-api). An [endpoint.PROVIDER] table overlays whichever route runs, under that route's own table. The last-used endpoint records the provider, so a toggle holds after a restart. /login ROUTE (for example /login claude or /login zai-cn) saves that route as the provider's choice and opens it. summonr login NAME checks and stores a key on the route that NAME runs. A table [endpoint.NAME] with its own base_url is your endpoint and always wins over a provider name. [endpoint.ROUTE] overlays one route. Each route reads only its own region's env keys: ZAI_CODING_API_KEY, ZAI_API_KEY, or ZHIPU_API_KEY for zai, ZAI_CODING_CN_API_KEY, GLM_CODING_API_KEY, or GLM_API_KEY for zai-cn, ZAI_API_KEY for zai-api, GLM_API_KEY for zai-cn-api, MINIMAX_API_KEY and MINIMAX_CN_API_KEY for the two MiniMax regions, and SILICONFLOW_API_KEY and SILICONFLOW_CN_API_KEY for SiliconFlow. Coding-plan routes take the key their vendor's console issues for the plan. Other keys are the host's own (XAI_API_KEY, OPENAI_API_KEY, OPENROUTER_API_KEY, TOGETHER_API_KEY, GROQ_API_KEY, CEREBRAS_API_KEY, MISTRAL_API_KEY, META_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY, OPENCODE_API_KEY, OPENCODE_GO_API_KEY, DEEPSEEK_API_KEY, FIREWORKS_API_KEY, DEEPINFRA_API_KEY, ALIBABA_CODING_PLAN_API_KEY, DASHSCOPE_API_KEY, TENCENT_CODING_PLAN_API_KEY, ARK_CODING_PLAN_API_KEY, NVIDIA_API_KEY, HF_TOKEN, COHERE_API_KEY, OLLAMA_API_KEY). Kimi takes a key (KIMI_CODING_API_KEY or KIMI_API_KEY). summonr login copilot is GitHub device login; chat then exchanges that token for a Copilot session token. together, groq, cerebras, mistral, fireworks, deepinfra, nvidia, huggingface, siliconflow, ollama-cloud, ollama, and lmstudio carry no default model: pass --model. perplexity is off: Sonar on chat completions runs no user-defined tools. No classify endpoint ships: add an [endpoint.NAME] row with wire = "decisions" to use summonr classify. Overlay wire = "anthropic" on any [endpoint.NAME] row. See config.example.toml.
summonr --goal "make cargo test pass"summonr --steps PLAN.md summonr --name TEXT (or /name TEXT) names a session. Every place that shows a session id shows the short id: leading zeros dropped, 12 characters kept. --session takes a name, the short id, or an id prefix; summonr sessions lists both (with a header row on a terminal), and summonr export [ID|NAME] prints the transcript as Markdown. summonr doctor --logs lists the last 20 per-run diagnostic logs. summonr doctor prints the running binary path and reports crashed or incomplete runs. Logs older than 14 days are removed unless their process is still active. Session directories under ~/.summonr/sessions/ with no file change for 30 days are removed once per start, except the session that run opens. Set another period in days, 1 or more, in ~/.summonr/config.toml:
[sessions]retain_days = 90 --goal keeps one objective until .summonr/check.toml is green and a judge says stop. The judge answers done, continue, stalled, or impossible; the last two end the goal with the reason. A goal has no turn cap; it runs until the judge stops it, a budget ends it, or you cancel it. --max-tokens and --max-secs bound every mode. A budget counts from the run that loads the session, so a resumed or forked session starts with its full budget. Every goal turn restates the objective to the model, so a compacted context cannot lose it. --steps hands the model one numbered item at a time. A step that contains Run `CMD` gets CMD as its own check, in addition to .summonr/check.toml. A step with no Run phrase is gated on .summonr/check.toml alone. The last step runs every check. A turn that ends while a background command it started is still running is deferred, with no verdict and no repair strike, until the job exits or the model kills it. The harness remembers that job across turns; a later turn cannot complete while it runs. A ### Heading under ## Steps groups the items that follow it into a phase. Every turn carries the ledger to the model and to the transcript: phases as Roman numerals, [x] done, [/] this step, [ ] later, [!] blocked. Both edit this directory. --worktree isolates in a git worktree (<repo>-worktrees/<id>). Exit 0 then commits the files the run changed as summonr: <objective> (files over 5 MB and anything the run did not touch are left in place and named), fast-forwards your branch, and removes the tree; a tree that cannot fast-forward or still holds uncommitted files is kept and named, and the exit code is 1. --here is the default.
## Steps 1. Add the `--limit` flag. Run `cargo test cli`.2. Document the flag in README.md. Flags
| Flag | Effect |
|---|---|
-e, --endpoint NAME | Use endpoint NAME. A bare endpoint name as the first word does the same. |
-p, --print | Run one prompt and exit. A bare prompt after the options does the same. |
-c, --continue | Resume the last session in this directory. |
--fork | Copy the resumed session (-c, --session) and continue the copy. Not with --goal or --steps. |
--trust | Read workspace SYSTEM.md, AGENTS.md, and CLAUDE.md. On by default. |
--no-trust | Ignore those workspace files. |
--no-verify | Skip the .summonr/check.toml gate. |
--no-splash | Skip the startup banner. |
--inline | Keep the transcript in terminal scrollback, with the composer pinned at the bottom. |
--here | Work in this checkout. This is the default; it cannot be combined with --worktree. |
--model NAME | Use model NAME on the endpoint instead of its default. |
--effort LEVEL | Set the reasoning effort: none, minimal, low, medium, high, xhigh, or max. See Reasoning effort. |
-w, --workflow NAME | Seat each step from [workflows.NAME]. |
--json | Print JSON: one event per line with -p, --goal, and --steps, and JSON output from diff, worktrees, mcp, and classify. |
--session ID | Resume a session by id, short id, prefix, or name. |
--name TEXT | Name this session. |
--goal TEXT | Work toward TEXT across turns until the check passes and the judge says done. |
--steps PLAN.md | Run each item under ## Steps in PLAN.md and gate it on its check. |
--max-tokens N | Session token budget. A breach stops the run. |
--max-secs N | Session wall-clock budget in seconds. A breach stops the run. |
--add-dir DIR | Add an extra writable root. Repeatable. |
--strict | Allow only the commands listed in policy.toml. |
--worktree | Isolate this session in a git worktree. |
--gui | Open the desktop window. Needs a build with --features gui. |
-h, --help | Show the help. |
-V, --version | Show the version. |
The last of a pair (--trust/--no-trust) wins. An option that takes a value rejects a value that starts with -: --name -x is an error, not the name -x.
summonr -p with no prompt reads the prompt from stdin until EOF. So does summonr with no prompt when stdin or stdout is not a terminal:
git diff | summonr kimi -pConfig keys
Top-level keys in ~/.summonr/config.toml:
| Key | Values | Effect |
|---|---|---|
splash | true (default), false | Show the startup banner. |
models_catalog | true (default), false | Fetch the models.dev catalog for summonr endpoints --check and /model; false keeps every request on your own endpoints. |
animations | true (default), false | Animate the interface. |
fps | 1 to 240, default 25 | Interface frame rate. |
diff_layout | split (default), unified | Diff pane layout. |
Keys on an [endpoint.NAME] row:
| Key | Effect |
|---|---|
context_window | Context size in tokens. Without it, summonr asks the provider. |
idle_timeout_secs | Seconds a response stream may stay silent before the request fails. At least 1; default 240. |
headers | A table of extra HTTP headers sent on every request. |
fallback | A list of endpoint names. When a request fails with an error that a retry cannot fix, the session moves to the next name. |
compact_tokens | Compact the context at this token count. With context_window also set, the smaller value applies. |
keep_reasoning | true sends earlier reasoning back to the model on later requests. |
cache_ttl | Prompt-cache lifetime on the Anthropic wire: "1h" or "5m"; unset uses [limits] cache_ttl. A cache write costs 2x the input price at 1h and 1.25x at 5m; a read costs 0.1x either way. grok also sends x-grok-conv-id with the prompt hash so xAI routes each request to a warm cache. |
auth.token_url | Token endpoint of a login. Required with auth.client_id. |
auth.label | Name of the subscription shown when an endpoint offers both a sign-in and a key. |
auth.required_scope | A scope the token reply must grant, or the sign-in fails. |
auth.device_url | Device authorization endpoint for grant = "device_code". |
[limits] in ~/.summonr/config.toml overrides the built-in values in src/limits.toml: every timeout, retry, size, retention, and UI timing summonr uses. A key you leave out keeps its built-in value.
[limits]retry_after_max_secs = 30 cache_ttl = "5m" | Key | Built in | Meaning |
|---|---|---|
cache_ttl | "1h" | Prompt-cache lifetime for an endpoint that sets none: "5m" or "1h". |
retry_limit | 5 | Retries for a 429, a 5xx, or a connection error. |
retry_base_ms | 1000 | First retry wait; each retry doubles it. |
retry_max_ms | 30000 | Longest retry wait. |
retry_after_max_secs | 60 | Longest Retry-After summonr waits for; a longer one falls back to the next endpoint. |
stream_idle_secs | 240 | Idle stream timeout for an endpoint with no idle_timeout_secs. |
stream_total_secs | 86400 | Total time limit for one request. |
connect_secs | 20 | Connect timeout. |
compact_percent | 80 | Share of the context window that starts compaction. |
elide_percent | 60 | Share of the context window that compaction aims for by clearing old tool output; it summarizes only when clearing cannot get there. |
compact_chars | 400000 | Prompt size in characters that starts compaction when the window is unknown. |
summary_retry_rounds | 8 | Rounds before a failed compaction summary retries. |
job_wait_secs | 120 | Wait on a job or hook before it is reported still running. |
command_wait_secs | 120 | Time before a run_command continues as a background job. |
command_kill_secs | 3600 | Hard stop for a foreground command with no timeout_secs. |
grant_wait_secs | 600 | Wait for a permission answer. |
job_poll_start_secs | 1 | First job poll interval. |
job_poll_cap_secs | 2 | Longest job poll interval. |
mail_stale_secs | 120 | A mail peer with no heartbeat for this long is stale. |
mail_sweep_secs | 86400 | Mail entries older than this are removed. |
verify_timeout_secs | 600 | Timeout for a check command. |
probe_secs | 5 | Endpoint probe timeout. |
auth_secs | 30 | Sign-in request timeout. |
update_secs | 600 | summonr update download timeout. |
model_probe_secs | 8 | Model list request timeout. |
web_search_secs | 15 | Web search timeout. |
search_secs | 20 | Time one search call walks and scans before it returns what it found. |
search_index_after_ms | 1000 | A name search outside the workspace that walks at least this long builds a file index in the background. |
search_index_secs | 300 | Age at which a file index is rebuilt. |
models_catalog_secs | 3600 | Age at which the models.dev catalog is fetched again. |
models_listing_secs | 86400 | Age at which an endpoint's model list reads stale and the /model picker asks the endpoint again. |
web_connect_secs | 8 | Web connect timeout. |
web_fetch_secs | 20 | Web fetch timeout. |
web_body_bytes | 1048576 | Largest web response body. |
web_redirect_max | 5 | Most redirects a web request follows. |
keychain_ms | 5000 | OS keychain call timeout. |
keychain_poll_ms | 20 | Keychain poll interval. |
mcp_open_secs | 60 | MCP server start timeout. |
mcp_call_secs | 300 | MCP tool call timeout when a server sets none. |
mcp_idle_secs | 120 | MCP idle stop when a server sets none. |
lsp_idle_secs | 300 | Language-server idle stop. |
servers_max | 8 | MCP and language servers live at once; past it the least recently used idle one stops. |
receipt_items_max | 5 | Failures and changed files listed in an expanded turn receipt. |
closest_percent | 34 | A name is offered as the closest match only when it differs by at most this percent of the name length. |
typo_min_chars | 3 | An endpoint name with at least this many characters also gets a hint for one changed, added, or removed character, or two swapped adjacent characters. |
diff_split_min_cols | 100 | Narrowest diff pane that shows hunks side by side; a narrower pane shows the unified diff. |
mcp_progress_stretch | 4 | Progress can extend an MCP call up to this multiple of its timeout. |
mcp_cancel_write_secs | 1 | Time to write an MCP cancel. |
mcp_close_grace_ms | 500 | After closing a stdio MCP server's input, how long summonr waits for it to exit before it stops the process. |
image_side_px | 2000 | Longest side of an image sent to the model; a larger image is scaled down. |
image_bytes | 5000000 | Largest image sent to the model; a larger one is re-encoded to fit. |
mcp_log_max_bytes | 1048576 | MCP log size before rotation. |
mcp_frame_max_bytes | 4194304 | Largest MCP reply. |
mcp_stderr_tail_bytes | 2048 | MCP stderr kept for diagnostics. |
mcp_stderr_settle_secs | 1 | Most time spent draining MCP stderr after stdout closes. |
mcp_defer_bytes | 8192 | Tool schemas above this size go behind one mcp tool. |
mcp_found_max | 8 | Most deferred tools returned per search. |
lsp_start_secs | 30 | Language server start timeout. |
lsp_request_secs | 30 | Language server request timeout. |
lsp_check_secs | 5 | Diagnostics wait after an edit. |
log_retain_days | 14 | Log retention. |
session_retain_days | 30 | Session retention when [sessions] retain_days is unset. |
job_retain_days | 7 | Finished job retention. |
speed_window_secs | 3 | Window for the tokens-per-second figure. |
reader_window_ms | 400 | Stream batching window. |
stamp_settle_ms | 2000 | A cached secret scan trusts a file stamp only once the file is this much older than the scan. |
frame_window_secs | 1 | Frame budget window. |
animation_ms | 40 | Animation frame period. |
wake_margin_ms | 1 | Delay added after the start screen's next visible change before it wakes. |
spinner_ms | 100 | Spinner frame period. |
splash_reveal_ms | 760 | Splash reveal time. |
status_refresh_secs | 1 | Status line refresh. |
beat_secs | 2 | Heartbeat interval. |
notice_secs | 2 | Time a notice stays on screen. |
worker_stop_secs | 2 | Desktop worker stop wait. |
repeat_window_secs | 2 | Window for a double key press. |
step_attempts | 3 | Failed-check attempts per numbered plan step; not applied to goals. |
repair_limit | 6 | Argument repairs and overflow retries per turn. |
repeat_nudge | 5 | Times the same tool call, or the same cycle of up to three calls, may return the same result in a row before summonr adds a note to the result asking the model to change approach. The call still runs, and a new message starts the count again. 0 turns the note off. |
edit_hunk_rows | 80 | Rows shown per edit hunk. |
display_patch_lines | 1000 | Most patch lines shown. |
read_line_limit | 1000 | Largest read line limit. |
paste_fold_lines | 8 | A paste of this many lines folds. |
paste_fold_chars | 1000 | A paste of this many characters folds. |
cron_tick_secs | 60 | Interval at which the OS runs summonr cron tick after summonr cron install. |
cron_budget_secs | 1800 | Time budget of a cron run that sets no --max-secs. |
cron_runs_kept | 50 | Runs kept per cron job; older runs and their saved webhook bodies are deleted. |
cron_catchup_secs | 604800 | A missed cron time older than this is logged as expired instead of run. |
cron_fail_pause | 3 | Failed cron runs in a row before the job pauses itself. |
memory_bytes | 25000 | Bytes of each memory file loaded into a session. |
gateway_poll_secs | 50 | Long-poll wait of each Telegram update request. |
gateway_pair_secs | 3600 | Lifetime of a Telegram pairing code. |
gateway_port | 8765 | Port summonr gateway webhook listens on without --port. |
gateway_body_bytes | 65536 | Largest webhook body; a larger one answers 413. |
gateway_fire_secs | 60 | A second webhook fire of one job within this time answers 429. Scheduled runs and cron run do not count. |
gateway_head_secs | 2 | Time a webhook client has to send its headers. |
gateway_read_secs | 10 | Time a webhook request has to finish; a slower one answers 408. |
gateway_stop_secs | 5 | After /stop in a chat, wait this long before the remaining commands are killed. |
Environment variables
| Variable | Effect |
|---|---|
SUMMONR_HOME | summonr home directory. Default ~/.summonr. |
SUMMONR_ENDPOINT | Endpoint to start on when none is named on the command line. |
SUMMONR_MODEL | Model to start on when --model is not given. |
SUMMONR_SECRETS | Credential store: file (the default) or keychain. Overrides secrets in config.toml. |
SUMMONR_MAIL | off hides this session from peer mail and turns off the mail tools. |
SUMMONR_PLUGIN_ROOT, SUMMONR_PLUGIN_DATA | Set by summonr for a plugin's hooks: the plugin directory and its data directory. |
SUMMONR_BASE_URL | Use this OpenAI-compatible base URL as the endpoint when no endpoint is named. |
SUMMONR_API_KEY | API key for SUMMONR_BASE_URL. |
SUMMONR_MAX_TOKENS | max_tokens sent with SUMMONR_BASE_URL. |
SUMMONR_KEEP_REASONING | When set, SUMMONR_BASE_URL keeps reasoning as keep_reasoning = true does. |
SUMMONR_SYSTEM_PROMPT | Replace the whole system prompt. SYSTEM.md, AGENTS.md, CLAUDE.md, and skills are not added. |
SUMMONR_MODELS_URL | URL of the model catalog. |
SUMMONR_CRON | Set by summonr to the job name in a cron run. summonr cron add, edit, and remove refuse while it is set. |
SUMMONR_CAPTURE_DIR | Write raw provider request and stream frames as JSON lines to this directory. |
SUMMONR_VERSION | Installer: release tag to install. Default latest. |
SUMMONR_INSTALL_DIR | Installer: install directory. |
SUMMONR_LIBC | install.sh on Linux: musl (default) or gnu. |
Reasoning effort
The levels are none, minimal, low, medium, high, xhigh, and max. Each model accepts some of them. summonr sends the nearest level the model accepts, and the lower one when two are equally near. max on a model that stops at high sends high. medium on a model that accepts only low and high sends low.
A model that takes no effort setting gets no effort field, so a level you pick cannot fail the request. With no effort set and none remembered, summonr uses high for a model the catalog marks as reasoning. For any other model it sends no effort field, and the model uses its own default.
none turns thinking off where the model can turn it off. If the model cannot, summonr sends the lowest level it accepts.
Anthropic Messages (anthropic, or any row with wire = "anthropic"), by model id:
| Model | Levels | none |
|---|---|---|
claude-opus-5-5, claude-fable-5, claude-mythos-5 | low, medium, high, xhigh, max | sends low |
claude-mythos-preview | low, medium, high, max | sends low |
claude-opus-5, claude-sonnet-5 | low, medium, high, xhigh, max | thinking type disabled |
claude-sonnet-5-5 | low, medium, high, xhigh, max | thinking type between_tools |
claude-haiku-5-5 | low, medium, high, xhigh, max | thinking type disabled |
claude-opus-4-8, claude-opus-4-7 | low, medium, high, xhigh, max | no thinking field |
claude-opus-4-6, claude-sonnet-4-6 | low, medium, high, max | no thinking field |
claude-opus-4-5 | low, medium, high | no thinking field |
| Earlier Claude models | low, medium, high, sent as a thinking budget | no thinking field |
On claude-fable-5-1, claude-opus-5-5, claude-sonnet-5-5, and claude-haiku-5-5, summonr sends adaptive thinking with display: "summarized" and block_binding.prefix_mismatch_behavior: "drop_block" (beta thinking-binding-controls-2026-08-01), so a compacted history drops stale thinking blocks instead of failing. max_tokens defaults to 128,000 on Claude 5.x models and 64,000 on the 4.5 family; thinking counts toward it.
OpenAI (openai, on the chat or the Responses wire), by model id:
| Model | Levels | none |
|---|---|---|
gpt-6, gpt-5.6 | low, medium, high, xhigh, max | sends none |
gpt-6-astra | low, medium, high, xhigh, max | sends low |
gpt-5.5, gpt-5.4, gpt-5.2 | low, medium, high, xhigh | sends none |
gpt-5.1 | low, medium, high | sends none |
gpt-5 | minimal, low, medium, high | sends minimal |
gpt-5-pro | high | sends high |
Other gpt-5 models that contain -pro | medium, high, xhigh | sends medium |
gpt-5.3-codex, gpt-5.2-codex | low, medium, high, xhigh | sends low |
Other codex models | low, medium, high | sends low |
gpt-5-chat, gpt-4, gpt-3 | no effort setting | sends nothing |
Any other model, such as o3 | low, medium, high | sends low |
Gemini (gemini), by model id. Levels for gemini-2.5 models set the thinking budget:
| Model | Levels | none |
|---|---|---|
gemini-2.5-pro | low, medium, high | sends the low budget |
Other gemini-2.5 models | low, medium, high | sets the budget to 0 |
gemini-3-pro | low, high | sends low |
gemini-3 models that contain pro, 3.7, or 3.8 | low, medium, high | sends low |
Other gemini-3 models | minimal, low, medium, high | sends minimal |
Other built-in endpoints:
| Endpoint | Levels | none |
|---|---|---|
zai-intl, zai-cn, zai-api, zai-cn-api | no effort setting: GLM-5.3 and GLM-5.3-Flash always think, and their reasoning goes back between tool calls | sends nothing |
deepseek | minimal to max | thinking type disabled |
kimi-cn, kimi-intl | k3 and kimi-for-coding: low, high, max. kimi-k2 models and kimi-for-coding-highspeed: no effort setting. | k3: sends low. kimi-for-coding and kimi-k2.6: thinking type disabled. Others: sends nothing. Every Kimi Code model gets its reasoning back between tool calls. |
grok | grok-4.7 and grok-4.6: low to xhigh. Others: low, medium, high. | sends the lowest level |
muse | minimal to max; -contributor models stop at xhigh | sends minimal |
mistral | high | sends none |
cerebras, deepinfra, ollama | low, medium, high | sends none |
openrouter | minimal to xhigh, sent as reasoning with an effort key | sends none |
qwen-plan, qwen-plan-cn, dashscope, dashscope-cn | low, medium, high | Qwen 3.x Plus and Max: enable_thinking: false. Others: sends nothing |
together, groq, copilot, go, opencode, fireworks | low, medium, high | sends nothing |
minimax-api, minimax-cn | no effort setting; reasoning goes back between tool calls | sends nothing |
minimax-plan, minimax-cn-plan | low, medium, high | sends nothing |
tencent-plan, volcengine-plan, siliconflow, siliconflow-cn, nvidia, huggingface, cohere, ollama-cloud, lmstudio | tencent-plan and volcengine-plan: no effort setting. Others: low, medium, high | sends nothing |
summonr matches the model id against these model rows on every endpoint except copilot, openrouter, ollama, lmstudio, tencent-plan, and volcengine-plan, which pass any model through and use the endpoint's own levels. A model that matches no row uses the endpoint's levels. An endpoint with no built-in host uses low, medium, and high, and sends nothing for none.
Set the levels or the none style on an endpoint to replace the built-in behavior. A [endpoint.NAME.models.ID] row replaces it for one model.
[endpoint.local] base_url = "http://127.0.0.1:8080/v1" model = "qwen3" reasoning_levels = ["low", "high", "max"] thinking_off = "disabled" [endpoint.local.models.qwen3-small] reasoning_levels = [] reasoning_levels lists the levels the endpoint accepts, from minimal to max. An empty list sends no effort. thinking_off sets what none sends:
thinking_off | none sends |
|---|---|
omit | nothing |
none | the level none |
disabled | thinking with type disabled |
between_tools | thinking with type between_tools |
chat_template_kwargs | chat_template_kwargs with enable_thinking set to false |
unsupported | the lowest level in reasoning_levels |
The body table of an endpoint is merged last, so it can still set any field by hand.
Modes
| Mode | Enter | Leave | Job |
|---|---|---|---|
| Auto | default, /auto | /goal, /steps | Follow the request this turn. |
| Work | /steps FILE, --steps | steps end (auto), /auto | Run a plan's ## Steps one at a time, each with its check. |
| Goal | /goal TEXT, --goal | judge done / stop, /auto; the session returns to the mode it had before | Loop on an objective until checks pass and the judge says done. |
/goal with no check configured uses a check detected from the project: cargo test for Cargo.toml, go test ./... for go.mod, and npm test when package.json declares a test script. A Python project gets no detected check, and the judge decides. /goal prints the detected check and says how to set another in .summonr/check.toml.
Confirmation
Everything runs without a prompt except irreversible destruction: wiping the system, home, or project root, mkfs, dd to a device, a fork bomb, chmod -R 777 /, terraform destroy, cluster deletes, and dropped database tables. Those ask first with [ allow ] / [ deny ] (or y / n). -p has no one to ask, so they do not run there. Each turn's checkpoint makes the rest, such as git reset --hard, recoverable with /undo.
sudo asks for your password in a dialog. The password goes to sudo through SUDO_ASKPASS; the model never sees it, and command output is scrubbed of it.
Workflows
A workflow runs each role on its own model. Roles are scout, implement, review, judge, and summary; a role the workflow does not name runs on the endpoint and model you started with.
# ~/.summonr/config.toml workflow = "cheap-scout" # optional default [workflows.cheap-scout] scout = "grok" review = "zai" judge = "grok" summonr -w cheap-scout, /workflow cheap-scout in the interface, or the workflow key picks one; summonr workflows lists them. In the interface every card action has a verb too:
/workflow the card/workflow NAME | off apply a saved workflow, or none /workflow list | show saved workflows · the live seats/workflow set ROLE ENDPOINT [MODEL]/workflow clear ROLE/workflow save NAME write the live seats as [workflows.NAME] /workflow default NAME the workflow new sessions start with