From Raw Output to Deliberate Computation

mksglu/context-mode turns the context-window idea into a concrete execution choice: should an agent expose data to the model, process it outside the conversation, or preserve it for a later lookup? This chapter focuses on that first decision and on the tools that implement it—ctx_execute, ctx_execute_file, ctx_batch_execute, and ctx_fetch_and_index. By the end, the useful distinction is not simply “small output versus large output,” but exact observation, derived knowledge, and durable evidence.

The key decision is what must cross the boundary

Suppose an agent is investigating a repository. A short git status result may be worth seeing directly. The agent needs to know the current branch and changed files, and the output is already bounded. A 700 KB collection of source files is different. If the question is “How many functions use this interface?” the model does not need to read every file. It needs a program to inspect them and a trustworthy count.

The same input can require a different route a few minutes later. After finding an unusual result, the agent may need the exact code around one function, or the precise text of a configuration entry before editing it. A count is not a substitute for source text. Hiding that text in a sandbox would make the final edit harder to audit. The purpose of context-mode is therefore not to keep everything away from the model. It is to make the crossing deliberate.

This purpose explains the project’s repeated instruction to “think in code.” When the task is to filter, count, parse, compare, or aggregate, the model writes the computation and lets a subprocess handle the raw input. When the task is to edit, inspect one known line, or observe a short fixed status, native tools remain appropriate. A context-saving mechanism that obscures the exact bytes needed for a safe edit would optimize the wrong part of the workflow.

What ctx_execute actually protects

ctx_execute accepts a language and a program. Context-mode writes that program to a temporary script, selects an available runtime, and starts a child process. The current executor supports twelve language families, including JavaScript, TypeScript, Python, shell, Ruby, Go, Rust, PHP, Perl, R, Elixir, and C#. The child runs with the project directory as its working directory, so repository-relative paths and project-aware commands resolve naturally, while the script itself lives in a temporary execution directory.

The important boundary is between the child’s inputs and its returned result. The child may read a log, inspect a directory, call a local command, or fetch a response. The model receives the output that the program prints, together with the execution provenance and any necessary diagnostics—not an automatic transcript of every byte the program read. A program that prints 42 matching records crosses a small answer. A program that prints the entire 200 MB file defeats the purpose, even though the file was technically processed inside the child.

That makes the program itself part of the contract. The tool description asks the agent to use console.log, print, echo, or the equivalent for the answer. The executor does not infer which lines matter. The agent has to choose an output shape that preserves the evidence needed for the next decision. For example, a useful repository analysis might print the number of matching files, the names of the top few candidates, and a short reason for each. It should not print every intermediate match merely because the program found one.

The execution boundary has practical controls, but they are not the same as a complete operating-system sandbox. The executor can apply an explicit timeout, kill the process group when a run exceeds it, cap combined stdout and stderr at 100 MB, and remove temporary directories after ordinary completion. Background mode deliberately leaves a process running after a timeout and returns partial output; that is useful for a server or watcher but creates a process-lifecycle responsibility. The code also filters environment variables that can inject startup code, replace compilers, alter module paths, or load profilers.

Those controls address predictable failure surfaces: a command that never terminates, a child that spawns descendants, a yes-style output flood, or an inherited environment that changes runtime behavior. They do not turn arbitrary code execution into a sealed container. The project’s own documentation says that execution tools inherit process filesystem access and network access, and advises keeping the host’s sandboxing and permission controls enabled. In context terms, the child keeps raw data out of the model’s conversation; in security terms, it remains a powerful process that must be governed.

sequenceDiagram participant A as Agent participant M as MCP server participant P as Policy checks participant X as Executor subprocess participant S as Project data participant K as Knowledge store A->>M: Submit language and program M->>P: Check command, file, and host policy P-->>M: Allow or deny M->>X: Create temporary script and run it X->>S: Read and derive over project data alt Small or intentional result X-->>M: Stdout and diagnostics M-->>A: Audited code echo plus selected output else Large or intent-driven result X-->>M: Output for indexing M->>K: Store sections in FTS5 M-->>A: Pointer, previews, and search shape end

The diagram shows why “sandboxed” should be read as a dataflow boundary first. The model can ask the process to do work over the data, but the response path still determines what consumes context. A small derived answer returns directly. A large or intent-driven result is moved into the knowledge store, where a later search can retrieve selected sections. In both cases, the program is the mediator between the source and the conversation.

When a file should be computed over, not read

ctx_execute_file applies the same boundary to one named file. It reads the file inside the execution path and exposes its contents to the supplied program through a language-specific variable called FILE_CONTENT—or the corresponding form for languages whose syntax differs. The program can count lines, parse JSON, select log entries, compute statistics, or identify records. Only what the program prints returns to the model.

That is a better fit for questions about a file than a native Read when seeing the whole file would consume space without improving the decision. A 45 KB access log can be searched for status codes and summarized by endpoint. A CSV can be reduced to row counts and grouped totals. A JSON response can be inspected for missing fields. The file remains available to the program, so the model can ask for a more targeted result without first placing the entire source in the conversation.

But the distinction is not “large files use one tool, small files use another.” Intent controls the choice. If an agent is about to edit a file, native Read is still the correct surface because the subsequent edit needs exact text that can be matched and reviewed. If the agent needs one known line and its offset, a bounded Read is simpler. If the agent needs to understand the file’s structure without seeing all of it, computation is appropriate. The tools are separated by what the agent must do with the bytes, not by a universal size threshold.

