When we assess a coding agent, our first question is usually: which model does it use?

Which model version is it? What level of reasoning effort is selected? How large is the context window? How reliable are its tool calls? These questions matter because the base model defines important boundaries on what the agent can do.

But when building real agent systems, we quickly encounter a harder phenomenon to explain:

The same model can behave very differently under a different harness.

Here, the harness is the system layer between the model and the real execution environment. It determines what context the model can see, which tools it can call, how those tools are presented, how execution results are returned, when context is compressed, how the system recovers from failures, and how a task continues from start to finish.

In an earlier article, “Harness Engineering: Engineering Beyond the Model”, I described the harness as the execution structure outside the model: tools, permissions, validation, observation, memory, and feedback jointly determine whether an agent can work reliably. Following that line of thought leads to a more specific question: even if two harnesses provide the same capabilities, do they expose those capabilities in forms that are equally easy for a model to use?

I use model ergonomics to describe this fit.

This is not yet a rigorously standardized academic term. Existing work more often uses concepts such as Agent-Computer Interface (ACI), agent scaffolding, tool interface, or harness design. But model ergonomics is a useful name for an increasingly important engineering question:

Does the harness present the environment’s capabilities in a way that helps a particular model understand the situation, make decisions, take action, and recover from errors?

This means that an agent’s observed capability cannot be attributed only to the model, or simply to the harness. What matters is the fit between the two.

A Harness Is Not Merely a Wrapper Around the Model

Early large-language-model applications can easily be understood as a simple pipeline:

task

model

answer

But the real execution process of an agent system is closer to:

task

harness constructs observation

model reasons

harness exposes actions

model selects action

harness executes

harness transforms feedback

model reasons again

...

The model does not interact directly with the computer. It interacts with the world constructed for it by the harness.

When SWE-agent introduced the Agent-Computer Interface in 2024, it made this point explicit: language-model agents are a new kind of computer user, so the interface designed for them can significantly affect their behavior and performance on software-engineering tasks.1

This suggests that observed agent capability is closer to:

Capability = f(Model, Harness, Environment, Budget)

rather than:

Capability = f(Model)

The Model × Harness interaction term is especially important.

The 2026 work Harness-Bench studies this issue more directly. It treats tools, context, state, permissions, constraints, and recovery mechanisms as parts of the harness and compares execution trajectories across model-harness configurations. One important conclusion is that agent capability is better reported at the model-harness configuration level than attributed to the base model alone.2

So, in an agent setting, “How strong is this model?” is itself an incomplete question.

A more precise question is:

What can this model do with a given harness, tool environment, context policy, and execution budget?

Model Ergonomics Is About More Than Whether Something Is Possible

Model ergonomics is easily mistaken for “writing some extra prompts for a specific model,” but its scope is broader.

The fact that a model can theoretically perform an operation does not mean the current harness gives it the best interface for performing that operation.

Suppose a model has only one very powerful tool:

exec_command(command)

From a capability perspective, the model can use it to construct almost an entire local toolset for itself. With shell, Python, Perl, awk, or other programs, it can read files, traverse directories, search, batch-process data, modify files, and run tests.

From the perspective of whether an operation is expressible, a general shell is therefore close to Turing-complete.

But expressiveness is not the model’s only problem.

The model must also decide what action to take next, construct the correct parameters, control side effects, understand tool results, and recover after failures. Harness quality therefore also depends on questions such as:

  • Can the model easily select the correct action?
  • Is the action granularity appropriate?
  • Are tool parameters easy to generate reliably?
  • Do tool results contain enough information without excessive noise?
  • Are errors easy to classify?
  • Does the context preserve the state needed for the next step?
  • After a mistake, can the model recover and continue making useful progress?

Therefore:

capability completeness ≠ ergonomic fit

One interface may be highly expressive in theory but force the model to make too many low-level decisions. Another may offer many convenient structured tools, yet make it harder to choose an action because those tools are numerous and overlap in meaning. Model ergonomics examines the relationship between these two situations, including the action search space they create.

Running Grok on Codex: What Comes After Protocol Compatibility

This issue becomes concrete when running Grok on the Codex harness.

Our goal is not to reimplement a Grok coding agent. It is to preserve as much of Codex’s existing execution system as possible, including Thread and session lifecycles, context and history, sandbox and approval, MCP, Code Mode, Multi-Agent, ToolRouter, and the App Server and UI contract.

The corresponding architecture principle is:

Stock Codex owns the harness. Provider adaptation owns backend differences.

In the current design, the Grok Provider is mainly responsible for real protocol differences between Codex and the Grok Responses API: request/history projection, the Grok Responses dialect, projecting Codex’s canonical namespaced tools into flat functions that Grok accepts, and restoring returned calls to their canonical Codex tool identity.3

These are all forms of Provider compatibility.

They answer this question:

Can the existing Codex harness work correctly through the Grok API?

But once the model starts executing real coding tasks, another class of problem appears.

For example, when several files must be read at once, we have observed Grok repeatedly generating temporary Python programs through exec_command:

python3 - <<'PY'
from pathlib import Path

for path in paths:
    print(Path(path).read_text())
PY

This does not mean Grok cannot use Codex: it successfully uses the shell Codex provides and can usually complete the task.

The more interesting question is:

Why does the model repeatedly reconstruct a file-reading abstraction inside the shell?

This question goes beyond Provider protocol compatibility and into model ergonomics.

Shell Is a General Interface, but Not a Neutral One

In the current Grok-enabled Codex release/rust-v0.151.0, the model catalog for Grok 4.6 configures UnifiedExec, while apply_patch_tool_type is None.4

Codex’s tool-planning code registers exec_command and write_stdin for Unified Exec. The stock ApplyPatchHandler enters the tool registry only when model_info.apply_patch_tool_type is present.5

So, in this specific configuration, Grok receives a highly expressive shell but does not receive Codex’s native apply_patch tool.

This fact alone does not prove that the harness design is wrong, much less that “giving Grok more file tools will necessarily improve performance.”

But it exposes an easily missed property of a generalized harness:

A general interface does not mean an interface without design bias.

If every model is given the same interface:

shell(command: string)

this can look highly generalized. Any model can use it, and a large set of computer operations can be expressed through it.

But choosing shell as the universal action representation is itself a strong design decision. It assumes that the model can reliably handle shell syntax, quoting, batching, side effects, stdout, and combinations of tools such as grep, sed, find, and Python.

For a model that handles these operations well, this freedom can be useful. For another, it may simply increase the number of choices and add extra steps to execution.

A generalized harness is therefore not free of specialization. Its preference for a particular interaction style may simply be hidden inside an abstraction considered universal enough.

GrokBuild Is a Design Signal, Not a Conclusion

xAI’s open-source GrokBuild provides an interesting comparison.

Its tool runtime contains a group of tools explicitly marked as Codex-specific:

apply_patch
grep_files
list_dir
read_file

The source describes these tools as ports and modifications of Codex implementations.6

It is easy to draw a conclusion that is too strong:

GrokBuild has read_file, so Grok must also have read_file when running in Codex.

There is not enough evidence to support that conclusion.

The GrokBuild design proves only that xAI chose to expose these structured file operations when building its own coding harness for Grok.

The comparison is still useful: two harnesses designed to help Grok perform software-engineering tasks can offer very different action vocabularies:

Codex                  GrokBuild

exec_command           read_file
write_stdin            list_dir
...                    grep_files
                       apply_patch
                       ...

If the same model behaves very differently in the two environments, the difference cannot be attributed entirely to model weights.

More importantly, GrokBuild’s ToolConfig separates canonical tool identity from client-facing presentation. It supports overrides for tool names, parameter names, and descriptions.7

This suggests an important architectural direction:

A tool’s definition and the way it is presented to the model do not necessarily belong in the same layer.

That principle is more valuable than simply copying GrokBuild’s particular tools.

How Generalized and Specialized Harnesses Can Share Responsibilities

Once we accept model ergonomics, it is easy to move to the opposite extreme: if different models prefer different interfaces, maintain a dedicated harness for each model.

For example:

Model A ToolRouter
Model B ToolRouter
Grok ToolRouter
...

In the short term, this can make it easy to improve benchmark scores.

If a model does not use one tool well, replace it with another. If a context layout performs poorly, add a model-specific branch. If a model often stalls at a particular point, add a dedicated recovery rule.

If this continues, however, another class of problem appears:

semantic divergence
test explosion
model-version drift
duplicate runtimes
upgrade difficulty

Models themselves continue to change. A workaround needed today may become useless after the next update, or even restrict the newer model’s capabilities.

So the real question is not:

Generalized harness or specialized harness?

It is:

What should be generalized, and what may be specialized?

I currently prefer to separate the system into three layers.

