Supervisor

The supervisor checks progress and completion, manages plans, and narrows large tool results around your session. Use

The supervisor checks progress and completion, manages plans, and narrows large tool results around your session. Use this guide to configure it and understand its notices, retries, and verification limits.

Get started

The shipped configuration enables the supervisor. Start a session and inspect its plan and local statistics:

bash
octomind run developer:general
text
Inspect the API routing and explain which files own authentication. Do not edit files or run tests.
/plan
/info

/plan displays the supervisor-owned plan and retained critical knowledge; routine work may have no plan. /info includes supervisor activity and model usage. You do not type the hidden status protocol yourself.

Configuration

Edit these sections in your existing configuration. The shipped values below enable supervision; model-profile fields are optional overrides. Required mechanic tables must remain present even when disabled. Detectors and recitation run when the supervisor is enabled; completion pre-gates also require the gate to be enabled.

toml
[supervisor]
enabled = true

[supervisor.model]          # optional; omitted fields inherit [model]
name = "octohub:auto"
reasoning_effort = "medium"
max_tokens = 8192
temperature = 0.0
top_p = 1.0
top_k = 0
max_retries = 1
retry_timeout = 30
request_timeout_seconds = 300

[supervisor.learning]      # see 13-learning.md
enabled = true

[supervisor.learning.evolution]
enabled = false

[supervisor.gate]          # verify on self-reported `done`
enabled = true

[supervisor.authorizer]    # user-intent check before tool execution
enabled = false

[supervisor.evaluate]      # calibrated evaluation gates, see below
model = "cloudflare:typesafe/jev"
recall = false
skills = false
authorizer = false

[supervisor.plan]          # adaptive external plan manager
enabled = true

[supervisor.condense]      # task-aware narrowing of oversized tool outputs
enabled = true
adaptive = false
tokens_threshold = 5000

Authorizer, gate, resolve, plan, condense, and every learning operation use the single supervisor profile. Omitting [supervisor.model] uses [model] unchanged.

[supervisor.condense].adaptive defaults to false. When enabled, the process-local runtime multiplier learns from realized savings while remaining between 0.5x and 2.0x of tokens_threshold; the configured value remains the baseline.

To enable the adaptive condenser, edit its existing section:

toml
[supervisor.condense]
enabled = true
adaptive = true
tokens_threshold = 5000

Every field is documented in [supervisor] — Config Reference.

Tool authorization

Enable [supervisor.authorizer] enabled = true to check proposed tool operations against role + user intent. The rule is allow-first: if uncertain, allow. Reasonable investigation and intermediate steps are permitted. Only a concrete prohibition or scope conflict can block a call. The shared supervisor receives separately labelled role and user sources, exact tool arguments, and runtime receipts of completed actions. Role text cannot masquerade as a user quote; injected memory and tool output cannot manufacture permission. Original user text survives pre-model pipes.

Native pre-call guards run first. The authorizer checks the remaining batch before execution, including inline capability activation and delegated tool loops. An ordinary allow needs one judge call. For a proposed block, the model selects a source ID and argument path; the runtime copies the exact source text and argument value. The proposed conflict must then pass a second independent check using the shared supervisor model. A native guard override is also verified. An unconfirmed or malformed opinion contributes no veto. A confirmed block returns a normal tool error with its original call ID:

text
[authorizer] Tool not executed: Tests conflict with the user's restriction. user source user:0: "Do not run tests".

Blocked calls never enter the guard history or run post-result hooks. Guard history is committed in call order after authorization; an earlier denied call cannot satisfy a later call's prerequisite. History records admission, not proof that an admitted parallel call succeeded.

Only independently confirmed denials are reused for identical calls under unchanged user, role, memory, tool-definition, and completed-action context. Uncertainty and missing prerequisites are never cached as prohibitions. Allow decisions are not cached. Completed actions have explicit success flags and retain argument/workdir identity separately from untrusted output text; a successful read in an earlier round satisfies reading first. Missing history is unknown, not proof of nonexecution. User instructions, the last 16 completed actions, and authorizer counters survive compaction and session resume; the bounded denial cache is process-local. /info shows this session's checked, blocked, cached, and unavailable counts. These counters and instruction text are not added to anonymous telemetry. Shared supervisor model-call totals retain their existing process-global accounting behavior.

