AI AgentAI Coding

The Grok Bot Leak: Why Cursor Only Gives Models Full Definitions for a Subset of Tools

In August 2026, the community reverse-engineered Grok Bot 0.18.0 and made the source code public. Grok Bot is a desktop agent product built by Anysphere, the company behind Cursor. Version 0.18.0 was a compiled app, and the reconstructed source code—clean, readable TypeScript—was published on GitHub. Following the incident, Anysphere took down the 0.18.0 installer, issuing no official statement and no DMCA takedown.

This offers a rare opportunity. When discussing agent harness design, what we usually see are blog posts and design philosophies; this time, we can inspect the actual internal orchestration code of a production-grade harness: how the system prompt is assembled, how tools are exposed to the model, and how context is managed. Moreover, this reconstruction is evidence-based—every recovered line of code has verifiable artifact anchors, and the behavior it describes is what the product actually does.

Reviewing the source code, many of its design principles align with industry best practices. Such alignment could stem from two possibilities: coincidence or imitation. How can we tell? By comparing it with Manus from a year earlier. In July 2025, the Manus team published Context Engineering, detailing how they manage agent context. When two teams design independently and converge on the exact same constraint, that constraint is overwhelmingly likely forced by underlying fundamentals, rather than anyone’s stylistic preference.

This article dissects Grok Bot’s capability layer: what the model can invoke and how to extend it on demand. The next article dissects the context layer: what the model sees and how prompts are managed.

A “Lookup-Before-Invoke” Threshold

Grok Bot has more than 30 tools. Among them, for 9 dynamic tools, the model only sees a single-line hint in each turn; the remaining 18 static tools are provided with their full schemas directly. For instance, with the CloudAgent tool, what the model sees is just one line: “Launch and manage Cursor cloud coding agents for repository work.”. To use it, the model must first invoke GetMcpTools to pull the full schema into context, and then invoke CallMcpTool to execute it. When a schema is too large (exceeding 12KB), instead of stuffing it into context, it is written to a file and only the path is returned to the model—the context capacity aspect of this mechanism will be detailed in the next article.

This adds an extra threshold for Cursor itself. Why not simply give the model the full definitions for all 30+ tools up front?

Let’s start with a secondary reason. Too many tools can distract the model—the more tools available, the easier it is to choose the wrong one. As Manus put it in their article, “your heavily armed agent gets dumber.” However, 30 tools is not a massive number, so the distraction is limited. This is not the primary reason.

The primary reason is the KV cache. Across requests, there is a layer of prefix caching: when the initial sequence of tokens in a request is identical to the previous one, this portion is billed at the cached rate, which is 10x cheaper than the standard rate (for Claude Sonnet, cached input is $0.30 per million tokens, whereas uncached is $3.00). In an agent run, the ratio of input tokens to output tokens is roughly 100:1, meaning the vast majority of the cost lies in input. The invalidation mechanics and exact numbers will be expanded in the next article; this piece only cites the conclusion.

Here, we must distinguish between two ways of placing tool definitions. When using the structured tools parameter, the provider serializes it at the very front of the context—the exact location Manus observed in their blog post. At the API level, you cannot see this serialized result because tools is just an independent parameter, but caching behavior exposes it: modifying tools once invalidates the cache for all subsequent messages as well. Anthropic’s prompt caching documentation explains this invalidation order clearly. When it remains unchanged across turns, the entire prefix (tools, system prompt, and the conversation history up to that point) matches the previous turn and hits the cache entirely—only the newly added turn is billed at the uncached rate.

Once the tools parameter changes, things become very different. Because tools are positioned at the very front, the first differing token appears very early, invalidating the cache from that point onward. This means the entire prefix is recomputed on every turn at full price—and since the prefix is large, you pay full price turn after turn. The tools themselves occupy only a small segment, but they dictate whether the massive prefix that follows can enjoy the 10x discount.

Writing tool definitions into the conversation content offers an alternative route. You control the placement yourself by appending them to the end of the conversation. The preceding tokens remain untouched, keeping the prefix cache fully intact, so only the newly added portion is billed at full price. The API allows modifying the tools array on every turn, and it also allows defining tools within messages. The constraint is not in the API, but in cache economics: which layer dynamic schemas reside in determines whether your prefix remains stable. Grok Bot’s meta-tool takes precisely this approach: dynamic schemas do not enter the tools array; they enter the conversation.

Cursor introduced that threshold specifically to keep the tool surface stable. The tools array contains only static core tools (such as READ, SHELL, WRITE, GLOB, and GREP, which are used in every turn) plus two stable entry points: GetMcpTools and CallMcpTool. The full schemas of the other 9 tools never enter the tools array; they exist only as single-line hints and are pulled into context only when needed.

That single-line hint is not generated by automatically truncating the tool’s description. In the source code, there is a constant named SAND_DYNAMIC_TOOL_HINTS, where all 9 hints are handwritten. The line corresponding to CLOUD_AGENT was authored by someone specifically to explain what the tool can do and when the model should select it. This is a product decision that requires crafting line by line. But this raises an unanswered question: why do only these 9 tools need this dynamic mechanism, while the remaining 18 static tools do not?

