Skip to main content
A flavour is a top-level container selected once at launch, before user, agent, and thread. It scopes which agents are visible, which threads exist, and one shared long-term memory, and it overlays a common policy baseline onto its member agents. Think of it as choosing which workspace you are in. An engineering flavour session sees engineering agents, engineering threads, and one engineering memory.

The bundled flavours

The folder shape

A flavour is a folder, mirroring packages/ziro-core/src/ziro/agents/<id>/:
A subdirectory counts as a flavour when it contains flavour.yaml. The name falls back to the folder name.

The policy overlay

Selecting or switching a flavour is scope-only: it never writes a policy file. The overlay is merged in memory at config-load time. flavour_overrides(agent_id, filename) merges the flavour’s shared_policies[filename] with its per-agent policies["<agent>/<file>"]. Per-agent wins on a clash. The merged dict is applied onto the parsed YAML before the config object is built, by load_shell_config, load_voice_config, load_webfetch_config, load_websearch_config, and load_policies (guardrails). With no active flavour, the overrides are an empty dict and behaviour is byte-identical to a Ziro with no flavours at all.
The overlay is how a flavour narrows a member. In engineering, the coder loses web_search and web_fetch; in research, the analyst does. That is deliberate: the shell-and-write agents do not hold the ingress tools, so untrusted web content cannot reach an autonomous shell. The read-only agents keep web and hand vetted material over through the shared memory.

Shared memory

Every agent in a flavour shares one long-term memory store, keyed:
Both the memory loader and the save_memory tool key on flavour or agent_id. So a fact the product_manager saves is visible to the architect and the coder, and switching agents mid-thread never loses or cross-contaminates memory. A config with no flavour (subagents, legacy callers) falls back to agent_id, unchanged from before flavours existed.
Flavour keying supersedes the earlier sticky-memory mechanism. The behaviour you see is the same: an in-place /agent switch keeps the same thread and history. Only the memory-key plumbing under it changed.

Thread scoping

Entries in <DATA_DIR>/threads.json carry a flavour field, written on every turn (even when it is None). Every thread surface filters by the active flavour: the launch picker, the in-chat /thread and /threads pickers, /thread delete, the console prompt, and the thread-count gate in the launch flow. A research-flavour thread is invisible while you are chatting in chat.
On first run against a pre-flavour threads.json, Ziro renames the old index to threads.json.pre-flavour.bak so the flavour-scoped index starts clean. It is an atomic rename, never a delete, and it is one-time and idempotent: once the .bak exists, later launches are a no-op.

Persona composition

When a flavour’s persona.md is non-empty, it becomes the dominant voice for every member agent. The flavour persona leads; the agent’s own soul prompt is folded in as a subordinate note:
The role note is omitted when the agent has no soul of its own. Persona leads, agent soul narrows the role. This applies only on top-level turns. The agent node gates on the flavour key, which top-level runnable configs carry and subagent child configs never do, so scout, reflector, and the rest keep their own specialized souls unconditionally. With no active flavour, or a flavour with no persona.md, composition returns the agent’s own soul unchanged. Four personas ship:

There is no in-chat flavour switch

A flavour is chosen once at launch (via the --flavour flag, the launch flow’s flavour step, or the flavour picker) and it is not switchable mid-chat. There is deliberately no /flavour command. Typing /flavour prints a one-line redirect hint rather than rebuilding the session. To move to a different flavour, relaunch. Within the current flavour, use the in-chat /agent, /thread, and /user switches. This is why there is no rebuild_for_flavour on the session objects, and why flavour is absent from the commands that are safe to run mid-turn.

Resolution order

The flavour resolves as:
1

The --flavour flag

An explicit flag always wins.
2

The user's last flavour

Remembered per user in ~/.ziro/users.json.
3

The picker

Shown only when unresolved and two or more flavours are configured: skip-when-trivial, like every other launch step.
Headless resolution mirrors the interactive one (flag, then last flavour, then unresolved) without ever prompting.

Defense in depth

An explicit --agent (or a background job’s agent_id) that names an agent outside the active flavour is corrected to the flavour’s default_agent rather than run under its policy overlay. The same backstop applies to the interactive runner, the REPL session, and the background worker pool.

Known limitation

ziro init --flavour (the separate bake-into-a-project tool) only writes a flavour’s per-agent policies into the scaffolded project. It does not apply shared_policies.The scope-only runtime overlay described above is the primary, fully-supported path for a flavour’s shared policy baseline. Treat ziro init --flavour as a convenience seed, not a full bake.

Next steps

Agents

What each member agent is made of.

Memory

How the shared store and project memory differ.

Configuration

Writing your own flavour and policy layers.