With learning and evolution enabled, denial observations become candidate leads for the existing verifier and native guard lifecycle. A denial is never evidence that its own rule is correct. Permanent rules need independently grounded user evidence, expressible scope, replay cases, shadow matching, and bounded trials. Task-local or conditional restrictions must not become unconditional permanent guards. A matching generated guard can be superseded for a call by an explicit current-user correction; user-authored project guards remain authoritative.

Octomind ACP children receive an immutable snapshot of ancestor constraints and completed actions. Child prompts cannot revoke ancestor constraints. Peers without this extension still run after parent admission, but cannot promise child-level authorization. In-process dynamic agents receive separate scoped contexts with the same parent boundary.

Unavailable, malformed, over-budget, or timed-out judgments allow calls; failure of the judge is not evidence against the tool. The full judgment has a 30-second deadline and a 32,000-token request budget. Unsupported blocks are allowed without becoming learned rules. User cancellation still stops execution at the tool loop, independently of authorization. Explicit native guards and sandbox protections retain their existing behavior. This is a model-based intent check, not a guarantee of zero false positives or protection against arbitrary code behavior. Configured pipes and hook scripts execute at their existing lifecycle points outside this tool-call check.

Evaluation gates

[supervisor.evaluate] adds a calibrated evaluation model (TypeSafe Jev, reached through octolib's evaluation module) as a gate at eight seams. Unlike the chat model, it takes one state and a set of typed questions and returns a probability per question; there is no generated text to parse. Each seam is one boolean, off by default, and switching every seam off leaves behavior byte-identical to a release without this section.

KeyMeaning
modelprovider:model string. Supported providers: cloudflare (cloudflare:typesafe/jev, AI Gateway unified billing), typesafe (typesafe:jev-latest, direct) and octohub (octohub:<alias> or octohub:auto — the hub picks the model; OCTOHUB_API_KEY, optional OCTOHUB_API_URL). A malformed or unsupported value fails config loading naming supervisor.evaluate.model. There is no profile: Jev accepts no sampling parameters.
recallAfter scoped lessons are ranked and before pack admission, one Noul per scoped candidate asks whether it bears on the current request. Candidates below 0.5 are excluded; the rank order of the rest is kept. Global-tier rules are never sent and are admitted exactly as before. Zero scoped candidates make no call.
skillsWhen auto-activation runs and every rule abstained (no deterministic match, no semantic candidate cleared the margin), one Choice lists every inactive skill in the domain pool (name and description) plus none. The chosen skill activates with trigger evaluate when it is not none and its probability in the answer's distribution is at least 0.8. Skills without rules join the pool for this choice only; they never meet the rule engine. A shadow evolution binding records a match instead of activating.
authorizerWith [supervisor.authorizer] enabled = true, after the memoized-denial cache and before the two-judge supervisor path, three Nouls per pending call ask whether it is prohibited by user or role instructions, destructive to non-regenerable files or git history, or external to the working directory. When every answer is below 0.5 the batch is admitted without waking the supervisor model; otherwise the pre-change judgment and verification run unchanged. The pre-screen can only admit, never block.
condenseWith [supervisor.condense] enabled = true, the same candidates the condenser would judge (tokens_threshold and adaptive unchanged) are scored instead of sent to the supervisor model: each candidate's full original text is split into line-aligned chunks of at most 256 tokens, windowed under the state cap (at most 96 chunks per call, at most four windows in flight at once; a chunk that is one oversized line goes in as a 512-token head-and-tail sample), and one Noul per chunk asks whether the agent needs it for the task. Chunks at or above 0.5 are kept with one neighbour on each side, plus diagnostics and any truncation notice; the kept lines go through the existing verbatim reconstruction, spill file, and 📎 CONDENSED notice. Everything kept leaves the result untouched; nothing kept omits an ok result (never an error). If any window is unavailable, the whole round's answers are discarded and the supervisor-model condenser runs once exactly as before. The adaptive controller sees the same numbers either way.
compressionBefore a fold's decision call, every ToolInteraction packet the PACT allocator placed in the summarize lane is scored with one Noul (state: pinned task, constraints, plan focus, and a 512-token head-and-tail sample per packet; at most 96 units per call, at most four windows in flight at once). Packets below 0.5 are demoted to archive_reference, so the fold model reads their one-line descriptor instead of their content; keep_exact, non-tool, real-user, and already-archived packets are never scored, and a packet another selected packet depends on is never demoted. The drained range, archive, fingerprint, validator, and fold decision are untouched. If any window is unavailable, nothing is demoted and the fold proceeds on the evidence set as allocated.
distillAt lesson extraction (/done, exit, compaction), the candidate lessons are grounded by one Noul each (state: every candidate's number, rule, and cited quote, plus the same transcript excerpt the chat verifier receives: the first 12,000 characters, then the full user turn each quote was found in when that head does not already contain the quote) instead of the batched supervisor-model verifier. Candidates at or above 0.5 are kept; the rest are rejected with the same debug line as before. Dedup, supersede, importance, storage, experiences, and orientation are untouched. If the evaluation is unavailable, the supervisor-model verifier runs once for the same candidates, fail-closed as before.
planWith [supervisor.plan] enabled = true, after every deterministic skip and before the planner call, a request signal is scored with one Noul asking whether the remaining work needs an external plan (state: current and working request, outcome conditions, runtime evidence, phase trajectory), and a phase_complete signal with one Noul asking whether the runtime evidence shows the active phase's done_when (state: phase title and done_when, evidence since the phase checkpoint, phase trajectory). Below 0.2 the request is declined and the phase_complete is held with the feedback runtime evidence does not yet show: <done_when>, without a planner call; otherwise the planner runs unchanged. reassess is never scored. The pre-screen can only skip a call, never create, advance, or revise; an unavailable evaluation runs the planner and never sets the per-turn failure latch.
gateWhen the verifier rules GAPS, each charged finding is scored with one Noul over the same rendered evidence the verifier saw (after any readback round). Findings at or above 0.8 are refuted and reported as refuted by second verifier: …; the rest stand, and when every finding is refuted the verdict is PASS, exactly as after the chat refutation. The verifier pass, readback round, and format retry are untouched. If the evaluation is unavailable or the evidence exceeds the state cap, the supervisor-model refutation runs as before.

Keys come from the environment, as for every other provider: CLOUDFLARE_API_KEY and CLOUDFLARE_ACCOUNT_ID for the cloudflare provider, TYPESAFE_API_KEY for typesafe. Nothing is stored in config.

Every call is one attempt with a 5-second timeout and no retries, and the assembled state is capped at 24,000 estimated tokens. Any failure — missing key, HTTP 401/402/403/429/5xx, timeout, transport error, an unparseable or incomplete answer set, a state or skill roster too large to send — keeps the pre-change behavior for that turn, writes one debug line (evaluate <seam> unavailable: <reason>) and increments the seam's unavailable counter. For the recall, skills, and authorizer seams the state never contains tool results, assistant messages, or condensed-output notices; the condense and compression seams judge tool output by design and send that output and nothing else from the transcript. The distill, plan, and gate seams receive exactly the payload the chat call they replace receives, and their answers can only reject a lesson, skip a planner call, or drop a finding — never store, create, advance, or pass. Thresholds and question text are constants in src/supervisor/evaluate.rs, not config keys.

/info shows, per seam, calls (attempts), unavailable (fallbacks), and applied (recall: candidates excluded; skills: activations; authorizer: batches admitted without the supervisor; condense: results whose inline content changed; compression: packets demoted; distill: verification rounds answered; plan: planner calls skipped; gate: refutation passes answered), plus replaced where the seam stood in for a chat call (authorizer, condense, distill, plan, gate). The evaluate row totals the seam calls with their input tokens and cost against the chat calls replaced, with the estimated input tokens those calls would have carried, priced at the supervisor model's reference input rate when the table knows it. Output tokens and wall time are not counted, so the saving shown is a floor. Usage lands under one evaluate call kind in the supervisor totals and in the session's external spend.

The closed loop

text
each assistant/tool round, no extra model call for detection:
  self-report  ⊕  detectors (counters)      <- status tokens plus deterministic counters
        │  agree → act with no model
        │  completion claim → ↓
  verify-gate (model, rare)  → labels the run pass/fail
        │
  distill (`/done`, exit, compaction) → grounded records with outcome labels
        │
  recall (next turn/session)  → build the bounded Active Memory Pack
        │
  steer  → advisory re-anchor when the agent loops or stalls

The verify-gate supplies outcome credit, but extraction is not limited to passed runs: quote-backed user rules may be retained independently, and experience records preserve verified, failed, or unknown rather than upgrading uncertain work. Supervisor context is explicit and mid-trajectory steering remains advisory.

Self-report

When supervision is enabled, the agent is instructed to end each response with a compact structured handoff:

text
<sup>{"state":"progressing","focus":"inspect authentication routing","next":"read the route handlers","carry":[],"plan":null,"memories":[],"behaviors":[]}</sup>

state is one of exploring, progressing, blocked, need_input, done. The token is parsed by the supervisor and stripped before display — you never see it. focus, next, and carry form a low-cost handoff to conversation compression. The compressor treats it as an attention hint, grounds it against the transcript, and may promote supported durable protocol into critical knowledge. It is never evidence by itself, and credential values are forbidden; only opaque credential pointers may be carried. Legacy one-word and STATE · reason reports remain accepted when resuming older sessions.

StateEffect
doneArms the verify-gate
need_inputTreated as a question — passed to you, never gated (no false-positive verification)
blockedLegitimate handback; detector hints do not interrupt it
exploring / progressingFused with the counters below

Detectors

Detectors run in-process after tool rounds without another model call. Their thresholds are fixed constants. The status report and injected notes still use tokens in normal agent requests.

The first two track receipt novelty: tool name, arguments, result, and error status. Different targets returning the same output are distinct observations. A fresh error can provide diagnostic information, and a successful mutation counts as progress even when its receipt repeats.

  • Loop — identical calls and results repeat for 3 tool rounds without current-round novelty.
  • No-progress — 5 tool rounds without new receipts or successful mutations.
  • Recovery — several command executions returned errors without a later success for those exact calls. The detector does not establish whether they were tests, expected probes, or obsolete attempts.

All three signals are advisory. Repetition can be legitimate polling, and an error need not require recovery. Hints never escalate into mandatory strategy changes or blocked handbacks; repeated hints back off. done, blocked, and need_input are left alone, and no-progress hints are also suppressed while exploring. The main model judges relevance from the actual outputs and user request; a counter does not establish non-compliance.

Verify-gate

For an eligible user-task completion with supervision and the gate enabled, the claim is checked before completion is accepted by an independent model verification pass.

Free pre-check (no model call):

  • Unfinished handback — non-interactive/background execution can nudge an exploring or progressing response that ends without action, within a fixed retry budget.

Mutation and verification detectors supply heuristic context to the model pass; they cannot reject completion by themselves. A saved artifact can fulfill an artifact request without a separate check. A command can both change state and exercise behavior, so its output remains available as evidence. The verifier judges the requested outcome against the resulting artifacts and recorded outputs, and must identify a concrete gap before requesting more work.

The gate also catches a missing self-report after mutations; need_input and blocked remain legitimate handbacks. Pending session-owned background work defers completion. User and standing-instruction prohibitions on verification remain binding: a forbidden check's absence is compliance, not a gap.

For example, a standing verification prohibition persists until you explicitly change it:

text
Make the requested documentation edits. Do not run tests; I will test myself.
Now you may run the relevant tests for those edits.

Plan outcomes are judged against evidence, not whether every status box is already checked. A PASS can close all remaining bookkeeping items for the applicable plan. With the completion gate disabled, an eligible completion self-report can finalize it instead.

Machine-checkable plan assumptions (for example file_exists: src/foo.rs) resolve relative paths from the session anchor. A confirmed broken assumption emits reassess; filesystem observation errors remain unknown. A planner outage preserves plan bookkeeping and allows the authorized task to continue.

Model-selected operational excerpts are matched against the current user's exact text before recitation. Selected excerpts are contextual reminders, not independently binding rules or additional requirements.

Model pass (rare): an independent verifier checks the result against your request:

  • Pass → the trajectory is labelled verified; only materially used memories receive positive outcome credit.
  • Gaps → an advisory listing the gaps is injected and the turn re-runs, bounded by a fixed re-entry budget. Exhaustion ends the turn unverified. Unchanged gaps after new evidence can also stop retries early.
  • Indeterminate → transport failure or invalid verifier protocol fails closed for the turn. A structurally malformed successful response gets one bounded format-only retry; substantive gaps do not.

The verifier can request one bounded read-back of recorded tool evidence. Blocking findings receive a separate refutation pass before causing rework: with [supervisor.evaluate] gate = true the evaluation model answers it per finding, otherwise a second supervisor-model call does. These passes use the shared supervisor profile; a separate call does not guarantee a different model family. Change [supervisor.model] in the configuration example to choose the profile.

Adaptive external planning

Planning is exceptional and supervisor-owned. Focused answers and routine work stay plan-free. For work with meaningful dependent phases, context-loss risk, or a real branch to track, the specialist emits a sparse hidden request signal alongside normal work. A separate supervisor call makes one structured create/no-plan decision from the current request, specialist instructions and capabilities, bounded current-phase assistant/tool trajectory, and runtime evidence. With [supervisor.evaluate] plan = true the evaluation model pre-screens request and phase_complete first and skips the planner call when it is confident no plan is needed or the phase outcome is not yet evidenced.

The specialist has no plan mutation tool. Later phase_complete or reassess signals ride with real work responses; the external manager advances, holds, or revises runtime state. Evidence is checkpointed per phase, and the completion gate owns final plan clearance.

Steer

When a detector fires (loop, recovery, or no-progress that the self-report doesn't excuse), the supervisor queues an advisory re-anchor note — "you've repeated this without new results; try a different approach, or report blocked" — injected at the next request's safe point. It nudges; it never forces. Re-emission follows a parameter-free doubling backoff when the agent repeats the same call-set after a note, so an ignored steer stays cheap without going silent.

Condense

When a plain-text tool result exceeds [supervisor.condense] tokens_threshold (with a 512-token minimum floor), it becomes a condense candidate. Results under the threshold are passed through exactly as returned and are never shown to the condenser. One shared supervisor-model call per round decides, for the candidates only, what the agent actually needs to see for the current task:

  • All relevant → kept in full, byte-for-byte.
  • Partly relevant → only the needed lines. The condenser sees a line-numbered copy and answers with line ranges; the kept lines are reconstructed verbatim from the original — the model never retypes content, so retained text is reconstructed from the source lines.
  • Irrelevant → replaced with a deterministic system notice. The condenser cannot write a factual summary that could hallucinate tool output.

It is recoverable: condensation runs only for plain-text results when the active role has a local file-reading tool, the body being narrowed is spilled to a temporary file first, and every condensed result carries the path so the agent can read any cut span on demand. The hard mcp_response_tokens_threshold prefix-cut is applied before condensation, so the condenser only ever sees — and only ever selects line ranges over — the body the agent would actually have received. Structured/non-text MCP payloads fail open instead of being flattened and corrupted. A failed call or unparseable response leaves the round untouched; unusable individual entries preserve only their own result. This runs in the main-session tool path, not the layer execution path; a child Octomind session has its own loop.

Relevance is conditioned on three separate signals: trusted standing context (system prompt, project instructions, and currently active skills), the live goal/request/plan, and the assistant text explaining why the current tool batch was issued. Tool data is serialized as JSON, treated as untrusted reference data, and cannot create instructions for the condenser.

Numbered views share a nominal 32,000-token round budget, allocated by result size with a 256-token per-result floor; at most 32 candidates enter a request. The floor can push the sum above the nominal view budget. A large result is represented by task/argument matches, diagnostics with context, head and tail lines, and stratified middle samples, all carrying their original line numbers. A partial view can be extracted but never discarded wholesale; selected ranges are clipped to visible spans. Missing, duplicate, unknown, malformed, or unsafe entries leave the affected result unchanged while valid siblings can still be condensed. Error/diagnostic lines are also retained deterministically even if the model overlooks them.

Cross-session memory

Learning stores quote-backed rules, grounded orientation, and longer experience records in the file backend. See Cross-Session Learning for configuration, commands, retrieval budgets, and retention.

Recite

With supervision enabled, the runtime re-injects the current goal and live plan near the request tail. Plans, explicit prohibitions, and verification policy can be recited before the first compaction. An archived goal is recited only when its task signature still matches the live request. No separate model call is needed, but the note consumes context tokens.

Delegation

The MCP tap action run and agent_* tools spawn a context-isolated child. Its prompt must supply the goal, established facts, constraints, and expected deliverable; the parent transcript and prior tool output are not inherited automatically. The child reports its measured completion outcome through ACP metadata; missing, failed, or cancelled handbacks count as unverified.

For a delegation handoff, include the concrete context and deliverable in the prompt:

text
Inspect src/main.rs and src/commands/run.rs. Identify the run flags and stdin behavior. Do not edit files or run
builds. Return each finding with its source path and line number, and state that this was source inspection only.

Invariants

  1. Free signals gate the model. Counters and the self-report run every turn without a separate model call; model calls serve completion, task resolution, planning, or an oversized tool round.
  2. Advisory, never silent rewrite. Every injection is a note the agent can reason about. Steering is advisory; completion verification can leave a turn unverified. No mid-trajectory judge ever blocks a tool call.
  3. Out-of-band. Status tokens are stripped from display; raw status protocol is removed from stored/displayed assistant text; runtime notes and debug diagnostics are separate.

Common questions

Why did completion run again? A missing check or a verifier finding can trigger a bounded retry. Read the supervisor notice for the remaining gap. A failed verifier call is an unverified completion, not proof your work is wrong. Inspect details with:

text
/loglevel debug
/info
/plan
/loglevel info

Why was nothing condensed? Results below the effective threshold, rich MCP payloads, missing spill-reader tools, and selections with no token savings stay unchanged. tokens_threshold = 0 disables condensation.

How do I turn supervision and memory off? Set both switches in the existing config; recall and extraction check supervisor.learning.enabled separately:

toml
[supervisor]
enabled = false

[supervisor.learning]
enabled = false

Supervisor /info counters are process-local and not persisted or anonymous telemetry. Concurrent daemon sessions can mix those counters. In-process supervisor costs feed session spending; detached exit learning runs separately.

Mechanics reference

MechanicWhenCostConfig
Self-reportEach assistant responseOutput tokensNone (automatic)
Detectors (loop / no-progress / recovery)Every turnFreeNone (automatic)
Deterministic completion checksCompletion or unfinished handbackNo separate model call[supervisor.gate]
Verify-gateEligible completion after deterministic checksModel (rare)[supervisor.gate]
CondenseOn oversized tool resultsModel call[supervisor.condense]
SteerOn loop / no-progress / recoveryContext tokensNone (automatic)
ReciteLive goal, plan, constraints, or policy availableContext tokensNone (automatic)
Distill (learn) + grounding verification/done, exit, and eligible compactionModel call[supervisor.learning]
RecallFirst and subsequent genuine requestsFirst-query model prep, retrieval, pack tokens[supervisor.learning]
Evaluation gates (recall / skills / authorizer)Ranked recall, rule abstention, pending tool batchOne bounded evaluation call per seam per turn[supervisor.evaluate]

Source reference

See also