“Dynamic Loading” Obscures Two Orthogonal Dimensions

The answer lies in the two distinct natures of tools themselves. The model’s ability to act upon the outside world relies on the tools array, from which it invokes tools via structured tool calls. However, the tools array contains not only specialized tools, but also general-purpose tools like bash, read, and write. Bash is particularly powerful: through it, the model can invoke any CLI, run Python scripts, and curl any HTTP endpoint. Most of the time, the model’s “hands” are just these few general-purpose tools.

Here lies an easily overlooked fact: many new capabilities do not require new tools. If a capability can be expressed via bash (a CLI, a Python snippet, an HTTP endpoint), the model only needs to know how to drive it—placing that knowledge into context is sufficient. The capability is provided by existing bash, while the skill provides only knowledge, without adding anything to the tools array. That is exactly how our skill ecosystem works: a skill is Markdown teaching the model how to invoke a CLI, and the model executes it via bash. This is also why thin harness fat skills holds true.

Dynamic loading conflates two different things. One is the knowledge layer: pulling “how to do it” into context on demand. Its carrier is Markdown, and its mechanisms are retrieval, routing, and loading. Claude’s Agent Skills operates at this layer: loading a skill means reading a file into context so the model knows what to do, then executing it using existing bash.

The other is the capability layer: exposing “what can be invoked” to the model on demand. Its carrier is the tool schema—the entry in the tools parameter passed to the API—not the context content. This layer is needed only when a capability cannot be expressed through existing general-purpose tools: functionality that must run in a sandboxed remote box, functionality that requires internal app state or authentication, or functionality requiring a specific structured interface. These cannot be expressed via bash and require adding a new tool schema to the tools array. Grok Bot’s GetMcpTools/CallMcpTool belongs to this layer.

The critical difference lies in mechanism ownership: a skill is a knowledge carrier whose mechanisms are retrieval, routing, and reading Markdown into context; it lacks the ability to alter the tools parameter for the next request. The tools array belongs to the harness, determined by the application code constructing each request. Loading a skill alters context content (the model knows how to do it), whereas loading at the capability layer alters the tools array (what the model can invoke). When a capability must go through a tool call rather than bash, skill mechanisms cannot cover it, requiring mechanisms from the capability layer.

This layering is viable because the knowledge layer had already developed an independent, mature mechanism in the year leading up to Grok Bot. If the knowledge layer did not yet have its own carrier, the two layers could not be decoupled.

The knowledge layer and capability layer are two orthogonal dimensions: skill loading pulls how-to knowledge into context, while dynamic tool loading puts callable tools into the tools array; the two cannot substitute for each other

The Evolutionary Timeline of the Knowledge Layer

To understand why Grok Bot could decouple the capability layer from the knowledge layer, we must first look at how the knowledge layer matured over the preceding year. In July 2025, the Manus team published their Context Engineering article. At the time, no skill mechanism existed. When Manus tackled context engineering, the knowledge layer lacked an independent Markdown skill carrier, so it relied on the filesystem and rehearsal to externalize and maintain goals.

Three months later, on October 16, 2025, Anthropic released Agent Skills. With Claude leading the way, the knowledge layer gained an independent carrier for the first time: a folder containing instructions, scripts, and resources that the model loads on demand only when relevant. Two months later, on December 18, 2025, Anthropic published it as an open standard, with Codex, Cursor, and VS Code following suit with support. A research paper conducted 8,135 controlled experiments and found that 65.7% of performance improvements came from step-by-step and checklist-style skills, while only 4.5% came from supplementary facts. We analyzed this paper earlier: skills are checklists, not textbooks.

In our local system, this corresponds to a three-tier cache architecture: L1 is AGENTS.md (about 200 lines of pointers) loaded on every run, L2 is an index queried on demand, and L3 is the concrete skill files loaded only after matching. Garry Tan’s piece thin harness fat skills addresses this exact layer: the harness does only four things, pushing intelligence into skills and execution into deterministic tools.

By August 2026, when Grok Bot leaked, it already incorporated skills and plugins. The system prompt verbatim described a plugin as “a marketplace bundle of connectors and skills”. Pushing to an even further extreme, DSH made even the agent loop a plugin—the ultimate form of dynamic loading at the knowledge layer, though it requires Cordis’s runtime infrastructure.

Only with the knowledge layer having its own carrier could the capability layer focus cleanly on its own job: handling strictly what bash cannot express. Grok Bot’s design at this layer is the true protagonist of this article.

Grok Bot’s Capability Layer Mechanism

Dissecting Grok Bot’s dynamic tool mechanism reveals three interlocking design elements.

Wrapping native tools as a virtual MCP server: Cursor wraps its native tools (CloudAgent, CopyToBox, etc.) as a virtual MCP server under the namespace “cursor”. In the source code, the constant CURSOR_DYNAMIC_TOOLS_NAMESPACE is “cursor”. This allows the model to access both native tools and external MCP plugins through the single pair of GetMcpTools/CallMcpTool, learning only one invocation pattern. The dispatch layer in CallMcpTool intercepts the raw arguments, parses out the real tool name, and routes the call to either a native executor or an external server.