┌────────────────────────────────────┐
│ Model Ergonomic Profile            │
│                                    │
│ tool presentation                  │
│ observation granularity            │
│ context policy                     │
│ reasoning defaults                 │
│ guidance / recovery                │
└────────────────┬───────────────────┘

┌────────────────▼───────────────────┐
│ General Semantic Harness           │
│                                    │
│ canonical tools                    │
│ ToolRouter                         │
│ sandbox / approvals                │
│ history / context                  │
│ multi-agent                        │
│ lifecycle / state                  │
└────────────────┬───────────────────┘

┌────────────────▼───────────────────┐
│ Provider / Wire Adapter            │
│                                    │
│ auth / endpoint                    │
│ request dialect                    │
│ reasoning projection               │
│ tool wire encoding                 │
│ response normalization             │
└────────────────────────────────────┘

Each layer solves a different problem.

The Semantic Harness Should Remain General

The first layer is the general semantic harness. It should avoid model-specific implementations as much as possible.

Operations such as Read File, Apply Patch, Exec, MCP Call, Web Search, and Spawn Agent can all be understood as canonical semantic operations in an agent system.

Likewise, sandboxing, permissions, history, tool lifecycle, persistence, and cancellation should remain unified.

The most important requirement at this layer is not that every model sees exactly the same interface. It is that:

One system must retain authority over execution.

If Codex already owns the ToolRegistry, ToolRouter, sandbox, history, and extension runtime, then creating a separate Grok ToolRouter just to support Grok usually means the architecture is beginning to split.

This is also the boundary maintained by the current Codex Third-Party Provider North Star: Codex core keeps the canonical concepts, while Provider-specific behavior is projected only at the narrowest backend boundary.8

Provider Compatibility Should Cover Protocol Differences Only

The second layer handles Provider compatibility. It can use specialized adaptations because backend protocols do differ.

For Grok, for example, it can handle:

logical Codex reasoning

Grok wire reasoning

canonical namespaced tool

backend-safe function name

reverse projection

canonical Codex identity

canonical history

Grok-compatible request representation

This specialization has a clear source: the backend contract is different.

It answers:

How can we preserve Codex’s unified semantics when connecting to different Providers?

If a difference cannot be explained by the Provider API, wire protocol, or backend behavior, we should be cautious before deciding that it belongs in the Provider layer.

For example, even if experiments eventually validate that “Grok prefers read_file to shell,” that is not a protocol fact about the Grok Responses API.

It belongs to another layer.

The Model Ergonomic Profile Controls What the Model Sees

The third layer is model ergonomics.

It addresses this question:

Once the harness can run correctly, how should its capabilities be presented to the current model?

This layer may control things such as:

  • Which canonical tools are exposed directly to the model;
  • How tool names and descriptions are presented;
  • How parameter schemas are organized;
  • Action granularity;
  • Context compression;
  • The level of detail in tool results;
  • Reasoning defaults;
  • Recovery hints;
  • Direct, deferred, or other tool-exposure policies.

The most important boundary is:

Specialize the interface, not the execution authority.

Suppose future benchmarks show that Grok performs substantially better with read_file than when it must organize file reading through exec_command.

The correct direction is more likely to be:

model-facing read_file

canonical filesystem operation

stock Codex execution environment

rather than:

GrokReadFileRuntime
GrokFileSystem
GrokToolRouter

The first changes the interface the model sees. The second starts to duplicate the implementation of harness semantics.

Capability and Ergonomics Are Different Kinds of Facts

If model ergonomics is eventually introduced into model profiles, ergonomic preferences must not be confused with capabilities.

For example:

supports_image = true

describes a capability.

It answers:

Does this execution path support images?

By contrast:

prefer_file_tools_over_shell = true

if a policy like this exists in the future, would describe an ergonomic preference.

It answers:

According to the current benchmark evidence, does this interface make it easier for the model to perform reliably?

The stability of these two facts is very different.

Capability support usually rests on clear evidence about an API, a model, or the complete execution path. Ergonomic policies, however, are empirical judgments. They may stop working when the model version, system prompt, tool implementation, or training method changes.

Policies for model ergonomics should therefore meet several conditions:

  • They have support from benchmarks or execution traces;
  • They can be replaced independently;
  • They can be checked with regression tests;
  • They do not turn empirical preferences into lasting semantic contracts;
  • They are not built into long-term architecture on the strength of a single observation.

This is why seeing Grok use Python is not enough reason to add read_file.

