Skip to main content
Core Concepts

How it works

All three SDKs run the Agent in a local qodercli process. The SDK exchanges JSONL messages and control requests with qodercli; qodercli calls the model service and executes approved tools.

Architecture

+------------------------- Application -----------------------------+
|  TypeScript query()                  Python query() / SDK client   |
|  Java QoderClient.query() / openSession()                          |
|              message parsing, callbacks, session controls         |
+-------------------------------+-----------------------------------+
                                |
                   local JSONL over stdin/stdout
                                |
+-------------------------------v-----------------------------------+
|                         qodercli SDK mode                          |
|  protocol + session  ->  agent loop  ->  permission + tool runner |
+--------------------------+----------------------+------------------+
                           |                      |
                    model requests          local execution
                           |              files / commands / MCP
                           v                      |
                  Qoder model service             |
                           |                      |
                           +------ results -------+
One local runtime session is owned by one qodercli process. A string-based query() normally closes that session after the final result. Multi-turn APIs keep it alive while the application sends more input.

Startup and handshake

The default local session starts in this order:
  1. Select the runtime. The SDK uses an explicitly configured qodercli path when provided; otherwise it finds the compatible runtime shipped with the package or available in the environment. The Java SDK does not bundle a runtime; it downloads and caches a pinned version instead. See Managed CLI (Java).
  2. Start SDK mode. The SDK launches qodercli with structured streaming input and output enabled. The process inherits the configured working directory and environment.
  3. Transfer authentication. The SDK resolves the selected authentication method and provides qodercli with a temporary, one-time authentication payload instead of writing the credential into the message stream.
  4. Initialize capabilities. Before sending the first task, the SDK and qodercli exchange an initialize control request. This registers SDK-provided hooks, agents, skills, and in-process MCP servers, then returns the runtime capabilities and available resources.
  5. Send the task. After initialization succeeds, the SDK sends the first user message and begins yielding qodercli messages to the application.
Initialization failures are reported before the task runs, which helps distinguish configuration or authentication problems from an Agent failure.

Managed CLI (Java)

Each Java SDK release pins one qodercli version. When no CLI path is specified, the first start downloads that version's archive, verifies its byte size and SHA-256, and installs it under ~/.qoder/runtimes/managed. Later starts reuse the cache. The SDK does not look up the latest version and never upgrades automatically. Managed platforms are macOS arm64/x64, Linux x64/arm64 (glibc and musl), and Windows x64. Other platforms, including Windows arm64, are not managed. Windows x64 requires Windows 10 1809 / Windows Server 2019 or later. The SDK does not check the OS version, so on older systems specify the CLI with qoderCliPath or QODERCLI_PATH. At startup the SDK picks the CLI in this order and stops at the first match:
  1. The path set with SessionOptions.Builder.qoderCliPath(Path). An invalid path fails immediately.
  2. The QODERCLI_PATH environment variable.
  3. The managed CLI: reuse the cache, otherwise install it. An install failure raises RuntimeInstallException; the SDK does not fall back to another CLI. This step is skipped when the current platform is not managed.
  4. A same-version CLI left under ~/.qoder/runtimes/ by an older SDK.
  5. ~/.local/bin/qodercli, then PATH.
If the runtime environment has no network access, prewarm the cache at deployment time, for example while building the image:
java -cp qoder-agent-sdk-VERSION.jar com.qoder.sdk.RuntimeInstaller
Replace VERSION with the SDK version your application depends on, and use the actual path to that JAR. Each SDK version pins its own CLI version, so prewarming with a different JAR may cache a CLI your application does not use. You can also ship the pinned archive with the application, use an enterprise mirror, or call QoderClient.installRuntime() to surface install problems early. For all settings, see ManagedRuntimeOptions.

SDK and qodercli communication

For the default process transport, each protocol message is one JSON object on one line. The SDK reads and writes this JSON Lines (JSONL) stream; applications should use the typed SDK messages rather than parse process output directly.
Application
    |
    | SDK writes to qodercli stdin
    |   user messages
    |   control requests and matching control responses
    v
 qodercli
    |
    | qodercli writes to stdout
    |   system, assistant, task, hook, and result messages
    |   partial stream events when enabled
    |   control requests and matching control responses
    v
 SDK message iterator

 qodercli stderr --------------------> diagnostics (not protocol data)
There are two logical traffic types:
  • Agent messages carry user input, assistant content, tool activity, progress, and the final result.
  • Control messages perform initialization, interruption, session operations, permission decisions, hooks, and in-process MCP calls. A request_id pairs each control response with its request, so several operations can be in flight without confusing their results.
Either side can initiate a control request. The SDK can ask qodercli to interrupt the current turn; qodercli can ask the application to approve a tool or execute an SDK-hosted hook. The SDK routes inbound requests to the configured callback and returns the callback result to qodercli.

The qodercli agent loop

qodercli repeatedly calls the model until the task finishes or reaches a configured limit. Tool results from one iteration become context for the next:
user task + conversation history + instructions + tool definitions
                              |
                              v
                 build the next model request
                              |
                              v
                     stream model output
                              |
                 +------------+-------------+
                 |                          |
             text/content                 tool call
                 |                          |
        emit assistant events      check policy and hooks
                                            |
                                      execute the tool
                                            |
                                 append the tool result to history
                                            |
                                            +------> next loop

                  no more tool calls
                              |
                     run completion hooks
                              |
                     emit final result
  1. Build context. qodercli combines the task, conversation history, system instructions, workspace configuration, available tools, and relevant hook context.
  2. Ask the model. Model output is streamed. Text can be surfaced immediately, while complete tool requests are sent to the execution pipeline.
  3. Authorize the action. qodercli applies tool availability, allow/ask/deny rules, permission callbacks, and pre-tool hooks. A denied tool produces a tool result explaining the denial; it is not executed.
  4. Execute tools. The runtime dispatches approved built-in tools, MCP tools, or subagents and captures their results. Independent tool calls can run concurrently when it is safe to do so.
  5. Continue with evidence. Tool results are appended to the conversation, and the model receives another turn to inspect the outcome and choose the next action.
  6. Finish or stop. The loop ends when the model has no more tool calls, a completion hook accepts the result, or a configured limit, interruption, cancellation, or error stops the task.
The model never opens a file or starts a process by itself. It proposes a tool call; qodercli is the component that decides whether and how to execute it.

Tools, MCP, and subagents

qodercli presents the model with only the tools available to the session:
  • Built-in tools read and edit files, search the project, run commands, and perform other local operations.
  • MCP tools can come from an external MCP server or from an in-process server hosted by the SDK application. For an in-process server, qodercli sends an MCP control request to the SDK, the SDK calls the registered server, and the response returns over the same control channel.
  • Subagents run a delegated task with their own prompt and context, usually with a narrower tool set. Their final output returns to the parent Agent as a tool result.
Tool results become model context and SDK events. Large results may be shortened in the conversation while the runtime preserves enough information for the Agent to continue safely.

Context and session state

qodercli owns the live conversation state. The SDK owns the application callbacks and converts protocol objects into TypeScript, Python, or Java message types. As a session grows, qodercli monitors its model context usage. When needed, it compacts older history into a smaller representation before the next model request. This keeps a long task moving without requiring the application to rebuild the prompt, although important details should still be stored in files or explicit session state instead of relying on unlimited conversation memory. When session persistence is enabled, qodercli can store a transcript and resume it later. Resume and checkpoint behavior is described in Session Storage and Checkpoint.

Completion, errors, and cancellation

Applications should keep consuming messages until they receive a result or the iterator raises an error.
  • A successful or failed Agent turn is summarized by the final result message, including status and available usage information.
  • interrupt asks qodercli to stop the active turn while keeping a long-lived session available where supported.
  • Closing or aborting the SDK stream closes the transport. The process transport first attempts a graceful shutdown and escalates if qodercli does not exit.
  • A process start failure, invalid protocol message, lost runtime, or initialization timeout is surfaced as an SDK error rather than an Agent result.
See Session Control for the public control APIs and Cost and Usage for usage fields.

Security and data flow

The local process boundary does not mean the entire task stays on the local machine.
local application <---- local protocol ----> qodercli
                                               |
                                               +----> Qoder model service
                                               |      task context and results
                                               |
                                               +----> local or configured tools
                                                      possible side effects
  • Authentication is passed to qodercli separately from the JSONL message stream through a temporary payload that the SDK cleans up.
  • qodercli sends the model service the task context needed for inference, which can include prompt content, file excerpts, and tool results.
  • Tools execute in the qodercli environment and may read, write, or call other systems according to their configuration.
  • cwd, tool allowlists, permission rules, hooks, sandboxing, and infrastructure isolation are complementary controls. Configure them according to the consequences of the task.
For approval patterns and permission modes, see Permissions. For intercepting lifecycle events, see Hooks.

TypeScript, Python, and Java session shape

The runtime protocol is shared by all three SDKs, but each exposes a language-appropriate session API:
ScenarioTypeScriptPythonJava
One prompt, one resultquery({ prompt: string, ... })query(prompt=..., options=...)client.query(OneShotQueryRequest.of(prompt))
Multiple user messagesPass an async message iterable to query()Connect a QoderSDKClient and call query() againclient.openSession(options), then call send() repeatedly
Read outputfor await over discriminated message unionsasync for over typed message objectsPull with MessageCursor or push with consume(); check message types with instanceof
Runtime controlsMethods on the returned query streamMethods on QoderSDKClientMethods on QoderQuery / QoderSession

Next steps