The single-line hint is a product decision. The 9 hints in SAND_DYNAMIC_TOOL_HINTS are handwritten. Each dynamic tool is annotated with contextType: { type: “dynamic”, conciseStaticContext: hint }, and that single line is all the model sees. This is a deliberately crafted routing prompt, not an automated truncation of the tool’s description field. When tools multiply to a certain point, the model needs a routing layer to determine which tool to select, and this routing layer demands manual refinement.

This index follows a Yahoo model, not a Google model. The Google model assumes information is already out there and simply needs to be retrieved in real time when queried; the Yahoo model relies on human editors-in-chief to curate, write, and organize a directory. Those 9 hint lines represent the product team acting as editors-in-chief, compiling the tool surface into one line per tool before the model ever queries it. We observed the same pattern in OpenAI’s data agent: in that article, an LLM takes on the role of an offline editor-in-chief, pre-compiling messy data warehouse code into dense context so the online system retrieves only the curated material, rather than raw metadata.

Skills and dynamic tools are orthogonal, each governing its own layer. Grok Bot employs both. Skills operate via the plugin system to govern the knowledge layer. The dynamic tool mechanism is reserved exclusively for the app’s own native tools to govern the capability layer. The two are never conflated. Yet this design is not the only answer: Manus, designed independently during the same period, took a completely opposite path.

Grok Bot’s lookup-before-invoke workflow: the model first sees a single-line hint, fetches the schema via GetMcpTools, and executes via CallMcpTool, with the dispatch layer routing to either a native executor or an external server

The Manus Contrast: Mask, Don’t Remove

Manus headed in the exact opposite direction: rather than dynamically loading tools, it includes the full set of all tools from the start, and then decides during decoding which ones cannot be selected. There are two reasons for this. First, serialized tool definitions reside at the very front of the context, so any modification invalidates all subsequent KV cache. Second, historical actions and observations continue to reference tools that no longer exist, causing model confusion and schema violations.

Their solution is called “Mask, Don’t Remove”: tool definitions remain permanently static and complete, while a context-aware state machine masks token logits during decoding to constrain which tools can be selected in the current state. Tool names are intentionally designed with consistent prefixes—such as tools starting with browser_ and shell_—to facilitate group-level constraints.

On the surface, Manus says not to add tools dynamically, while Grok Bot dynamically loads tools—two opposing answers. In reality, both adhere to the exact same underlying rule: the serialized tool surface must remain stable, pushing dynamism elsewhere. The only difference is which layer it gets pushed to.

Manus pushes it to decoding time. All tools reside permanently in context; what is dynamic is which ones can currently be selected. The cost is the token tax of having all schemas permanently in context; the benefit is a completely stable KV cache.

Grok Bot pushes it to the context layer. The tools array contains only the static core plus two stable meta-tool entry points; dynamic tool schemas do not enter the tools array, existing instead as single-line hints and being pulled into context only when needed. It appears to load dynamically, but its serialized tool surface is actually stable. This complies precisely with Manus’s rule.

Two teams, one year apart, designing independently, converged on the exact same constraint: the tool surface must remain stable. Both arriving at this point demonstrates that this constraint is forced by underlying dynamics rather than design preference. The remaining question, then, is: when pushing dynamism to different layers, what are the trade-offs of each?

Where Dynamism Lives Determines the Entire Design

Looking at four harnesses side by side, where dynamism lives determines the entire design:

harness Where Dynamism Lives Cost / Benefit
Codex Declarative + restart (declared up front) Simple, but switching tools requires restarting the process
Manus 2025/7 Decoding time Fully stable KV cache, but incurs token tax from permanent schemas
Grok Bot 2026/8 Context layer Stable tool surface + on-demand schemas, but adds an extra GetMcpTools round-trip
DSH In-process plugins (even the loop is swappable) Maximum flexibility, but requires Cordis runtime infrastructure
Where dynamism lives across four harnesses determines their entire design: Codex restarts the process, Manus masks at decoding time, Grok Bot places it in the context layer, and DSH uses in-process plugins

When should you use Grok Bot’s approach? Do the math on costs: the marginal cost of an extra GetMcpTools round-trip must be less than the permanent residency tax of N unused schemas. It is economical only when three conditions are simultaneously met: a large tool surface, sparse usage per turn, and limited model selection capability. The DSH article made an insightful observation: same ceiling, different floor. When tools are few, the approaches perform similarly; as tools multiply, the gap in the floor becomes stark.

The causal chain behind this constraint will be expanded in the next article. The specific numbers for KV cache economics will be provided there as well.

A closing takeaway for harness builders: first distinguish whether what you are pulling is knowledge or capability, and avoid using mechanisms from the wrong layer. For capability layer dynamism, first decide which layer it should live in before talking implementation. Two independent products converging on the exact same constraint is, in itself, the clearest signal for whether you should adopt this design.

Series

The same leak, two perspectives: