
GitHub repository: github.com/MiniMax-AI/minimax-code



1. What happens when a task enters MiniMax Code
Suppose we give MiniMax Code a task: fix an edge case in a function, check its callers, then run the tests. The model might search the code first, read a few files, propose a change, and finally decide whether to keep going based on the test results. A single user request goes through many rounds of model inference and tool execution. MiniMax Code has three entry points: interactivemcode, script-friendly mcode exec, and mcode acp for compatible clients. All three go through CliService and the local applications to reach the same in-process runtime. When the CLI starts, createEmbeddedRuntimeHost() creates a local host, waits for it to be ready, and obtains CliService, without going through the Desktop HTTP service. Model requests and some tools still reach remote services.

LocalAgentHost. It prepares the turn’s runtime environment, assembles capabilities through agent-runtime, then hands off to PiTurnRunner, which uses Pi components to drive the model–tool loop. The Session system handles history storage and recovery.
At the start of the loop, the runtime prepares the current model request. If the model proposes a tool call, the runtime checks and executes it, then commits the result to history for later requests. In our example, search results, file contents, and test output gradually enter the context this way. Once the model returns a final answer or execution is interrupted, the Host still has to wrap up history and Turn state.
So one Turn can contain many model requests, and one Session can span many Turns. PiTurnRunner itself is reusable, but every runTurn() creates a fresh Agent, event bridge, event queue, and history cursor. Mutable objects for a turn are created with that turn; anything the next turn needs is kept by the session layer.
The following sections walk this loop: first how input is prepared before each model request, then how the operations the model proposes are executed and recorded, and finally how the same process extends to sub-agents.
2. What the Harness prepares before each model request
To fix the function in our example, the model needs to see the task requirements and what has been found so far, and it needs to know which tools it can use. This input keeps changing as execution proceeds: freshly read files get added, test logs can be long, and plugin configuration may even update mid-task. Two constraints must hold at the same time: the tool descriptions in the input must match the capabilities actually used in this turn, and the whole request must fit in the model’s window. MiniMax Code handles them with capability assembly and context management respectively.Pin the turn’s capabilities first, then build the request
The extension Registry normally moves throughnew → initializing → ready; if initialization fails, it goes to failed. Extensions register capabilities through owner-scoped interfaces, and only within their own initialization window. A registry that hasn’t finished initializing can’t be used as a normally available registry.
On entering assembleTurn(), the Registry synchronously snapshots each extension’s enabled state before the first await. A setEnabled() call made in between only takes effect at the next assembly. Each turn’s hooks create their own closures over that turn’s ctx, so concurrent assemblies can’t leak context into each other.
Plugin capabilities are leased by version. The turn capability lifecycle takes a revisioned capability view for each newly admitted execution, covering plugins, skills, runtime tools, and hooks. There is no await between capturing the view and registering the in-flight execution; both happen in the same synchronous JavaScript critical section. The reference is released when execution ends.
That way, once the model has read one version of a tool’s description, a plugin update can’t silently swap this turn’s capabilities for another version. The new version is used by Turns admitted later. What’s pinned is the capability view; the files and remote services that tools touch can still change.
Tool descriptions take up context too. The MCP disclosure policy first checks the feature flag, the model allowlist, and the effective window, then estimates the size of the configured MCP tools’ descriptions. Once a threshold is reached, candidate tools move into a search index and a deferred-call registry, while the other tools stay directly exposed. The default threshold is 15% of the window; whether it actually kicks in also depends on model gating and configuration overrides.
Deferred disclosure saves the space of a whole batch of tool descriptions, but the model has to take an extra step to discover tools, and whether it finds the right one depends on retrieval quality.
As files and test output pile up, can the next request still go out?
With capabilities ready, the turn’s history still has to be turned into model input. MiniMax Code’s local footprint measurer estimates tokens together with the system prompt and tool definitions, and computes the UTF-8 serialized byte size of the request. The local estimate may differ from the provider’s exact count of the final wire payload. The budget has to leave room for output and for the rest of execution. Let the context window beC, the output cap O, the reserve R, and the safety margin S. The current shared defaults are R = 16,384 and S = 2,048.
When C − O − S ≥ R, the budget uses the full output O; otherwise it uses min(O, R), written O_eff. The input limit is:
L = max(1, min(floor(0.95 × C), C − R, C − O_eff − S))
The automatic compaction threshold sits earlier:
T = min(L, max(1, C − min(2 × R, floor(C / 4))))
For example, with a window of 131,072 and an output cap of 16,384, the defaults give L = 112,640 and T = 98,304. In other words, context handling starts well before the input limit is hit. Changing the model or configuration means recomputing.
If the example task reads in lots of source code and test logs, the ToolResultArchiver assembled by the runtime picks what to archive based on the output watermark, candidate size, recent-turn protection, and expected gain. It first produces a plan that doesn’t mutate state, then actually archives. When a read tool is available, larger older outputs can be replaced with an archive handle, while the original stays on disk for later reads.
Archive candidates have to pass checks: at least one of token count or byte size must go down, tokens must fit within the input budget, and bytes must satisfy their limit. Without an explicit byte cap, the candidate’s serialized size can’t exceed the pre-archive size.
When no archive candidate satisfies the conditions directly, the LLM checkpoint path takes over. The generated checkpoint is validated, history is replaced, and the request is measured again. If it’s still over the limit, POST_ADMISSION_FAILED is returned. So whether compaction succeeded is judged by whether the next request — prompt and tool definitions included — fits the limits.

