Documentation Index
Fetch the complete documentation index at: https://qitor.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Engine is the single execution kernel for all QitOS agent workflows. It runs the step loop, coordinates your AgentModule hooks, dispatches tool calls to the ToolRegistry for execution, applies critics (post-step evaluators that can approve, stop, or retry the step), checks stop conditions, and writes trace artifacts (persistent records like steps.jsonl and events.jsonl that capture what happened during the run). You interact with it directly only when you need control beyond what agent.run() provides.
QitOS enforces a single-kernel rule: there is exactly one
Engine per run. Extensions like parsers, critics, memory adapters, and toolkits attach to this pipeline — they do not introduce a second execution loop.How the loop works
Each step follows a fixed sequence:- prepare —
agent.prepare(state)formats state into the model-ready prompt text. - decide —
agent.decide(state, observation)is checked first; if it returnsNone, the Engine calls the LLM via the configured parser. - act — Tool calls in the decision’s
actionslist are executed against theToolRegistry. - reduce —
agent.reduce(state, observation, decision)updates state with the new observation. - critics — Any registered
Criticinstances (post-step evaluators that can approve, stop, or retry the step) evaluate the step; they can trigger a stop or retry. - check_stop — Budget exhaustion,
FinalResultCriteria,agent.should_stop(), and any customStopCriteriaare evaluated. - trace — The step record and events are written to the
TraceWriter.
Constructor
| Parameter | Type | Description |
|---|---|---|
agent | AgentModule | Required. The policy module to execute. |
budget | RuntimeBudget | None | Step/time/token limits. Defaults to RuntimeBudget(max_steps=10). |
parser | Parser | None | Parses raw model output into a Decision. Must match your prompt format. |
critics | list[Critic] | None | Post-step evaluators that can stop or retry a step. |
stop_criteria | list[StopCriteria] | None | Stop conditions. Defaults to [FinalResultCriteria()]. |
env | Env | None | Environment providing reset/observe/step/is_terminal/close. |
trace_writer | TraceWriter | None | Writes manifest.json, events.jsonl, steps.jsonl for this run. |
hooks | list[EngineHook] | None | Hook instances called on lifecycle events. |
render_hooks | list | None | Render hooks (e.g., terminal UI). Appended to hooks internally. |
history_policy | HistoryPolicy | None | Controls how the in-run conversation history is managed. |
recovery_policy | RecoveryPolicy | None | Controls how the Engine responds to step failures. |
Engine.run(task)
Task object. Returns an EngineResult.
When you pass a Task, the Engine extracts the budget from task.budget and overrides the Engine’s own budget for that run. It also orchestrates resource staging and environment lifecycle (reset, observe, close) automatically.
EngineResult
| Field | Description |
|---|---|
state | Final typed state after the run. Check state.final_result and state.stop_reason. |
records | One StepRecord per step, containing decision, observation, and diffs. |
events | All RuntimeEvent objects emitted during the run. |
step_count | Number of steps executed (len(records)). |
task_result | Structured outcome including success flag and criterion results. |
Hooks
Hooks observe and react to lifecycle events without modifying Engine internals. They implementEngineHook and are called at on_before_step and on_after_step boundaries.
hooks parameter, or at run time via agent.run(hooks=[...]).
Budget exhaustion
When the step budget, wall-clock time limit, or token budget is exceeded, the Engine setsstate.stop_reason to the appropriate value and emits an END event. The run terminates gracefully and EngineResult is still returned — inspect state.stop_reason to detect this case.
Building an Engine from AgentModule
AgentModule.build_engine() is a convenience factory that creates an Engine pre-bound to the agent:
Engine(agent=agent, ...) and is what agent.run() calls internally.