An unusual behavior is a starting point for investigation, not enough evidence for a design conclusion.

Model ID May Not Be the Final Abstraction Either

Going further, model ergonomics may not ultimately be modeled entirely around model IDs.

We can of course select different profiles from identifiers such as:

grok-4.6
model-a
model-b

But the more important properties may be the behavioral dimensions behind the model, such as:

shell fluency
tool-schema adherence
parallel-call reliability
context-noise tolerance
self-recovery strength
action-granularity preference
planning reliability

These dimensions are not yet standardized enough to justify turning them into a formal schema today. Doing so would be premature abstraction.

But they point toward the more important research question.

What we really want to know is not:

What special code should Grok have?

It is:

Which interaction patterns help Grok complete tasks most reliably?

The same question applies to different models in the same family, different reasoning configurations, and even different versions before and after a model upgrade.

Models that share an API do not necessarily work best with the same interaction patterns.

Harness Quality Has at Least Two Dimensions: Generality and Adaptability

Once we accept this view, “Is this harness good?” also requires a more precise definition.

The first dimension remains Generality:

How many models can it connect to? How many Providers can it work through? How many environments can it support?

This is portability in the traditional sense.

But there should also be a second dimension: Adaptability.

It asks:

After connecting a new model, how many additional mechanisms are needed to bring it close to its potential as an agent?

This gives us two very different kinds of systems.

One harness may support one hundred models, but expose every model to the same lowest-common-denominator interface.

Another may preserve the same semantic kernel while allowing different models to use validated tool presentation, context policies, and recovery policies.

Counting only “how many models are supported” cannot distinguish the quality of these two harnesses.

We can even describe the idea with a concept that is not mathematically rigorous but is still useful:

Harness Efficiency(Model)
    =
Observed Agent Capability(Model, Harness)
    /
Potential Agent Capability(Model)

The denominator cannot be observed directly, so this is not an engineering metric we can calculate directly.

But it expresses an important goal:

A good harness should do more than let a model run. It should reduce the capability lost in the interface and execution loop.

The Benchmark Unit Should Be Model × Harness

This also changes how benchmarks should be designed.

Suppose we observe:

Model A + Harness X = 70
Model A + Harness Y = 48

Model B + Harness X = 52
Model B + Harness Y = 69

Then “Is Model A or Model B stronger?” is no longer a fully specified question.

At minimum, it should become:

Which model and harness work better together, and under what budget and environmental conditions?

The recent work Same Model, Different Harness takes a more direct approach: hold the model fixed, change context management and stalled-work handling, and observe changes in coding-agent results. It is still a relatively recent preprint, so its specific findings should not be treated as settled consensus on their own, but the experimental design clearly illustrates how harness effects can be isolated.9

Self-Harness approaches the question from another direction: discover model-specific failure patterns through execution traces, propose small harness modifications, and validate them through regression testing.10

Together, these works point toward a methodology:

Model ergonomics should be studied through controlled experiments, not decided because “this tool call looks inelegant.”

Back to Grok: How Model Ergonomics Should Be Validated

For Grok’s tendency to organize file operations through Python inside Codex, I would therefore not begin with “How do we stop it from writing Python?”

Using Python is not itself a failure.

We should first define the observations that actually matter, such as:

  • Task success;
  • Patch correctness;
  • Token usage;
  • Tool-call count;
  • Latency;
  • Invalid-action rate;
  • Recovery rate;
  • Unnecessary shell complexity;
  • The range of operations that involve approval and sandbox controls.

Then compare controlled harness configurations, for example:

A. current Codex tool surface

B. current surface
   + improved tool guidance

C. current surface
   + stock apply_patch

D. current surface
   + read_file

E. current surface
   + read_file / list_dir / grep_files

If the results are:

A  61%
B  62%
C  69%
D  69%
E  72%

then ergonomic specialization has clear value.

If the results are only:

A  61%
E  62%

while maintenance cost and the tool surface both grow significantly, then reducing Python invocation from 80% to 10% has little engineering value by itself.

Prettier tool calls do not necessarily mean a stronger agent.

Why apply_patch Is a Better Early Experiment

In the current Grok × Codex implementation, I would investigate apply_patch before immediately adding the full read_file / list_dir / grep_files tool family.

The first reason is architectural cost.

Codex already has a stock ApplyPatchHandler; the current Grok catalog simply does not enable the corresponding apply_patch_tool_type.

