settings.yaml per agent, with one
optional section per concern. Host-level knobs that bound the whole application
(not a single persona) live one level up, in a layer-root settings.yaml.
Ziro reads both across a fixed chain of layers, most specific to least, and falls
back to built-in defaults when nothing supplies a value.
The older layout of one split file per concern (
shell_policy.yaml,
permissions.yaml, …) still works: Ziro dual-reads a section from
settings.yaml or the matching split file at each layer. The bundled agents
now ship as consolidated settings.yaml; run ziro migrate-config to fold your
own split files into one file.The per-agent folder
An agent is a directory whose name is the agent id. Itssettings.yaml holds the
sections it sets; a missing section falls back to the built-in default.
_policy / _servers / _config
suffix: shell_policy.yaml → shell, mcp_servers.yaml → mcp,
agent_config.yaml → persona, plugin_config.yaml → plugins.
registry.yaml is deliberately tiny: it names the default agent and nothing else.
Whether an agent is selectable is its own meta.enabled flag, not a central list.
The resolution chain
Config resolves across three layers, most specific first:1
Project layer
<project>/.ziro/agents/<id>/: this repo, this agent.2
User layer
~/.ziro/agents/<id>/: this machine, this agent. How you configure a
pip-installed Ziro without editing the package.3
Bundled package
The
settings.yaml shipped inside the ziro package.4
Built-in defaults
No layer defines a section: the loader constructs the config object from its
model defaults.
- Per section, deep-merged across layers. For each section, every layer that
defines it contributes, and the layers deep-merge most-specific-last: a
project
settings.yamlthat sets onlyshell.timeout_sinherits the rest of the bundledshellsection. This is safer than a wholesale replace: you cannot silently drop a guardrail by omitting it. - Section or split file, per layer. At each layer the contribution is that
layer’s
settings.yamlsection if present, else its legacy split file. So a project splitshell_policy.yamlstill overrides a bundledshellsection.
A missing section is normal and safe: it degrades to built-in defaults. The one
deliberate exception is the
plugins section: an agent no layer supplies it for
surfaces zero plugins (absence is opt-out). See Plugins.Trust gate
Thepermissions, mcp, hooks, and plugins sections can widen authority or
launch a subprocess, so they are ignored from an untrusted project layer (they
fall through to the user / bundled layers). The first interactive run in a new
project prompts to trust it. See Permissions.
The top-level resource tier
Some knobs bound host resources, not a persona: how many subagents fan out, the background job pool, scratch and background-shell garbage collection. Because a thread can switch agents mid-conversation, these do not belong on any one agent. They live in a layer-rootsettings.yaml (~/.ziro/settings.yaml,
<project>/.ziro/settings.yaml, or bundled):
resources values are ceilings: a project layer may lower them but never
raise them above the user layer, and the whole block is ignored from an untrusted
project. security.fs_deny_paths is the symmetric floor: it only ever adds to
the non-removable shipped secret list, so a project (or an agent’s own fs
section) can tighten what is denied but never open a hole in it.
Where the top-level tier is unset, each knob falls back to the per-agent value
(subagents, queue, fs sections), so existing configs keep working.
The flavour overlay
A flavour is a top-level container selected once at launch. Beyond scoping which agents and threads you see, it can overlay a policy baseline onto its member agents, merged in memory, before the config object is built:
So the full order for any one config value is:
ziro init --flavour <name> writes a flavour’s
overrides into the scaffolded project agent’s settings.yaml sections.
Registration gates
Several sections gate registration entirely: whenshell, websearch, or
webfetch has enabled: false (or is absent, for the default-off features), the
tool is never registered. It is invisible to search_tools and to the subagent
permission view. The absence is the disable switch.
Migrating split files
*.migrated backups (use --delete to remove them).
The three state files
Config files describe intent and are yours to edit and commit. State files record what happened and are written by Ziro. Do not hand-edit them.layered env file
API keys, the default model, the LLM provider, Langfuse credentials, and
DATABASE_URL. Written by the setup wizard (ziro setup) and by /settings.
Read as layers, so a project-level .env can override it.MRU registry
The list of known user ids,
last_user, and the last flavour each user chose.
Drives the launch-time user picker and the /user command.per-workspace index
Thread metadata: user, agent, flavour, title, timestamps, and any per-thread
LLM or plugin overrides. Checkpoints remain the source of truth for
conversation content. This file is the index over them, and is rebuildable.
<basename>-<hash>): project memory under ~/.ziro/projects/<key>/memory/ and
the per-thread scratchpad under your system temp directory. See
Memory.
Runtime mode
One environment variable decides the whole storage backend:Inspecting and editing
/settings edits the API key, model, Langfuse, and database entries in
~/.ziro/.env, queuing a live rebind only for the section you actually changed.
Next steps
Agent file reference
Every section of
settings.yaml.Environment variables
Every variable Ziro reads and where it is written.
Providers and models
Pinning a provider and model per agent.