Configuration¶
File location and loading¶
flowchart TD
A["XUN_HOME, else ./.xun"] --> B["config.json"]
B --> C["deep-merged onto the built-in template"]
C --> D["substitute ${XUN_...} placeholders"]
D --> E["pydantic validation"]
E --> F["Agent.config takes a deep clone"]
get_home_dir():XUN_HOMEwins, otherwise.xun/under the current working directory. The container image pinsXUN_HOME=/.xun.- The same directory also holds:
conversation/(history),extensions/(extensions),x/xunx.db(thexunxuser database). - When
xunc/xunxcreate a container they copy onlyHOME_COPY_INCLUDE(config.json,extensions) from the host xun home. xun_version()(exported at package level) returns the installed release version, orNonewhen running from source without package metadata; the extension version gate relies on that, see Extension system.- The reading entry point
load_config(force_reload: bool = False) -> AgentConfigcaches in-process;Agent.configis a deep copy of it by default, so changing one agent's configuration does not affect the global one. load_dotenv()is called while loading; keep secrets in.env.- There is no write-back API:
config.jsonis written by hand by the user;to_json()exists only for the/configprintout, and changes made by/yoloor by extensions live in memory only.
Structure and fields¶
Every configuration model is extra="forbid": a misspelled field name raises an error instead of being silently ignored.
| Field | Type | Default | Description |
|---|---|---|---|
auto_confirm |
bool |
${XUN_AUTO_CONFIRM}, falls back to false |
automatically confirm prompts (choices take the default option, source="auto"); does not write to the allowlist; the ask_preference tool skips auto-confirmation and always asks |
enable_extensions |
bool |
true |
whether extensions are loaded; internal helper agents (risk assessment, summarisation) turn it off themselves |
provider.openai_base_url |
str |
${XUN_OPENAI_BASE_URL} |
OpenAI-compatible endpoint, an error is raised when missing |
provider.openai_api_key |
str |
${XUN_OPENAI_API_KEY} |
the API key, an error is raised when missing |
model.name |
str |
${XUN_OPENAI_MODEL}, falls back to "" |
when empty, the first entry of models.list() is taken during initialization (a warning is raised when there is more than one, an error when there is none) |
model.capabilities |
set["vision"] |
["vision"] |
the value domain is only vision for now (ModelCapabilityType), any other value fails validation; used to filter tools by required_capabilities |
model.temperature |
float \| None |
None |
when None, the parameter is not sent |
model.reasoning_field |
str \| None |
None |
reasoning or reasoning_content; None means detect it automatically on first sight and cache the result |
model.reasoning_effort |
"none"\|"minimal"\|"low"\|"medium"\|"high"\|"xhigh"\|"max" | None |
None |
some models support only a few of these levels |
auto_compact.enabled |
bool |
true |
switch for automatic compaction |
auto_compact.token_threshold |
int |
192000 |
compaction is triggered once the tokens of the previous model call exceed this value |
The built-in template (the configuration file is deep merged over it field by field):
{
"auto_confirm": "${XUN_AUTO_CONFIRM}",
"enable_extensions": true,
"auto_compact": { "enabled": true, "token_threshold": 192000 },
"provider": {
"openai_base_url": "${XUN_OPENAI_BASE_URL}",
"openai_api_key": "${XUN_OPENAI_API_KEY}"
},
"model": { "name": "${XUN_OPENAI_MODEL}", "capabilities": ["vision"] }
}
Placeholder rules¶
- A placeholder must start with
XUN_, otherwiseRuntimeError: Invalid placeholder .... - Resolution order:
os.environ→ the built-in fallback table (XUN_OPENAI_MODEL="",XUN_AUTO_CONFIRM="false") → if neither is present,RuntimeError: Missing environment variable .... - Substitution happens before JSON parsing, and the substituted value is always a string, converted to
bool/intby pydantic in lax mode. SoXUN_AUTO_CONFIRM=""(present but empty) is not rescued by the fallback value and fails during validation.
Environment variable list¶
| Variable | Read by | Purpose |
|---|---|---|
XUN_HOME |
get_home_dir() |
root directory for configuration/extensions/history; excluded when container environment variables are forwarded |
XUN_OPENAI_BASE_URL |
configuration template | the endpoint |
XUN_OPENAI_API_KEY |
configuration template | the API key |
XUN_OPENAI_MODEL |
configuration template | model name, auto-detected when empty |
XUN_AUTO_CONFIRM |
configuration template | automatic confirmation |
_XUN_DEFAULT_MAX_ITER |
agent.py |
the default max_iterations of execute() (512 built in) |
_XUN_INFO_TOOL_OVERRIDE |
toolbox.py |
print tool override/replacement information |
XUN_* / _XUN_* |
container entry points | the pattern always forwarded by xunc --env / xunx serve --env |
Names starting with _XUN_ are internal switches (get_internal_env() / get_internal_env_bool()), not user-facing configuration options.
Common ways to change it¶
{
"model": { "name": "my-model", "temperature": 0.2, "reasoning_effort": "low" },
"auto_compact": { "token_threshold": 64000 }
}
export XUN_OPENAI_BASE_URL=https://api.example.com/v1
export XUN_OPENAI_API_KEY=sk-...
export XUN_AUTO_CONFIRM=true
from xun import Agent
from xun.config import load_config
cfg = load_config().clone() # config.json (and .env), deep-copied
cfg.model.name = "my-model"
cfg.auto_compact.enabled = False
agent = Agent(config=cfg)
# $XUN_HOME/extensions/use_weak_model.py
"""Pin a small model for every agent."""
from xun import ExtensionContext
def setup_extension(ctx: ExtensionContext) -> None:
ctx.agent.config.model.name = "small-model"
Extensions run before the model is auto-detected, so an override here takes effect.
Prompts¶
The system prompt is not a configuration option but a constant in src/xun/prompt.py: the main agent uses get_system_prompt(), sub-agents use get_subagent_prompt(); compaction has its own templates (see Session and auto compaction). To replace it:
agent = setup_agent(default_system_prompt=False)
agent.system("You are a terse assistant. Answer in one sentence.")
system() overwrites message 0 of the session and can be called again at any time (summary compaction rewrites this message as well). The AGENTS.md convention used by compaction also comes from the prompt text: the framework asks the agent to look at AGENTS.md in the working directory first and to follow it — this is a prompt-level convention, the code does not parse that file.