Config Files
Pythinker Code uses configuration files to manage API providers, models, services, and runtime parameters, supporting both TOML and JSON formats.
Config file location
The default configuration file is located at ~/.pythinker/config.toml. On first run, if the configuration file doesn't exist, Pythinker Code will automatically create a default configuration file.
You can specify a different configuration file (TOML or JSON format) with the --config-file flag:
pythinker --config-file /path/to/config.tomlWhen calling Pythinker Code programmatically, you can also pass the complete configuration content directly via the --config flag:
pythinker --config '{"default_model": "pythinker-for-coding", "providers": {...}, "models": {...}}'Config items
The configuration file contains the following top-level configuration items:
| Item | Type | Description |
|---|---|---|
default_model | string | Default model name, must be a model defined in models |
default_thinking | boolean | Whether to enable thinking mode by default (defaults to false) |
default_yolo | boolean | Whether to dangerously skip permission approvals by default (defaults to false) |
skip_auto_prompt_injection | boolean | Whether to suppress the auto-mode system reminder (defaults to false) |
default_plan_mode | boolean | Whether to start new sessions in plan mode by default (defaults to false); resumed sessions preserve their existing state |
default_editor | string | Default external editor command (e.g. "vim", "code --wait"), auto-detects when empty |
theme | string | Terminal color theme: "dark", "light", or "auto" (detects the terminal background at startup, falling back to dark); defaults to "dark" |
show_thinking_stream | boolean | Whether to stream the raw reasoning text in the live area as a 6-line scrolling preview and commit the full reasoning markdown to history when the block ends (defaults to true; set to false to show only the compact Thinking ... indicator and a one-line trace summary) |
prevent_idle_sleep | boolean | Whether to prevent the computer from idle-sleeping while an agent turn is running (defaults to false; supported on macOS, Linux, and Windows) |
auto_update | boolean | Automatically install new releases in the background at startup; the current session keeps running and you restart to apply (defaults to true) |
merge_all_available_skills | boolean | Whether to merge skills from all brand directories (defaults to true); see Skills configuration |
providers | table | API provider configuration |
models | table | Model configuration |
loop_control | table | Agent loop control parameters |
goal | table | Thread-goal (/goal) behavior, including auto-continuation |
compact_prompt | string | null | Override the built-in compaction summarization prompt; null/unset keeps the default handoff-structured prompt (a /compact focus argument is still appended on top) |
background | table | Background task runtime parameters |
services | table | External service configuration (search, fetch) |
web | table | Shared web fetch/search policy (e.g. allowed_domains) |
mcp | table | MCP client configuration |
Complete configuration example
default_model = "pythinker-for-coding"
default_thinking = false
default_yolo = false
skip_auto_prompt_injection = false
default_plan_mode = false
default_editor = ""
theme = "dark"
show_thinking_stream = true
prevent_idle_sleep = false
auto_update = true
merge_all_available_skills = true
[providers.pythinker-for-coding]
type = "pythinker"
base_url = "https://api.pythinker.com/coding/v1"
api_key = "sk-xxx"
[models.pythinker-for-coding]
provider = "pythinker-for-coding"
model = "pythinker-for-coding"
max_context_size = 262144
[loop_control]
max_steps_per_turn = 1000
max_retries_per_step = 3
max_ralph_iterations = 0
reserved_context_size = 50000
compaction_trigger_ratio = 0.85
[goal]
auto_continue = false
max_continuations = 3
[background]
max_running_tasks = 4
keep_alive_on_exit = false
agent_task_timeout_s = 3600
[services.pythinker_ai_search]
base_url = "https://api.pythinker.com/coding/v1/search"
api_key = "sk-xxx"
[services.pythinker_ai_fetch]
base_url = "https://api.pythinker.com/coding/v1/fetch"
api_key = "sk-xxx"
[web]
allowed_domains = ["example.com", "docs.python.org"]
[mcp.client]
tool_call_timeout_ms = 60000providers
providers defines API provider connection information. Each provider uses a unique name as key.
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | Provider type, see Providers for details |
base_url | string | Yes | API base URL |
api_key | string | Yes | API key |
env | table | No | Environment variables to set before creating provider instance |
custom_headers | table | No | Custom HTTP headers to attach to requests |
Example:
[providers.pythinker_ai-cn]
type = "pythinker"
base_url = "https://api.pythinker-ai.cn/v1"
api_key = "sk-xxx"
custom_headers = { "X-Custom-Header" = "value" }models
models defines available models. Each model uses a unique name as key.
Note
If a providers or models key contains ., you must use a quoted TOML key. Otherwise, TOML treats . as a path separator and parses the key as nested tables.
| Field | Type | Required | Description |
|---|---|---|---|
provider | string | Yes | Provider name to use, must be defined in providers |
model | string | Yes | Model identifier (model name used in API) |
max_context_size | integer | Yes | Maximum context length (in tokens) |
capabilities | array | No | Model capability list, see Providers for details |
display_name | string | No | Human-readable model name shown in the welcome panel, prompt status bar, /model picker, and switch confirmations; falls back to model when unset. For OAuth-logged-in managed models, this field is auto-refreshed from the provider's /models endpoint at startup |
Example:
[models.pythinker-ai-thinking]
provider = "pythinker_ai-cn"
model = "pythinker-ai-thinking"
max_context_size = 262144
capabilities = ["thinking", "image_in"]If the model name contains ., use a quoted key:
[models."gpt-4.1"]
provider = "openai"
model = "gpt-4.1"
max_context_size = 1047576
capabilities = ["thinking"]loop_control
loop_control controls agent execution loop behavior.
| Field | Type | Default | Description |
|---|---|---|---|
max_steps_per_turn | integer | 1000 | Maximum steps per turn (alias: max_steps_per_run) |
max_retries_per_step | integer | 3 | Maximum retries per step |
max_ralph_iterations | integer | 0 | Extra iterations after each user message; 0 disables; -1 is unlimited |
reserved_context_size | integer | 50000 | Reserved token count for LLM response generation; auto-compaction triggers when context_tokens + reserved_context_size >= max_context_size |
compaction_trigger_ratio | float | 0.85 | Context usage ratio threshold for auto-compaction (0.5–0.99); auto-compaction triggers when context_tokens >= max_context_size * compaction_trigger_ratio, whichever condition is met first with reserved_context_size |
goal
goal controls thread-goal (/goal) behavior.
| Field | Type | Default | Description |
|---|---|---|---|
auto_continue | boolean | false | Automatically continue turns toward the active /goal after the primary turn ends, until the goal is marked complete/blocked (via the UpdateGoal tool), a continuation is rejected, or the cap is reached |
max_continuations | integer | 3 | Maximum automatic goal continuations per user submission (1–10); the final continuation carries a wrap-up instruction |
background
background controls background task runtime behavior. Background tasks are launched via the Shell tool or the Agent tool with run_in_background=true.
| Field | Type | Default | Description |
|---|---|---|---|
max_running_tasks | integer | 4 | Maximum number of concurrent background tasks |
keep_alive_on_exit | boolean | false | Whether to keep background tasks running when CLI exits; default is to terminate all background tasks on exit |
kill_grace_period_ms | integer | 2000 | Grace period (in milliseconds) to wait after sending SIGTERM during CLI shutdown before reporting any shell workers that have not yet written terminal state. Agent tasks transition to terminal synchronously on kill and do not use this grace period |
agent_task_timeout_s | integer | 3600 | Maximum runtime in seconds for a background agent task; timed-out tasks are marked as failed, the main agent is notified, and the saved subagent can be resumed with a narrower prompt |
print_wait_ceiling_s | integer | 3600 | Hard ceiling (in seconds) for how long one-shot --print mode waits for background tasks to finish before killing them and exiting. The effective wait is the longest remaining task budget, clipped by this ceiling |
services
services configures external services used by Pythinker Code.
pythinker_ai_search
Configures web search service. When enabled, the SearchWeb tool becomes available.
| Field | Type | Required | Description |
|---|---|---|---|
base_url | string | Yes | Search service API URL |
api_key | string | Yes | API key |
custom_headers | table | No | Custom HTTP headers to attach to requests |
pythinker_ai_fetch
Configures web fetch service. When enabled, the FetchURL tool prioritizes using this service to fetch webpage content.
| Field | Type | Required | Description |
|---|---|---|---|
base_url | string | Yes | Fetch service API URL |
api_key | string | Yes | API key |
custom_headers | table | No | Custom HTTP headers to attach to requests |
TIP
When configuring the Pythinker platform using the /login command, search and fetch services are automatically configured.
web
web configures policy shared by the FetchURL and SearchWeb tools.
| Field | Type | Default | Description |
|---|---|---|---|
allowed_domains | array<string> | unset | When set, web fetch and search may only touch these domains and their subdomains. FetchURL rejects URLs on other hosts before making any request — including redirect targets, which are re-validated on every hop — and SearchWeb drops results from other domains. Unset or empty means unrestricted. Entries must be bare hostnames (e.g. example.com), not URLs, paths, or host:port. |
This is a coarse governance control layered on top of the existing SSRF protections (which always block private, loopback, link-local, multicast, and reserved addresses); it does not replace them. Matching is label-aware: example.com matches example.com and docs.example.com, but not notexample.com.
mcp
mcp configures MCP client behavior.
| Field | Type | Default | Description |
|---|---|---|---|
client.tool_call_timeout_ms | integer | 60000 | MCP tool call timeout (milliseconds) |
hooks
hooks configures lifecycle hooks (Beta feature). See Hooks for details.
Use the [[hooks]] array syntax to define multiple hooks:
[[hooks]]
event = "PreToolUse"
matcher = "Shell"
command = ".pythinker/hooks/safety-check.sh"
timeout = 10
[[hooks]]
event = "PostToolUse"
matcher = "WriteFile"
command = "prettier --write"| Field | Type | Required | Description |
|---|---|---|---|
event | string | Yes | Event type, e.g., PreToolUse, Stop, etc. |
command | string | Yes | Shell command to execute |
matcher | string | No | Regex filter condition |
timeout | integer | No | Timeout in seconds, default 30 |
JSON configuration migration
If ~/.pythinker/config.toml doesn't exist but ~/.pythinker/config.json exists, Pythinker Code will automatically migrate the JSON configuration to TOML format and backup the original file as config.json.bak.
--config-file specified configuration files are parsed based on file extension. --config passed configuration content is first attempted as JSON, then falls back to TOML if that fails.