The Python SDK gives you the same control as the TypeScript SDK from Python code: start Threads, run Turns, stream events, and resume Sessions.Every Turn runs one local Import the package as
A Thread runs one Turn at a time. A concurrent call raises A Session belongs to the workspace it was created in, so pass the same Events are the CLI’s stream-json events as plain dicts, passed through unchanged, unknown types included: The SDK never retries automatically. When an error carries
mcode exec --output-format=stream-json process and continues the Session with --session. The package is 0.x, so APIs may change between minor versions until 1.0.Related pages: TypeScript SDK, Headless and CI. Package: PyPI minimax-code-sdk.Requirements
The SDK does not install the CLI. Install it separately and sign in, or configure a working API-key provider in the data directory, before the first run.
Installation
minimax_code.Quick start
run() returns a Turn only when the status is succeeded. It carries final_response, normalized items, usage, model, session_id, turn_id, duration_ms, and the full CLI result. Every other outcome raises.Blocking API
If your code is not async, useSyncMCode. It has the same methods without await:SyncMCode runs its own event loop, so it cannot be used where a loop is already running, such as a Jupyter notebook or inside an async def function. There, running a Turn raises a single RuntimeError that points you to the async API. Use MCode with await instead.CLI resolution
Lookup order:MCodeOptions(bin=...);- The
MCODE_BINenvironment variable; mcodeonPATH.
MCodeNotFoundError. Before the first run, each client runs mcode --version once; a CLI older than 0.6.3 raises MCodeVersionError.On Windows, the mcode.cmd launcher written by the official installer or by npm / pnpm is followed to the JS entry and Node runtime it runs. An unrecognized .cmd file is rejected; pass the JS entry as bin instead.Options
Options are dataclasses passed to the client, the Thread, and each Turn.MCode(MCodeOptions(...))
To add variables instead of replacing the environment, merge
os.environ:start_thread / resume_thread(ThreadOptions(...))
Invalid values raise
MCodeInvocationError before the CLI starts. mode="lightweight" on resume_thread is rejected the same way. There is no ask permission: each Turn is a separate process, so interactive permission prompts are not supported.thread.run / thread.run_streamed(prompt, RunOptions(...))
ThreadBusyError; Turns are not queued.Threads and resume
thread.id is the Session id. It becomes available once the first Turn emits its first event. Persist it and continue later with resume_thread:cwd to resume_thread(). When cwd is omitted, the current working directory at that call is used. A Thread pins its cwd when it is created, so a later os.chdir() does not affect it. Resuming from a different workspace fails with MCodeRunError, and retrying does not help.Streaming
run_streamed() returns a StreamedTurn that you iterate with async for. Text deltas for an agent_message can arrive on item.started as well as item.updated, so read contentDelta from any event that carries an item:exec.started, session.started / session.resumed, turn.started, item.started / item.updated / item.completed, turn.completed, turn.failed, and exec.completed. The one exception: an item.updated snapshot (no contentDelta) identical to the previous snapshot of the same item is skipped. Text deltas are never skipped.turn.failed is an ordinary event. Iteration raises only for process or protocol failures.Turn.items are normalized dataclasses: AgentMessageItem, ReasoningItem, and ToolCallItem. Items that had no item.completed when the Turn ended have incomplete=True.Errors
Every error subclassesMCodeError, which carries exit_code, stderr (the CLI stderr tail, for diagnostics only), session_id, result, and items.MCodeRunError.status is failed, timeout, or limit_exceeded. category is config, runtime, internal, or None. MCODE_EXEC_EXIT_CODES maps the CLI exit codes by name.session_id, you can continue with resume_thread(error.session_id, ...). Errors can be pickled, for example to return them from a ProcessPoolExecutor worker.Cancellation and timeouts
streamed.cancel()sendsSIGTERM, the CLI’s cancel signal. The stream then ends with the CLI’s final events;- Leaving the
async forearly (breakor an exception), or cancelling the task runningthread.run(), stops the CLI:SIGTERM, thenSIGKILLif it is still running after the CLI’s 60-second shutdown budget. The next Turn on the same Thread waits for that shutdown instead of raisingThreadBusyError; async with streamed:orawait streamed.aclose()stops the CLI deterministically;timeout_msis enforced by the CLI. If the CLI is still running 90 seconds aftertimeout_ms, the SDK kills it and raisesMCodeRunErrorwithstatus="timeout";- On Windows, cancellation stops the CLI immediately.
Not available yet
- Interactive permission prompts (
permission="ask") and custom in-process tools; output_schema(structured-output constraints), approval callbacks, steering a running Turn, and forking.