Code Mode: MCP & OpenAPI
Why Qosm compiles tool calls into verified code instead of dispatching them at runtime.
Most agent frameworks work in what you could call tool mode: the LLM decides at runtime which tools to call, with what arguments, in what order. The framework dispatches the calls and feeds results back to the LLM.
Qosm works differently. It uses code mode: the LLM writes a program ahead of time, the compiler verifies it, and then it runs without the LLM in the loop.
Tool mode vs code mode
In tool mode (LangChain, CrewAI, etc.):
- The LLM reasons about which tool to call on every step
- Tool calls are opaque function calls dispatched at runtime
- Errors are discovered when they happen — wrong argument types, missing fields, invalid combinations
- The LLM is in the hot path for every decision
In code mode (Qosm):
- The LLM writes a complete program using available tools as typed functions
- The compiler checks every tool call — argument types, return types, effect tracking — before execution
- Errors are caught at compile time, not runtime
- Once verified, the code runs without the LLM (unless the code itself makes LLM calls as a capability)
The result: code-mode agents are cheaper (the LLM writes once, the code runs many times), more reliable (the compiler catches errors the LLM would miss), and auditable (you can read the code and know exactly what it does).
MCP tools become typed functions
When you connect an MCP server in the workspace, Qosm discovers its tools via tools/list and converts each one into a typed extern:
// The MCP server "github" has a tool "create_issue"
// Qosm auto-generates:
effect Github.CreateIssue;
extern github_create_issue :
{owner: String, repo: String, title: String, body?: String}
-> Result<{number: Int, url: String}, QosmError> ! {Github.CreateIssue};
Notice:
- The JSON Schema input becomes a Qosm record type
- Optional fields (not in
required) becomefield?: Type - The tool gets its own effect label
- It returns
Resultlike every capability
Your LLM writes code that calls github_create_issue as a regular function. The compiler verifies the argument types match. At runtime, Qosm serializes the record to JSON and calls the MCP tool.
OpenAPI endpoints become typed functions
Same idea, different source. Import an OpenAPI spec and every endpoint becomes a typed extern:
// GET /repos/{owner}/{repo}/issues becomes:
extern api_get_issues :
{path: {owner: String, repo: String}, query: {state?: String, per_page?: Int}}
-> Result<Array<{number: Int, title: String, state: String}>, QosmError>
! {Api.GetIssues};
Parameters are grouped by location (path, query, header, body) so serialization is unambiguous. The compiler knows the types. The runtime handles the HTTP details.
Why this matters
With tool mode, you're trusting the LLM to get the tool calls right every time at runtime. With code mode, you're trusting the compiler — and the LLM only has to get it right once, during development, with the compiler giving it feedback.
This is especially important for complex workflows. A self-healing agent that monitors a service, diagnoses errors, and pushes fixes involves multiple tools, conditional logic, and error handling. In tool mode, any step can fail in surprising ways. In code mode, the compiler verifies the entire pipeline before it runs.
We'll build exactly this agent in the tutorial.
But first: attenuations — how to narrow capabilities so agents get the minimum access they need.