The file path also has a security meaning. Context-mode checks the project boundary and Read deny rules before processing a file, and the implementation treats symlink and path traversal behavior as part of that check. That is important because an MCP tool’s input may not be as visible to a host approver as a native file read. The execution result may be concise, but the path that supplied it still needs to remain within the user’s intended authority. The security chapter will examine those checks in detail; here the practical rule is enough: computation reduces what is returned, not what the operator must authorize.

Gather first, derive second

A single ctx_execute call works well when the input and the computation are already clear. Real investigations often begin with several independent sources: a repository status, recent commits, issue records, test output, or a set of regional API queries. ctx_batch_execute is the gather layer for that situation. It runs multiple labeled commands in one call, combines their results, indexes the output, and can run queries against the newly created sections before returning.

Labels are more than cosmetic. Each command becomes a named section in the indexed result, so a later query can distinguish an issue lookup from a commit analysis or a test report. The batch response includes an inventory of commands and indexed sections, while matching windows come back for the questions supplied with the call. Full command output remains available through the store instead of being echoed wholesale. This is the difference between “the agent ran five commands” and “the agent can now ask the indexed evidence five related questions without paying for five separate raw-output dumps.”

The tool separates collection from interpretation. Concurrency can reduce the waiting time for independent I/O, such as unrelated network requests or read-only queries. It does not mean that the model should receive all of those responses and then mentally aggregate them. A later processing step can consume retained or indexed material and print the comparison, count, or filtered result. The useful pattern is gather, preserve, derive, and return—not gather, flood, and hope that attention finds the important line.

There are two deliberately different concurrency modes. At concurrency one, the batch retains a shared timeout budget and a legacy cascading behavior: if the batch runs out of time, later commands may be marked skipped. Above one, context-mode uses a bounded worker pool, gives each command its own timeout, isolates failures, and preserves the original input order in the response. That is a sensible distinction between a serial pipeline and independent jobs, but it does not make shared state independent.

Builds, tests, lock-file operations, port-binding servers, and commands that mutate the same workspace can interfere with one another even when each command is individually safe. For those tasks, the project tells the caller to keep concurrency at one. A faster batch that lets two commands rewrite the same generated file is not an improvement. The context boundary saves reasoning capacity only if the execution boundary preserves the meaning of the work.

Batch queries also have scope. By default, the queries search the sections produced by that batch, which makes the result predictable for a just-collected research step. A global query scope can include earlier indexed knowledge as well. The difference matters when a new command is intended to enrich a larger body of evidence: local scope answers “what did this batch contain?” while global scope asks “how does this batch relate to everything already stored?”

Fetching is another boundary, not a browser replacement

ctx_fetch_and_index handles a related but distinct case: external content that should be preserved for later questions. It performs a plain HTTP or HTTPS fetch in an executor subprocess, identifies the content type, converts HTML to Markdown, pretty-prints JSON when possible, and indexes plain text or other content in the appropriate form. It returns metadata and a bounded preview rather than placing the whole response in the conversation.

The tool is useful when the source is a documentation page, changelog, API reference, or specification that will be queried more than once. A one-off question about an endpoint may be cheaper to answer with a sandboxed derivation. A library comparison may need several pages retained under distinct labels so the agent can ask the same set of questions across them. In the latter case, indexing turns the web response into durable evidence instead of making the conversation carry every page at once.

This path also makes freshness explicit. A successful fetch is cached on disk and reused within a default 24-hour time-to-live. A cache hit returns a freshness hint rather than refetching and re-indexing the page. The caller can extend the window for stable specifications or bypass it with ttl: 0 or force: true when freshness matters more than the saved round trip. A cached page is therefore not “the latest page” by definition; it is a known representation within a stated freshness policy.

A plain fetch is not a headless browser. Pages whose useful content appears only after client-side JavaScript execution are outside this tool’s documented scope. Network reachability is also not the same as permission to retrieve every address: context-mode validates schemes, DNS results, redirects, and response size, with a stricter private-network mode available for hosted or CI environments. Those checks can reject a request before any content is indexed. The fact that the raw response stays out of context does not remove the network boundary.

Choosing the path by intent

The practical choices can be reduced to four questions. Do you need to see or edit exact bytes? Use the native observation or edit surface, especially when the next operation depends on matching text. Do you need a derived fact from data? Use ctx_execute or ctx_execute_file, and make the program print only the evidence that supports the next step. Do you have several independent sources to gather? Use ctx_batch_execute, choosing concurrency according to whether the work is independent I/O or shared-state computation. Will you need the source again? Use ctx_fetch_and_index or the indexing path so exact sections can be retrieved later.

These are not rigid product categories. A single investigation can move through all four. An agent might observe a short status natively, batch several read-only queries, compute a summary over the results, and index a specification for later exact lookup. Context-mode’s contribution is to make the transitions visible and to keep each form of output tied to its purpose.

The next architectural problem follows from this one. Once raw material is kept outside the conversation, the system needs a reliable way to divide it into sections, rank those sections, and return the exact passage that a later question requires. That is the role of context-mode’s searchable knowledge base: not a more aggressive summary, but a second memory path for evidence that must remain recoverable.

References