Where Model Intent Becomes Work

Grok Build's session actor can decide that the model should use a tool, but it does not itself define every tool or reach directly into the host operating system. This chapter follows the boundary between model-facing intent and concrete work. The focus is the tool registry, the ToolBridge that dispatches it, and the WorkspaceOps layer that mediates host effects. By the end, readers should be able to tell the difference between a capability being advertised, a tool call being executed, and a result being safe or useful enough for the next turn.

The distinction matters because “the agent can run commands and edit files” is a summary of several contracts. A command may be foreground work or a background task. An edit may match one exact region, several regions, or none. A session may expose a tool in one configuration but not another. The model needs schemas and results; the host needs resources, paths, notifications, and policy boundaries. Grok Build's architecture makes those concerns meet without making them identical.

A registry is a capability contract

A flat list of functions tells us what names exist. Grok Build's registry tries to describe when a tool is meaningful. A registered tool has a namespace, an identifier, a general kind such as execute, read, or edit, an input schema, configuration parameters, requirements, and a way to convert its typed output into the common tool-output form. That information serves two audiences at once. The model receives a definition it can call, while the runtime receives enough metadata to decide whether the definition's dependencies are present.

This is why the registry can contain terminal execution, file reads and edits, search, task output, subagents, web access, plan mode, monitoring, and scheduling without presenting them as interchangeable buttons. A terminal tool may require a way to retrieve background output and a way to kill a task when background execution is enabled. An edit tool may require a read capability unless its configuration changes that requirement. A tool can therefore be registered in the codebase but absent from a particular effective session because configuration, capability mode, client contract, or another requirement filters it out.

That filtering is a useful form of honesty. If a session advertises a tool, the model can reasonably expect its schema and supporting resources to exist. If the required support is absent, the registry should not create a convincing but unusable definition. Conversely, the existence of a tool in the default registry does not prove that every Grok Build session exposes it. Optional integrations and compatibility tool families broaden the possible toolset, while the effective session narrows it.

The registry also separates the stable identity of a capability from the name a particular client sees. A tool can have a namespace-qualified identity internally while its displayed name or parameter names are adapted for a client contract. That distinction lets compatibility layers use familiar conventions without changing the underlying implementation's kind and requirements. It also means that an explanation should focus on what the operation does and what resources it needs, not assume that one spelling is the only possible interface.

The requirements are where composition becomes operational. A background-capable terminal tool is useful only if the session can expose a way to retrieve or kill the resulting task. A tool that promises a file notification needs a notification channel connected to the session. A tool that reads or writes files needs an injected filesystem rooted in the right context. These dependencies are not incidental plumbing: they determine whether the model's advertised action can produce a complete, observable result. A registry entry without its supporting resource would be a broken promise to both the model and the user.

The ToolBridge is the runtime object that turns this registry into an executable boundary. It finalizes the builder's registrations, exposes model-facing definitions, holds a reference to shared resources such as the terminal backend, and dispatches a named call through the finalized toolset. It also provides operations that are not ordinary model calls: listing tasks, killing background work, updating resources, registering MCP tools, and tracking announced skills. In other words, it connects a stable tool contract to changing session state.

The bridge returns two related forms of a tool result. One form is clean output that can be serialized into a client update, a diff, or a notification. The other is prompt-ready text that can include reminders or explanations intended for the next model turn. Keeping those projections separate matters. A human-facing update may need a full diff or a task card, while the model needs a concise statement of what happened and what action is possible next.

The session does not normally call every concrete tool implementation directly. Its local dispatch boundary routes a prepared call through WorkspaceOps. The workspace layer owns host-local filesystem, version-control, execution, discovery, and session toolsets. It can create a session with a working directory, capability mode, terminal backend, hunk tracker, and resolved toolset. It can also decide how a toolset change behaves while a turn is active: an identical configuration may be reused, a change may wait for a turn boundary, or an externally owned local-bind toolset may be kept rather than silently replaced.

classDiagram class Agent { owns session lifecycle receives client requests } class ToolRegistryBuilder { registers schemas records requirements } class FinalizedToolset { filters capabilities converts outputs } class ToolBridge { exposes definitions dispatches calls holds resources } class WorkspaceOps { mediates host effects manages session toolset } class TerminalBackend { runs foreground/background work } class AsyncFileSystem { reads and writes files } class ToolOutput { prompt projection client projection } class NotificationHandle { emits typed updates } Agent --> ToolBridge : uses per session ToolRegistryBuilder --> FinalizedToolset : finalizes FinalizedToolset --> ToolBridge : becomes ToolBridge --> WorkspaceOps : dispatches through WorkspaceOps --> TerminalBackend : owns access to WorkspaceOps --> AsyncFileSystem : owns access to ToolBridge --> ToolOutput : returns TerminalBackend --> NotificationHandle : reports AsyncFileSystem --> NotificationHandle : reports

