> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reasonblocks.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Monitors

> ReasonBlocks runs six trajectory monitors server-side on /monitors/evaluate. They detect failure patterns mid-run and produce the steering text appended to the system message.

ReasonBlocks evaluates trajectory health with six trajectory monitors that run **server-side** on rb-api. `MonitorSteeringInjection` posts the trace to `POST /monitors/evaluate` each step; when a monitor fires, the server returns steering text that the middleware appends to the system message as the `[REASONBLOCKS]` block.

<Note>
  Earlier SDK versions shipped a local pure-Python monitor suite (`reasonblocks.monitors.suite.evaluate_all`, `DEFAULT_WEIGHTS`). That suite has been removed — monitor evaluation now runs server-side only. If you need a local trajectory signal (for example, to drive `TokenSavingMiddleware`'s early-exit nudge), supply your own `signals_fn`; see [token saving](/guides/token-saving).
</Note>

## How monitor steering works

`MonitorSteeringInjection.retrieve` posts the current trace to `POST /monitors/evaluate` with the model identifier, `task_profile`, and any explicit weight overrides. The server runs the six monitors, applies its injection gate, optionally falls back to an E2 pattern lookup, and returns:

```python theme={null}
{
    "inject":              bool,           # whether to fire an injection this step
    "intervention_text":   str | None,     # text to append to the system message
    "fired":               list[str],      # monitors whose score reached the fire threshold
    "scores":              dict[str, float],
    "composite":           float,          # weighted sum across the six monitors
    "failure_type":        str | None,     # categorical failure label
    "intervention_source": str | None,     # which path produced intervention_text
}
```

When `inject` is `True` and the text is new (different from the last firing), the middleware queues a `PendingInjection` carrying that text plus `monitors_fired` and `failure_type`. Per-run guardrails are enforced client-side after the server's decision:

* **Hard cap of 5 monitor injections per run.**
* **Cooldowns by FSM state:** every 2 steps in `SLOW`/`SKIP`, every 3 in `NORMAL`, every 5 in `FAST`.
* **Duplicate suppression:** the same intervention text is not re-queued back-to-back.

The `task_profile` argument selects the server-side weight preset (`coding`, `pr_review`, `qa`). See [Monitor weights and profiles](/configuration/monitor-profiles) for the per-profile weight tables and how to override individual weights.

## The six monitors

Scores are in `[0, 1]` where `1` is maximum badness. The weighted sum is the composite; the `coding` weights are shown below (other profiles redistribute them).

<AccordionGroup>
  <Accordion title="claim_contradiction — self-contradictory conclusions (weight: 0.30)">
    Examines what the agent has *concluded*, not what it called, and flags when its stated claims contradict each other or earlier findings. It carries the highest weight because it's the only detector that looks at the agent's reasoning output rather than its tool-call pattern.
  </Accordion>

  <Accordion title="semantic_loop — reworded repetition (weight: 0.25)">
    Detects the same action or search repeated with reworded inputs. It is embedding-based, so it recognizes that "session timeout", "session expiry", and "session token expiration" are the same loop — something edit-distance similarity would miss.
  </Accordion>

  <Accordion title="verification_skip — concluding without checking (weight: 0.15)">
    Fires when the agent reaches a conclusion without verifying its work — no test run, no re-read of the file it changed, no confirmation step before declaring done.
  </Accordion>

  <Accordion title="cyclic_compression — context churn (weight: 0.10)">
    Detects repeated re-summarization cycles: the agent compresses its context, re-derives the same state, and churns without making forward progress.
  </Accordion>

  <Accordion title="late_sprawl — late scope creep (weight: 0.10)">
    Fires when a run that should be converging instead sprawls — new tools and tangents introduced deep into the trajectory.
  </Accordion>

  <Accordion title="silent_topic_drift — quiet off-task drift (weight: 0.10)">
    Detects the agent quietly drifting away from the original task without acknowledging the change of direction.
  </Accordion>
</AccordionGroup>

## How monitor results gate E1 retrieval

The middleware consumes the server-side evaluation to gate E1 retrieval, so vector search stays off healthy steps. A two-step lookback keeps the gate open across consecutive at-risk steps.

```text theme={null}
allow E1 if:
  any monitor fired this step
  OR composite this step > 0.15
  OR any monitor fired on the previous 2 steps
```

If `MonitorSteeringInjection` is not configured at all, E1 is allowed unconditionally for backward compatibility.

<Tip>
  Inspect what fired on each step via `mw.step_log[i].monitors_fired` and the composite via the live telemetry. E1 stays quiet when the run looks healthy, so an empty `monitors_fired` over the trailing window is expected on a clean run.
</Tip>