So validating whether Grok can correctly use stock apply_patch through the existing reversible tool projection is a narrower experiment than adding an entirely new toolset.

Second, structured tools have value beyond model ergonomics: they make the intended operation explicit.

When the model calls:

apply_patch

the harness knows that the model is modifying files.

When the model modifies files through:

exec_command("python3 ...")

the meaning of the operation is hidden inside arbitrary code execution.

The first form is easier to integrate with sandboxing, approval, tracing, telemetry, replay, and failure classification.

The value of a structured tool therefore goes beyond whether the model prefers to call it. It may also help the harness understand what the agent is doing.

If File Tools Are Needed, They Still Should Not Duplicate the Runtime

Suppose benchmarks eventually show that Grok benefits significantly from read_file, list_dir, or grep_files.

That still does not mean GrokBuild’s entire tool runtime should be ported into Codex.

Codex already allows extension tools to enter the same ToolRegistry and ToolRouter.11

A more reasonable structure would therefore be:

model-facing compatibility tool

Codex extension adapter

stock filesystem / sandbox context

stock ToolRouter

The model gets an action vocabulary that is easier for it to use, while the system still keeps:

one history
one router
one sandbox
one execution authority

This is the key to making a generalized semantic harness and specialized model ergonomics coexist.

Generalize Semantics; Specialize Interaction

In the end, I think the most useful boundary between generalized and specialized harnesses can be compressed into one sentence:

Generalize semantics as much as possible; allow measured specialization in ergonomics.

The corresponding system structure is:

Generalized Semantic Harness
        +
Thin Provider Compatibility Layer
        +
Measured Model Ergonomic Profiles

The first layer prevents the system from fragmenting as the number of models increases.

The second handles real protocol differences between backends.

The third accepts an increasingly visible fact: different models are not identical “API consumers.”

They can have different tool-selection habits, context tolerance, action granularity, recovery patterns, and execution biases.

A mature harness should account for these differences while avoiding a separate agent runtime for every model.

The central engineering challenge is to preserve unified semantics, safety boundaries, and execution authority while allowing limited, verifiable changes to the interface based on actual model behavior.

At first, the primary question was:

Can the model run?

Then it became:

Can the model use tools?

Later:

Can the model finish long-horizon tasks reliably?

Model ergonomics moves the question one step further:

Does this harness allow this model
to use its capabilities efficiently and reliably?

This may become a fundamental dimension for evaluating agent harnesses.

The model sets the agent’s potential limits. The harness determines how that potential becomes reliable behavior in practice, and how much of it can be realized.

We therefore need to optimize the model and harness as a system, not just the model on its own.

Footnotes

  1. John Yang et al., SWE-agent: Agent-Computer Interfaces Enable Automated Software Engineering, 2024.

  2. Yilun Yao et al., Harness-Bench: Measuring Harness Effects across Models in Realistic Agent Workflows, 2026.

  3. The Grok × Codex case in this article is based on the release/rust-v0.151.0 branch of Harness-X-Harness/codex. In that implementation, the Grok Provider handles Provider-specific adaptation such as request projection, the Responses dialect, and flat-function projection.

  4. In grok_catalog.rs, the current Grok 4.6 catalog configures shell_type: UnifiedExec, apply_patch_tool_type: None, and tool_mode: None.

  5. In spec_plan.rs, Unified Exec registers ExecCommandHandler and WriteStdinHandler; ApplyPatchHandler is registered only when model_info.apply_patch_tool_type.is_some().

  6. xAI GrokBuild’s implementations/codex module contains apply_patch, grep_files, list_dir, and read_file. The source describes them as Codex-specific tool implementations ported and modified from Codex.

  7. GrokBuild’s ToolConfig supports name_override, params_name_overrides, and description_override, separating internal tool identity from client-facing presentation.

  8. Codex Third-Party Provider North Star defines the goal as preserving the stock Codex harness and placing only verified backend API differences at the Provider projection boundary.

  9. Sydney Lewis, Same Model, Different Harness: Different Coding-Agent Results, 2026. At the time of writing, this was still a relatively recent preprint, so I cite it mainly for its research question and experimental design rather than treating the results of one paper as a final conclusion.

  10. Self-Harness: Harnesses That Improve Themselves, 2026.

  11. The current Codex spec_plan.rs combines core tools, MCP tools, extension tools, and dynamic tools into one ToolRegistry, then constructs a unified ToolRouter. This provides an existing boundary for adding model-facing compatibility tools without duplicating the execution runtime.