The diagram is not a catalogue of internal files. It shows the ownership question: the registry defines a possible operation, the bridge turns it into a session resource, and WorkspaceOps mediates the point where that operation can affect the host. The terminal and filesystem are resources with their own lifecycles, while notifications carry evidence back out.

Two paths from intent to effect

A terminal command shows why a tool needs more structure than a name such as “bash.” Grok Build's terminal tool supports foreground execution and explicit background execution. A foreground call returns output for the current turn, subject to timeout and output limits. A background call returns a task identity and keeps the process running; later retrieval or completion notifications can supply the rest of the story. The model therefore has to choose not only what command to run, but whether the current turn should wait for it.

The runtime preserves that distinction in its result. A background task can include an identifier, its output-file location, a running status, the original command, and a retrieval hint. A foreground result can include the exit code, signal or timeout state, current directory, output, truncation information, and the path to a fuller log when the returned output is bounded. These fields make the next decision more precise. “The command ran” is weaker than “the command is still running under task X,” and “the command failed” is weaker than “it exited with a particular status after producing this output.”

Time also changes the semantics. Foreground work needs a limit so that one command does not wedge the whole turn indefinitely. Background work has a different lifecycle because the model can continue with another task while the process runs. The tool validates shell-specific background operators and can move some foreground work into the background under configured behavior. A monitor uses the same general terminal machinery differently: it starts a long-running process, tails its output through a rate-limited pipeline, attaches an owner session, and emits selected lines as events. A monitor is therefore not just a command with a larger timeout; it is an event source whose output is expected to wake or inform the right session.

These differences are meaningful to the model. A foreground test command can answer the current question. A development server should normally become a background task. A log watch should emit filtered events rather than dump an unbounded stream into the conversation. The tool contract is doing part of the reasoning work by telling the model what the task identity means, how to retrieve output, and what not to do while waiting.

An exact file edit follows a different path. The edit tool receives a file path, an old string, a new string, and an optional replace-all choice. It uses an injected filesystem rather than assuming that the tool can write directly to any path on the host. The current contract can reject paths filtered by .gitignore, resolve the model-facing path against the session context, and refuse to treat a directory as a file. Those checks occur before the text replacement itself.

The central editing rule is deliberately strict: a nonempty old string should identify one location unless the model explicitly requests replacement of all occurrences. If the text appears more than once, the tool reports ambiguity instead of silently choosing the first match. If no match is found, the result can tell the model to reread the file, show a nearby matching line, warn that the user may have changed the file, or explain that visually similar Unicode punctuation differs at the byte level. The tool is not merely saying “write failed.” It is helping the next turn recover from stale or underspecified input.

When an edit succeeds, the result can include the file path, the old and new text, contextual edit details, and a notification carrying the new content and previous content. That evidence serves both the user interface and later state tracking. A user can inspect what changed; the runtime can associate the write with the tool call; the next model turn can reason from a concrete update rather than from its own intention.

This feedback is especially valuable when a user and an agent can both change a workspace. A failed match may mean that the model supplied the wrong context, but it may also mean that a person edited the file between the read and the write. Reporting a nearest match and warning about possible user edits gives the next turn a reason to reread instead of retrying stale text. The tool's behavior therefore acknowledges that the workspace is shared and mutable; it does not treat the model's previous observation as permanent truth.

The terminal path has a comparable distinction between observation and effect. The command output shown in the current turn can be capped, while the full output remains associated with a task log. A background task can continue after the model has moved on, and a monitor can select lines from a long-running output stream rather than copy every byte into chat. These choices reduce context pressure, but they also make task identity and retrieval part of the tool contract. A result that omits whether output is complete, truncated, or still being produced would invite the model to draw the wrong conclusion.

The two cases reveal a common design pattern. A robust tool has an input contract, a resource boundary, a lifecycle, an output projection, and a failure explanation. The terminal tool's task ID and output file serve the lifecycle. The edit tool's exact-match rule and prior-content notification serve correction and auditability. Neither tool has to solve every safety problem by itself.

Tool-local validation does not replace permission policy. A command that passes a timeout check may still be denied by a rule or hook. An edit that matches exactly may still target a path outside the intended boundary if broader controls allow it. Nor do typed results replace kernel containment. A tool can report a clean status while a shell redirection, child process, or external program creates effects that the tool's own parser did not model. The registry and bridge make capabilities legible; WorkspaceOps gives them a host context; other layers decide whether that context is authorized and contained.

That separation is the point at which Grok Build becomes easier to reason about. When a tool is missing, inspect capability composition. When a call is well-formed but affects the wrong place, inspect workspace and path mediation. When the result is ambiguous or stale, inspect the tool's recovery contract. When an approved operation still reaches too far, inspect permission and process containment rather than adding another friendly error message. The next checkpoint can now reconstruct the whole path—from prompt, to session, to tool, to workspace effect—and test where each decision belongs.

References