summonr

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 --remove

summonr 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. Port 0 keeps 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_uri switches to paste-back: summonr asks for the code the browser shows and accepts the code#state form. 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.
  • scheme sets the carrier for the token: bearer (the default for every login), api_key, or google_key.
  • pkce = true adds 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.

ProviderRoutes
zaizai-intl (coding plan, international), zai-cn (coding plan, China), zai-api (API key, international), zai-cn-api (API key, China)
alibabaqwen-plan, qwen-plan-cn (coding plan), dashscope, dashscope-cn (API key)
kimikimi-cn (Kimi Code, China), kimi-intl (Kimi Code, international)
minimaxminimax-api, minimax-cn (API key), minimax-plan, minimax-cn-plan (coding plan, Anthropic wire)
siliconflowsiliconflow-intl (international), siliconflow-cn (China)
anthropicanthropic-api (API key), claude (Claude plan through Claude Code)
opencodeopencode-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

FlagEffect
-e, --endpoint NAMEUse endpoint NAME. A bare endpoint name as the first word does the same.
-p, --printRun one prompt and exit. A bare prompt after the options does the same.
-c, --continueResume the last session in this directory.
--forkCopy the resumed session (-c, --session) and continue the copy. Not with --goal or --steps.
--trustRead workspace SYSTEM.md, AGENTS.md, and CLAUDE.md. On by default.
--no-trustIgnore those workspace files.
--no-verifySkip the .summonr/check.toml gate.
--no-splashSkip the startup banner.
--inlineKeep the transcript in terminal scrollback, with the composer pinned at the bottom.
--hereWork in this checkout. This is the default; it cannot be combined with --worktree.
--model NAMEUse model NAME on the endpoint instead of its default.
--effort LEVELSet the reasoning effort: none, minimal, low, medium, high, xhigh, or max. See Reasoning effort.
-w, --workflow NAMESeat each step from [workflows.NAME].
--jsonPrint JSON: one event per line with -p, --goal, and --steps, and JSON output from diff, worktrees, mcp, and classify.
--session IDResume a session by id, short id, prefix, or name.
--name TEXTName this session.
--goal TEXTWork toward TEXT across turns until the check passes and the judge says done.
--steps PLAN.mdRun each item under ## Steps in PLAN.md and gate it on its check.
--max-tokens NSession token budget. A breach stops the run.
--max-secs NSession wall-clock budget in seconds. A breach stops the run.
--add-dir DIRAdd an extra writable root. Repeatable.
--strictAllow only the commands listed in policy.toml.
--worktreeIsolate this session in a git worktree.
--guiOpen the desktop window. Needs a build with --features gui.
-h, --helpShow the help.
-V, --versionShow 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 -p

Config keys

Top-level keys in ~/.summonr/config.toml:

KeyValuesEffect
splashtrue (default), falseShow the startup banner.
models_catalogtrue (default), falseFetch the models.dev catalog for summonr endpoints --check and /model; false keeps every request on your own endpoints.
animationstrue (default), falseAnimate the interface.
fps1 to 240, default 25Interface frame rate.
diff_layoutsplit (default), unifiedDiff pane layout.

Keys on an [endpoint.NAME] row:

KeyEffect
context_windowContext size in tokens. Without it, summonr asks the provider.
idle_timeout_secsSeconds a response stream may stay silent before the request fails. At least 1; default 240.
headersA table of extra HTTP headers sent on every request.
fallbackA list of endpoint names. When a request fails with an error that a retry cannot fix, the session moves to the next name.
compact_tokensCompact the context at this token count. With context_window also set, the smaller value applies.
keep_reasoningtrue sends earlier reasoning back to the model on later requests.
cache_ttlPrompt-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_urlToken endpoint of a login. Required with auth.client_id.
auth.labelName of the subscription shown when an endpoint offers both a sign-in and a key.
auth.required_scopeA scope the token reply must grant, or the sign-in fails.
auth.device_urlDevice 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 = 30cache_ttl = "5m"
KeyBuilt inMeaning
cache_ttl"1h"Prompt-cache lifetime for an endpoint that sets none: "5m" or "1h".
retry_limit5Retries for a 429, a 5xx, or a connection error.
retry_base_ms1000First retry wait; each retry doubles it.
retry_max_ms30000Longest retry wait.
retry_after_max_secs60Longest Retry-After summonr waits for; a longer one falls back to the next endpoint.
stream_idle_secs240Idle stream timeout for an endpoint with no idle_timeout_secs.
stream_total_secs86400Total time limit for one request.
connect_secs20Connect timeout.
compact_percent80Share of the context window that starts compaction.
elide_percent60Share of the context window that compaction aims for by clearing old tool output; it summarizes only when clearing cannot get there.
compact_chars400000Prompt size in characters that starts compaction when the window is unknown.
summary_retry_rounds8Rounds before a failed compaction summary retries.
job_wait_secs120Wait on a job or hook before it is reported still running.
command_wait_secs120Time before a run_command continues as a background job.
command_kill_secs3600Hard stop for a foreground command with no timeout_secs.
grant_wait_secs600Wait for a permission answer.
job_poll_start_secs1First job poll interval.
job_poll_cap_secs2Longest job poll interval.
mail_stale_secs120A mail peer with no heartbeat for this long is stale.
mail_sweep_secs86400Mail entries older than this are removed.
verify_timeout_secs600Timeout for a check command.
probe_secs5Endpoint probe timeout.
auth_secs30Sign-in request timeout.
update_secs600summonr update download timeout.
model_probe_secs8Model list request timeout.
web_search_secs15Web search timeout.
search_secs20Time one search call walks and scans before it returns what it found.
search_index_after_ms1000A name search outside the workspace that walks at least this long builds a file index in the background.
search_index_secs300Age at which a file index is rebuilt.
models_catalog_secs3600Age at which the models.dev catalog is fetched again.
models_listing_secs86400Age at which an endpoint's model list reads stale and the /model picker asks the endpoint again.
web_connect_secs8Web connect timeout.
web_fetch_secs20Web fetch timeout.
web_body_bytes1048576Largest web response body.
web_redirect_max5Most redirects a web request follows.
keychain_ms5000OS keychain call timeout.
keychain_poll_ms20Keychain poll interval.
mcp_open_secs60MCP server start timeout.
mcp_call_secs300MCP tool call timeout when a server sets none.
mcp_idle_secs120MCP idle stop when a server sets none.
lsp_idle_secs300Language-server idle stop.
servers_max8MCP and language servers live at once; past it the least recently used idle one stops.
receipt_items_max5Failures and changed files listed in an expanded turn receipt.
closest_percent34A name is offered as the closest match only when it differs by at most this percent of the name length.
typo_min_chars3An 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_cols100Narrowest diff pane that shows hunks side by side; a narrower pane shows the unified diff.
mcp_progress_stretch4Progress can extend an MCP call up to this multiple of its timeout.
mcp_cancel_write_secs1Time to write an MCP cancel.
mcp_close_grace_ms500After closing a stdio MCP server's input, how long summonr waits for it to exit before it stops the process.
image_side_px2000Longest side of an image sent to the model; a larger image is scaled down.
image_bytes5000000Largest image sent to the model; a larger one is re-encoded to fit.
mcp_log_max_bytes1048576MCP log size before rotation.
mcp_frame_max_bytes4194304Largest MCP reply.
mcp_stderr_tail_bytes2048MCP stderr kept for diagnostics.
mcp_stderr_settle_secs1Most time spent draining MCP stderr after stdout closes.
mcp_defer_bytes8192Tool schemas above this size go behind one mcp tool.
mcp_found_max8Most deferred tools returned per search.
lsp_start_secs30Language server start timeout.
lsp_request_secs30Language server request timeout.
lsp_check_secs5Diagnostics wait after an edit.
log_retain_days14Log retention.
session_retain_days30Session retention when [sessions] retain_days is unset.
job_retain_days7Finished job retention.
speed_window_secs3Window for the tokens-per-second figure.
reader_window_ms400Stream batching window.
stamp_settle_ms2000A cached secret scan trusts a file stamp only once the file is this much older than the scan.
frame_window_secs1Frame budget window.
animation_ms40Animation frame period.
wake_margin_ms1Delay added after the start screen's next visible change before it wakes.
spinner_ms100Spinner frame period.
splash_reveal_ms760Splash reveal time.
status_refresh_secs1Status line refresh.
beat_secs2Heartbeat interval.
notice_secs2Time a notice stays on screen.
worker_stop_secs2Desktop worker stop wait.
repeat_window_secs2Window for a double key press.
step_attempts3Failed-check attempts per numbered plan step; not applied to goals.
repair_limit6Argument repairs and overflow retries per turn.
repeat_nudge5Times 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_rows80Rows shown per edit hunk.
display_patch_lines1000Most patch lines shown.
read_line_limit1000Largest read line limit.
paste_fold_lines8A paste of this many lines folds.
paste_fold_chars1000A paste of this many characters folds.
cron_tick_secs60Interval at which the OS runs summonr cron tick after summonr cron install.
cron_budget_secs1800Time budget of a cron run that sets no --max-secs.
cron_runs_kept50Runs kept per cron job; older runs and their saved webhook bodies are deleted.
cron_catchup_secs604800A missed cron time older than this is logged as expired instead of run.
cron_fail_pause3Failed cron runs in a row before the job pauses itself.
memory_bytes25000Bytes of each memory file loaded into a session.
gateway_poll_secs50Long-poll wait of each Telegram update request.
gateway_pair_secs3600Lifetime of a Telegram pairing code.
gateway_port8765Port summonr gateway webhook listens on without --port.
gateway_body_bytes65536Largest webhook body; a larger one answers 413.
gateway_fire_secs60A second webhook fire of one job within this time answers 429. Scheduled runs and cron run do not count.
gateway_head_secs2Time a webhook client has to send its headers.
gateway_read_secs10Time a webhook request has to finish; a slower one answers 408.
gateway_stop_secs5After /stop in a chat, wait this long before the remaining commands are killed.

Environment variables

VariableEffect
SUMMONR_HOMEsummonr home directory. Default ~/.summonr.
SUMMONR_ENDPOINTEndpoint to start on when none is named on the command line.
SUMMONR_MODELModel to start on when --model is not given.
SUMMONR_SECRETSCredential store: file (the default) or keychain. Overrides secrets in config.toml.
SUMMONR_MAILoff hides this session from peer mail and turns off the mail tools.
SUMMONR_PLUGIN_ROOT, SUMMONR_PLUGIN_DATASet by summonr for a plugin's hooks: the plugin directory and its data directory.
SUMMONR_BASE_URLUse this OpenAI-compatible base URL as the endpoint when no endpoint is named.
SUMMONR_API_KEYAPI key for SUMMONR_BASE_URL.
SUMMONR_MAX_TOKENSmax_tokens sent with SUMMONR_BASE_URL.
SUMMONR_KEEP_REASONINGWhen set, SUMMONR_BASE_URL keeps reasoning as keep_reasoning = true does.
SUMMONR_SYSTEM_PROMPTReplace the whole system prompt. SYSTEM.md, AGENTS.md, CLAUDE.md, and skills are not added.
SUMMONR_MODELS_URLURL of the model catalog.
SUMMONR_CRONSet by summonr to the job name in a cron run. summonr cron add, edit, and remove refuse while it is set.
SUMMONR_CAPTURE_DIRWrite raw provider request and stream frames as JSON lines to this directory.
SUMMONR_VERSIONInstaller: release tag to install. Default latest.
SUMMONR_INSTALL_DIRInstaller: install directory.
SUMMONR_LIBCinstall.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:

