The agent contract
An agent is declared as a map entry inagents.yaml. The key is the agent’s id (its address)
and, by default, the role name it fulfills (used to resolve prompts/<role>.md and to match
required_agents in schema.yaml), so you usually do not write id: or role: inside the
entry.
Memory scope is derived from the flow’s instance model — one conversation per flow
instance, so in a
mode: template flow that means one per instance/entity. memory: true on
a flow with no per-instance identity (a plain root flow) fails at boot with an error
explaining why: there is no flow-instance owner to scope the conversation to.
What an agent can call
You list only declared tools intools. Beyond those, every agent automatically gets:
- Universal tools:
agent_message,mailbox_send. - Emit tools:
emit_{event_name}for each entry inemit_events. - Role-scoped entity tools:
read_*,save_*,update_*, generated from the entity contract andentity_writes. read_flow_data: generated only when a flow-scoped agent declaresflow_data_access, to read deploy-time reference files shipped with the flow.
bash, web_search, file_io) are gated separately by the
native_tools field, a channel independent of tools and permissions. See
Tools.
Prompts
Each agent has a markdown prompt atprompts/{agent-id}.md. Prompts use {{variable}}
placeholders, substituted at session creation from four sources, in priority order:
- Instance variables
- Policy values
- Entity-state fields
- A small runtime-token allowlist (
current_date,agent_id,flow_instance_path)
Keeping reviewers independent
To stop two agents from sharing context, give a role two pools — separate agent entries for the same role with different subscriptions — and route originals to one and appeals to the other. Same prompt, separate sessions, no shared context.The older
model_tier and conversation_mode/session_scope fields are retired; model
and memory replace them.