3. How the Harness executes and records what the model proposes
Now the model has read the code and decides to call a tool to edit a file. Two separate facts need confirming: whether the operation may run right now, and whether its result has made it into the history the next step will use. A tool returning output only answers part of that.Recheck eligibility before a tool starts
The tool control chain first checks for duplicate tool-call IDs in the turn. For delegated calls carrying a hosttool_ref, it also resolves the actual execution target, then passes through safety/plugin pre-checks, tool policy, and extension hooks before the permission decision. Later checks see the real target, so permissions aren’t evaluated only against the wrapper tool.
Suppose a tool is waiting for user approval, but the user cancels the task first. When the approval comes back, the original Turn may already be over even though permission was granted. So after permission passes, the control chain still has to attempt openToolResultTail(), which only succeeds if the matching active Turn is still in the running phase.
The Turn controller checks sessionId, turnId, leaseId, the admission sequence, the execution reason, and the signal identity. A session can run many turns one after another, and callbacks from an old turn must not take over a new one. The lease here rejects stale executions within the current runtime.
Actual filesystem and network access is further constrained by the enabled sandbox backend. V2 currently registers the macOS srt-macos backend by default; isolation on other platforms depends on whether a corresponding backend supports it.
After a tool returns, commit the result to canonical history
Once the file edit succeeds, the model needs to know the result before it can go on to run tests. If the process exits before history is committed, the files on disk may not match the history read back after recovery. That’s why MiniMax Code separates in-flight execution events from canonical history: the former describes what is happening; the latter is the authoritative history used to continue. Canonical history is stored and recovered by the Session system. The Host handles plain appends, replacements, compaction, and reconciliation through a single committed-history writer. History commits happen during execution, and the compaction discussed in the previous section goes through the same commit path. A commit proceeds in this order:- Capture a semantic snapshot and validate the session, turn, and operation identity.
- Perform the durable mutation and read canonical history back within the same session operation lane.
- Validate the read-back result and obtain the committed revision.
- Wait for the required
HistoryCommittedprojection; when compaction is involved, also complete the compaction lifecycle. - Return an acknowledgement to the caller.

sessionId + operationId and then compares semantic fingerprints. Only when both identity and content match is the earlier execution reused; the same identity with different content triggers conflict handling. This replay registry is bounded and process-local, and provides no exactly-once guarantee across processes or external services.
When a tool result carries appended input, taking it and confirming it are also kept apart: the control chain claims it first and acks it only after history is committed. If input is still being consumed when the Turn wraps up, shutdown is deferred. Unconsumed user steers have a path back into the queue, and machine input that has already been delivered can’t simply be dropped during wrap-up.
Canonical history is only acknowledged after the required state projections finish. Usage accounting and diagnostics are best effort: failures are logged but don’t block history acknowledgement. External side effects need separate handling. If a remote write succeeds but the response is lost, you still need an idempotency key or business-level compensation on the target service; local history can’t undo it.
After the tool result is committed, the loop returns to the previous section: prepare a context that includes the new result, then request the model again. The example task keeps editing and running tests this way until it can finish. When the turn exits, the Host confirms the runner’s terminal state, reconciles history, runs the turn_end handlers, and finally commits and confirms the Turn’s terminal state. The Host may still be doing this after the model has stopped generating.
4. How the process extends when a task is split across agents
The same fix can also be split up: the main agent edits the function while a sub-agent checks callers or does extra investigation. The sub-agent has its own session and execution, and the main agent needs to pick up its result at the right moment. Input preparation, tool execution, and history acknowledgement from the earlier sections still have to hold within each execution. MiniMax Code records an independent task ID, owning session, parent task, status, and output reference for each background task. Statuses are queued, running, stopping, succeeded, failed, canceled, and lost, and the TUI shows delegated agents according to the parent–child session relationship. What collaboration adds is this question: after a sub-task finishes, when does the main task count as having used its result? Completion, notification delivery, and reading the result can happen at different times, and the main task can fail after reading the result.deliveredAt records delivery state; an automatic completion notification does not mark the result as consumed. The current Host records a consumption candidate only after it successfully reads a terminal task’s output; reading a running task’s progress doesn’t suppress the later completion notification. Only when the main task’s turn ends as completed and its terminal state is committed does the Host confirm the candidate as consumed.
For example, a sub-agent finishes investigating callers, the main agent reads the result with task_output, then fails later in the turn. If the result were permanently marked consumed the moment it was read, the next continuation might never get reminded again. Deferring confirmation until the Turn commits ties that read to whether the main task actually completed.
This follows the commit order from the previous section and keeps the same possible failure between steps: the Turn has been committed, and only then can the consumption confirmation or later settlement fail. In that case diagnostics are recorded, and the committed Turn isn’t retroactively marked failed; these steps don’t form one atomic transaction across all components.
After a runtime restart, tasks are also checked for a live executor. Tasks without a valid executor are settled as lost instead of showing running forever. The main task can continue from the recovered session history, but sub-task processes that have disappeared need to be handled separately.