Core features
The heart of Z Engine: how a conversation runs, how tools run and how permissions decide. Steering, plan mode, hooks and commands are in Interaction features. Each section goes from plain words to developer detail; see How to read these pages.
Conversations, turns and rounds
In plain words
A chat is a notebook with a running conversation. Each message you send starts a turn: one errand for the agent. Inside a turn the agent works in small steps called rounds: think, act, look at what happened, repeat.
How it works
- A session is one chat. Its log is written to disk before the app shows each change, so a chat reopens where it was, even after a crash; a turn cut short by closing the app shows as interrupted.
- A turn starts when you send a message or a prompt command:
UserPromptSubmithooks may add context or block it; the opening message is built (your text and attachments, steering left from an ended turn, reminders such as "plan mode is on"); a checkpoint of your files is taken before any tool may run; then rounds run until the stop boundary ends the turn. - A round is one request to the model and what follows:
- Budgets: at most
agents.max_turnsrounds per run (default 200), and the session cost capagents.session_cost_cap_usd(0 means off). A spent budget ends the turn as budget exhausted. - Context pressure: above half of the context window old tool results are cleared; above
context.compact_at_percent(default 92) older history is summarized (compaction). - Request and stream: the request is built and the answer streams in.
- Record: the answer, its token usage and its cost are saved.
- Next: tool calls run as a batch and a new round starts; no tool calls leads to the stop boundary.
- Budgets: at most
- One rule keeps every conversation valid: each tool call gets exactly one tool result, in order, even when denied or cancelled. That is why a chat can be resumed with any provider.
For developers
- session/actor.rs owns the command channel and runs each turn in its own task; session/turn.rs runs one turn and session/prompt.rs builds its opening message.
AgentRunin run/agent.rs drives the rounds with its neighbours inrun/:budget.rs,pressure.rsandcompact.rs,request.rs,stream.rs(a context-overflow error forces compaction and one retry),usage.rsandstop.rs.- session/journal.rs appends each record before its event is published; replay.rs rebuilds the state from the log without repeating side effects.
- Protocol: command
submit; eventsturnStarted,usageUpdated,retryingandturnFinished(outcome, usage, cost and badge). - If you add an early exit to the loop, close every open tool call first.
Tools and tool batches
In plain words
Tools are the agent's hands; each does one job, such as reading a file or running a command. When the model asks for several at once, the engine works like a careful assistant: look-only jobs happen together, anything that changes something happens alone and in order, and every request gets an answer.
How it works
Z Engine has 22 built-in tools, named and shaped like Claude Code's:
| Group | Tools |
|---|---|
| Files | Read, Write, Edit, MultiEdit, NotebookEdit, Glob, Grep |
| Shell and background jobs | Bash, JobOutput, JobKill |
| Web | WebFetch, WebSearch |
| Working with you | TodoWrite, AskUserQuestion, ExitPlanMode |
| Skills and agents | Skill, Agent, ApplyAgentChanges |
| Evidence and code intelligence | Verify, LSP |
| MCP resources | ListMcpResources, ReadMcpResource |
MCP servers add tools named mcp__<server>__<tool>; LoadMcpTools appears only while MCP schemas are deferred (integrations and safety). Each run gets a filtered list: an agent definition may limit its tools, AskUserQuestion and ExitPlanMode are for the main agent only, Agent disappears at the nesting limit, and tools of services that are off are left out.
All tool calls in one model answer form a batch:
- Check: an unknown tool, malformed JSON or a missing required field gives an error result.
- Gate:
PreToolUsehooks run, then the permission decision. - Approvals: every call that needs approval shows its card at once, and you answer in any order. The batch runs when all are answered.
- Run in order: neighbouring calls that are safe together (read-only calls, and
Agent) run at the same time; any other call is a barrier and runs alone. - Report: each call streams progress;
PostToolUsehooks may add feedback to its result. - Return: all results go back in call order in one message, with queued steering and reminders.
Results always pair with calls: a call you denied returns "The user denied this action" plus your feedback, a rule's refusal returns its reason, a cancelled call returns "cancelled by user", a failure returns its error. The tools also protect you:
- Edits need a fresh read: the engine remembers what each file looked like when the model last read it and refuses an edit based on stale content.
- A write marks the turn as changed (for the verification badge); touching a new folder can bring in its
AGENTS.mdor matching rule files as a reminder. Bashkeeps its working directory between calls and can start background jobs, read withJobOutputand stopped withJobKill.- Very long outputs are shortened; the full text is saved as an artifact in the session folder.
For developers
- The
Tooltrait in tool.rs:is_read_only,is_concurrency_safe(defaults to read-only;Agentopts in,TodoWrite,AskUserQuestionandExitPlanModeopt out),action(what the policy decides on),title,preview(the approval card's diff or command) andcall. - Names in names.rs; stable order in registry.rs so the prompt cache holds; one file per tool in builtin/; descriptions in prompts/tools/. Each call gets a
ToolCtx(ctx.rs) and reaches the engine only through ports. - The engine's batch lives in batch/:
toolset.rs(the offered list),schema.rs,gate.rs,approval.rs, execute.rs (ordering),call.rsandprogress.rs(at most about twenty progress events a second). - Events:
toolStarted,toolProgressandtoolFinished, whoseToolStatusisok,error,deniedorcancelled. - To add a tool, follow the "a tool" row in AGENTS.md.
Permissions: modes, rules and approvals
In plain words
Permissions work like the key cards of an office building. Some doors open for everyone, some need a swipe each time, some stay locked. The mode sets how strict the building is today; rules are your exceptions for particular doors.
How it works
Each tool call is first described as an action: read paths, write paths, run a command, fetch a URL, search the web, start an agent, call an MCP tool, load a skill, or other. The policy decides on the action, never on raw tool input, so a Read(./.env) deny rule also stops cat .env.
| Mode (label in the app) | Setting | In short |
|---|---|---|
| Ask | default | Asks before edits and before commands not proven read-only |
| Auto-accept edits | acceptEdits | Edits inside the project and simple file commands run; other commands ask |
| Plan | plan | Read-only: anything that changes state is refused |
| Bypass | bypass | Everything runs except what a deny rule forbids |
- Shell lines are split into their commands, including
$(...)and wrappers. A deny or ask rule matches if it matches any command; an allow rule helps only if it covers every command. A command counts as read-only only when the engine can prove it. - Protected paths (any
.gitfolder, the project's.z-engine/,.claude/settings.json,.claude/settings.local.json,.mcp.json) always ask before a change, even with an allow rule or in Auto-accept edits; only Bypass allows them. - Approval cards ask a question ("Allow Bash to run npm test?") over a preview (a diff or a command). Allow once runs this call; Always allow… then In this chat also adds the suggested rule, such as
Bash(npm test:*), for the rest of the chat, and In this project also saves it to.z-engine/settings.local.toml; Deny… sends your optional feedback to the model. Targets outside the project can be allowed for the session only; protected paths never offer a rule. Subagents pass the same gate, with cards labelled by agent. - Subagents are decided in their own mode (their definition's, else their caller's), except that while the chat is in Bypass they all bypass too; see the agent registry.
For developers
z-engine-policydoes no I/O. action.rs definesAction; decide/pipeline.rs holds the order above, withfiles.rs(paths, protected paths),execute.rs(shell rules, read-only and Auto-accept defaults, the suggestedBash(<prefix>:*)rule) andsandbox.rsbeside it; rules/ parses rules and gitignore-style paths; shell/ lexes command lines and proves them read-only.- settings/policy.rs builds a session's policy (a rebuild keeps session rules and
/add-dirfolders); broker/approvals.rs announces a batch's approvals together and audits each answer. - Protocol (permission.rs):
PermissionMode,ApprovalRequestandApprovalDecision(AllowOnce,AllowSession { rule },AllowProject { rule },Deny { feedback }); commandsresolveApproval,setMode; eventsapprovalRequested,approvalResolved,modeChanged. - A new tool returns the most specific
Action, andaction()must stay conservative even for malformed input.
See also: How Z Engine works · Interaction features · Agents and context · Integrations and safety · Glossary · User guide