ModelLevelsnone
claude-opus-5-5, claude-fable-5, claude-mythos-5low, medium, high, xhigh, maxsends low
claude-mythos-previewlow, medium, high, maxsends low
claude-opus-5, claude-sonnet-5low, medium, high, xhigh, maxthinking type disabled
claude-sonnet-5-5low, medium, high, xhigh, maxthinking type between_tools
claude-haiku-5-5low, medium, high, xhigh, maxthinking type disabled
claude-opus-4-8, claude-opus-4-7low, medium, high, xhigh, maxno thinking field
claude-opus-4-6, claude-sonnet-4-6low, medium, high, maxno thinking field
claude-opus-4-5low, medium, highno thinking field
Earlier Claude modelslow, medium, high, sent as a thinking budgetno 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:

ModelLevelsnone
gpt-6, gpt-5.6low, medium, high, xhigh, maxsends none
gpt-6-astralow, medium, high, xhigh, maxsends low
gpt-5.5, gpt-5.4, gpt-5.2low, medium, high, xhighsends none
gpt-5.1low, medium, highsends none
gpt-5minimal, low, medium, highsends minimal
gpt-5-prohighsends high
Other gpt-5 models that contain -promedium, high, xhighsends medium
gpt-5.3-codex, gpt-5.2-codexlow, medium, high, xhighsends low
Other codex modelslow, medium, highsends low
gpt-5-chat, gpt-4, gpt-3no effort settingsends nothing
Any other model, such as o3low, medium, highsends low

Gemini (gemini), by model id. Levels for gemini-2.5 models set the thinking budget:

ModelLevelsnone
gemini-2.5-prolow, medium, highsends the low budget
Other gemini-2.5 modelslow, medium, highsets the budget to 0
gemini-3-prolow, highsends low
gemini-3 models that contain pro, 3.7, or 3.8low, medium, highsends low
Other gemini-3 modelsminimal, low, medium, highsends minimal

Other built-in endpoints:

EndpointLevelsnone
zai-intl, zai-cn, zai-api, zai-cn-apino effort setting: GLM-5.3 and GLM-5.3-Flash always think, and their reasoning goes back between tool callssends nothing
deepseekminimal to maxthinking type disabled
kimi-cn, kimi-intlk3 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.
grokgrok-4.7 and grok-4.6: low to xhigh. Others: low, medium, high.sends the lowest level
museminimal to max; -contributor models stop at xhighsends minimal
mistralhighsends none
cerebras, deepinfra, ollamalow, medium, highsends none
openrouterminimal to xhigh, sent as reasoning with an effort keysends none
qwen-plan, qwen-plan-cn, dashscope, dashscope-cnlow, medium, highQwen 3.x Plus and Max: enable_thinking: false. Others: sends nothing
together, groq, copilot, go, opencode, fireworkslow, medium, highsends nothing
minimax-api, minimax-cnno effort setting; reasoning goes back between tool callssends nothing
minimax-plan, minimax-cn-planlow, medium, highsends nothing
tencent-plan, volcengine-plan, siliconflow, siliconflow-cn, nvidia, huggingface, cohere, ollama-cloud, lmstudiotencent-plan and volcengine-plan: no effort setting. Others: low, medium, highsends 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_offnone sends
omitnothing
nonethe level none
disabledthinking with type disabled
between_toolsthinking with type between_tools
chat_template_kwargschat_template_kwargs with enable_thinking set to false
unsupportedthe lowest level in reasoning_levels

The body table of an endpoint is merged last, so it can still set any field by hand.

Modes

ModeEnterLeaveJob
Autodefault, /auto/goal, /stepsFollow the request this turn.
Work/steps FILE, --stepssteps end (auto), /autoRun a plan's ## Steps one at a time, each with its check.
Goal/goal TEXT, --goaljudge done / stop, /auto; the session returns to the mode it had beforeLoop 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.tomlworkflow = "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