Skip to main content
The Davenporter
Essays Builds Now About
Theme
Palette
Jason Davenport

I write about agents doing real engineering work: source control, memory, telemetry, and the human side of AI.

Subscribe

Elsewhere

  • About me
  • Substack
  • Medium
  • LinkedIn
  • GitHub
  • X
  • RSS
  1. Home
  2. Essays
  3. Same harness, same rules, different habits: Opus vs. Argon in Antigravity

Same harness, same rules, different habits: Opus vs. Argon in Antigravity

Nov 11, 2026 · 8 min read

Why Claude Opus 5.5 and Gemini 4 Argon used the same code graph plugin so differently in Antigravity. Argon read each tool's schema and queried the graph. Opus stayed in bash with zero schema reads, used the graph heavily when a repo wired it into package.json, and still defaulted to grep after AGENTS.md added one line call syntax.

Architectural diptych comparing a structured code graph lookup on the left against Unix stream pipelines on the right.

In Antigravity, with the same AGENTS.md rules and the same ast-graph plugin, Gemini 4 Argon used the code graph in 12 of 17 sessions. Claude Opus 5.5 used it in 4 of 17, and ran grep and sed in bash instead.

I built ast-graph (code on GitHub) as part of fixing my own workflow, because I found the agent just scanning thousands of lines of code, being slow, and inefficient. Every couple days I check how it's used across my sessions to find bugs, and on the morning of November 10 I pulled the logs for every session since it went live on November 3 (32 sessions, 5,426 steps). Of those 32, 15 ran only on Opus, 15 ran only on Argon, and 2 switched models partway. Those two count once for each model, which is why the table shows 17 sessions per model.

The plugin's hooks kept the graph index fresh on every edit (hundreds of sync runs in the busiest repos), so the graph was always there to use.

The numbers across 32 sessions

Metric (Nov 3 to Nov 10)Claude Opus 5.5 (17 sessions)Gemini 4 Argon (17 sessions)
Planner steps analyzed3,2832,143
Sessions with at least 1 ast-graph query4 / 17 (23.5%)12 / 17 (70.6%)
Sessions with more than 1 ast-graph query1 / 17 (5.9%)11 / 17 (64.7%)
Canonical ast-graph MCP or plugin CLI calls396
Repo local npm run ast:* CLI commands (FreightFloor)2611
Lazy MCP schema reads (mcp/ast-graph/*.json)038
Shell commands using grep, rg, or find1,555161
Shell commands using sed -n, head, tail, or cat1,51750
read_file calls (of which unbounded or over 250 lines)787 (237, 30.1%)1,575 (340, 21.6%)

Two notes help read the bottom rows. Compound pipelines (grep ... && sed -n ...) count in both shell rows. And Argon's read_file count is higher (1,575 vs. 787) because Argon read files through read_file (50 shell slices), while Opus did most of its file slicing in bash (1,517 sed, head, tail, or cat commands).

In one of my repos, when I pulled the logs, the graph's telemetry table had 25 queries recorded (each batched search term or outlined file counts as one). Two long running Opus sessions (853 combined steps) accounted for 2 of those queries while running 317 grep commands and 343 sed or cat commands.

The first 13 steps of one Argon session accounted for the other 23.

Flow diagram comparing Argon's schema-first graph lookups against Opus's bash pipelines and CLI path.

What we saw from Argon: schema first, then bounded reads

With ast-graph available, Argon followed the tool contract step by step.

In that Argon session, it started by reading ast_search.json and ast_assess.json so it knew how to call the tools. On the next turn, it called ast_assess and batched 7 search terms into ast_search. Then it read the ast_outline schema and batched 7 files into one ast_outline call.

After that, it issued up to 6 parallel read_file calls per turn with exact StartLine and EndLine spans, and only reached for rg and grep to find string literals that aren't in the symbol table. Across 17 sessions it ran only 161 shell commands with grep, rg, or find (7.5 per 100 steps).

What we saw from Opus: bash first

Opus went straight to bash.

Antigravity loads MCP tool schemas on demand to keep startup context small. To call ast_outline, the model reads the tool's schema file first, then calls the tool on the next turn.

Across 3,283 steps, Opus read an ast-graph schema file 0 times. AGENTS.md mentioned the plugin CLI path (dist/cli.js) without subcommand examples, and Opus tried it only 3 times across 3 sessions (1 call each).

Instead, it packed several searches into each shell command. Across its 17 sessions, 71.3% of Opus shell commands (1,552 of 2,178) chained three or more commands with && or ; in a single turn.

Here is what that looked like in the logs:

  • Early in one session it ran grep -rn -iE "in_scope|out_of_scope|inScope|outOfScope|scope" across the apps, packages, and docs folders, then a few steps later chained cat, wc -l apps/api/src/*.ts, and ls into one bash call.
  • Instead of ast_outline, it wrote regex outlines in bash: grep -n "function .Player\|interface .Store\|class .*Store" apps/lobby/src/index.ts.
  • Instead of calling read_file with StartLine and EndLine, it chained sed -n slices in one command (sed -n 220,226p packages/protocol/src/index.ts; sed -n 36,75p tools/sprites/src/index.ts).

Why does Opus do this?

The logs can't answer that. These weren't matched tasks. Each session was whatever I was working on that day. So they show how Opus searched, not why.

What they do show is what the bash path gets it. One pipeline searches symbol names, string literals, SQL columns, and UI copy in the same turn. No schema to read first. For quick edits, that is genuinely fast. My guess is that Opus leans on bash because that's where it does most of its work in other harnesses. That's a hypothesis. A same task, same repo, same commit run on each model would test it.

The cost shows up on longer sessions. On one project, Opus ran grep against App.tsx in 8 sessions (71 times in one of them) and against db.ts up to 42 times in a session, instead of asking the graph once (1,555 grep commands and 1,517 sed or cat reads across 17 sessions). Blind sed -n line slices cut mid function and miss callers or covering tests, so as context fills up, the agent keeps re-grepping the same big files to reorient itself.

Where Opus used the graph: a one line npm script

There was one exception in the logs: FreightFloor.

In FreightFloor, package.json had one line CLI scripts (ast:query and ast:analyze calling tools/ast-sidecar/dist/cli.js).

Those scripts lived right inside package.json, which Opus already reads at the start of a session. It could call the graph from bash with no schema to look up first, and it called the graph in 26 commands in a single session (8 ast:query lookups and 18 ast:analyze runs to check for circular dependencies). On Step 16, it queried four symbols in one shot (startDriverRun, upsertPlayerStats, dealHand, generateDriverCallsign).

It piped the result through grep and head to keep only the target summaries. On the next step, Opus made 4 bounded read_file calls (engine.ts:5700-5811, engine.ts:764-784, server.ts:825-880, persistence.ts:55-110) across 2 packages, with no round of grep in between.

This lines up with what Armin Ronacher wrote about coding agents. When an agent has a terminal, you can often skip a custom MCP wrapper and give it a script or Makefile target instead.

What the logs caught inside ast-graph

Looking at the Argon and Opus traces side by side also exposed four bugs in my own plugin:

  • Batch budget starvation: Argon passed 7 files to ast_outline in one batch. Dividing the 3.8 KB budget by 7 left about 540 bytes per file, which cut the 29 symbol outline for auth.ts down to its header and forced an extra read of the overflow file.
  • Giant wrapper recommendations: in one repo's apps/api/src/app.ts, createApp spans lines 46 to 3355. ast_outline recommended StartLine=46, EndLine=3355, violating our own 250 line rule (and inflating Argon's over 250 line read_file count in the table).
  • Ranking noise: CSS rules (StylesheetSection in styles.css) and HTML mockups (docs/planning/mockup-v4.html) outranked real TypeScript functions in apps/ and packages/.
  • Missing inline signatures: rules/AGENTS.md named the tools (ast_outline, ast_search, ast_symbol), but omitted the exact call_mcp_tool JSON keys and CLI subcommands. Opus skipped them rather than paying the schema read turn.

We patched all four on November 10.

Multi file outlines now cap at 30 symbols per file so 7 file batches keep their spans inline. When a wrapper spans over 250 lines, ast_outline points to the first bounded inner function instead. Real code in src/, apps/, and packages/ now ranks ahead of CSS, docs, and mockups. And AGENTS.md puts the exact call_mcp_tool JSON and one line CLI commands inline, while explicitly banning sed -n file slicing.

What changed after the fix

In the Opus sessions since the fix (9 sessions, about 940 steps), Opus called the graph in 4 sessions, 9 calls in total. It still read the schema 0 times. It didn't need to. The inline call syntax in AGENTS.md covered it.

That's about 1.0 graph call per 100 steps, up from 0.1 before the fix outside FreightFloor (Argon sat at 4.5 per 100 steps).

But Opus still searches primarily with bash. It ran 39 grep commands per 100 steps (47 before the fix) and 43 sed or cat commands (46 before). My second laptop shows the same shape: graph calls in 3 of its first 4 Opus sessions, with grep and sed about where they were.

The inline syntax got Opus to try the graph. Bash is still where it does its searching.

What I'm taking from this

Models have different default habits, even in the same harness under the same rules. Argon paid the schema read turn and followed the MCP contract. Opus stayed in bash.

Removing tool friction helped, up to a point. Putting one line CLI and MCP call syntax in AGENTS.md lifted Opus 10x off zero (0.1 to 1.0 calls per 100 steps). Putting ast:query and ast:analyze inside package.json worked even better because package.json is already part of how Opus explores a repo. Even so, a rule in AGENTS.md didn't stop Opus from running grep and sed 40 times per 100 steps. If a check needs to run every time across models, wire it into repo scripts, hooks, or CI. Prompt rules alone won't override how a model likes to work.

The other lesson is to check the session logs on both sides. Without pulling transcripts, I wouldn't have seen Opus skipping lazy MCP schemas, and I wouldn't have caught ast-graph clipping Argon's 7 file batches or recommending a 3,300 line wrapper read. A model following your rules doesn't mean your tool is returning good output.

Have you seen Claude and Gemini behave differently under the same rules? Let me know in the comments!

← All essays Browse all 24 essays Older essay → Your coding agent is reading too much code

Get new posts by email

I send new essays by email through Substack. Subscribe there and they'll land in your inbox.

Subscribe on Substack ↗
About · Subscribe on Substack · RSS · Privacy ·
Ask

Social card and structured data

The share image, feeds and Schema.org JSON-LD that search engines and AI tools read for this page.

Social card

Editorial illustration contrasting a structured code graph path and a shell pipeline path converging on the same codebase.
Card URL: /og/opus-vs-argon-how-models-search-code.svg

Machine feeds

/llms.txt /llms-full.txt /sitemap.xml /api/agent/spec

Structured data

{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "Person",
      "@id": "https://davenporter.com/#jason-davenport",
      "name": "Jason Davenport",
      "alternateName": "@davenportjw",
      "jobTitle": "AI & Distributed Systems Architect",
      "description": "Exploring agent-first source control (cosm), trajectory-to-lineage observability, Spanner-backed agent memory consolidation (Electric Sheep), hybrid local/cloud LLM routing, and real-time multiplayer browser simulations on Google Cloud Run.",
      "url": "https://davenporter.com",
      "sameAs": [
        "https://davenporter.substack.com",
        "https://www.linkedin.com/in/davenportjw",
        "https://github.com/davenportjw",
        "https://x.com/davenportjw",
        "https://medium.com/@davenportjw"
      ]
    },
    {
      "@type": "WebSite",
      "@id": "https://davenporter.com/#website",
      "url": "https://davenporter.com",
      "name": "The Davenporter",
      "description": "Learnings about software, technology, agentic systems, and occasionally home renovation.",
      "publisher": {
        "@id": "https://davenporter.com/#jason-davenport"
      },
      "inLanguage": "en-US"
    },
    {
      "@type": "ImageObject",
      "@id": "https://davenporter.com/writings/opus-vs-argon-how-models-search-code#primaryimage",
      "url": "https://davenporter.com/static/images/essays/opus-vs-argon-how-models-search-code/og-opus-vs-argon-search-1200x630.png",
      "contentUrl": "https://davenporter.com/static/images/essays/opus-vs-argon-how-models-search-code/og-opus-vs-argon-search-1200x630.png",
      "width": 1200,
      "height": 630,
      "caption": "Editorial illustration contrasting a structured code graph path and a shell pipeline path converging on the same codebase.",
      "representativeOfPage": true,
      "creator": {
        "@id": "https://davenporter.com/#jason-davenport"
      },
      "license": "https://creativecommons.org/licenses/by/4.0/",
      "acquireLicensePage": "https://davenporter.com/writings"
    },
    {
      "@type": "WebPage",
      "@id": "https://davenporter.com/writings/opus-vs-argon-how-models-search-code#webpage",
      "url": "https://davenporter.com/writings/opus-vs-argon-how-models-search-code",
      "name": "Same harness, same rules, different habits: Opus vs. Argon in Antigravity | The Davenporter",
      "description": "Why Claude Opus 5.5 and Gemini 4 Argon used the same code graph plugin so differently in Antigravity. Argon read each tool's schema and queried the graph. Opus stayed in bash with zero schema reads, used the graph heavily when a repo wired it into package.json, and still defaulted to grep after AGENTS.md added one line call syntax.",
      "isPartOf": {
        "@id": "https://davenporter.com/#website"
      },
      "about": {
        "@id": "https://davenporter.com/#jason-davenport"
      },
      "primaryImageOfPage": {
        "@id": "https://davenporter.com/writings/opus-vs-argon-how-models-search-code#primaryimage"
      },
      "inLanguage": "en-US"
    },
    {
      "@type": "FAQPage",
      "@id": "https://davenporter.com/writings/opus-vs-argon-how-models-search-code#faq",
      "mainEntity": [
        {
          "@type": "Question",
          "name": "What is \u201cSame harness, same rules, different habits: Opus vs. Argon in Antigravity\u201d about?",
          "acceptedAnswer": {
            "@type": "Answer",
            "text": "Why Claude Opus 5.5 and Gemini 4 Argon used the same code graph plugin so differently in Antigravity. Argon read each tool's schema and queried the graph. Opus stayed in bash with zero schema reads, used the graph heavily when a repo wired it into package.json, and still defaulted to grep after AGENTS.md added one line call syntax."
          }
        }
      ]
    },
    {
      "@type": "BlogPosting",
      "@id": "https://davenporter.com/writings/opus-vs-argon-how-models-search-code#article",
      "mainEntityOfPage": {
        "@id": "https://davenporter.com/writings/opus-vs-argon-how-models-search-code#webpage",
        "url": "https://davenporter.com/writings/opus-vs-argon-how-models-search-code"
      },
      "headline": "Same harness, same rules, different habits: Opus vs. Argon in Antigravity",
      "alternativeHeadline": "Why Claude Opus 5.5 and Gemini 4 Argon used the same code graph plugin so differently in Antigravity.",
      "description": "Why Claude Opus 5.5 and Gemini 4 Argon used the same code graph plugin so differently in Antigravity. Argon read each tool's schema and queried the graph. Opus stayed in bash with zero schema reads, used the graph heavily when a repo wired it into package.json, and still defaulted to grep after AGENTS.md added one line call syntax.",
      "datePublished": "2026-11-11T16:00:00Z",
      "dateModified": "2026-11-11T16:00:00Z",
      "wordCount": 1692,
      "keywords": "Agent Engineering, Developer Workflow, Developer Tools, Open Source",
      "author": {
        "@id": "https://davenporter.com/#jason-davenport"
      },
      "publisher": {
        "@id": "https://davenporter.com/#jason-davenport"
      },
      "image": {
        "@id": "https://davenporter.com/writings/opus-vs-argon-how-models-search-code#primaryimage"
      },
      "url": "https://davenporter.com/writings/opus-vs-argon-how-models-search-code"
    },
    {
      "@type": "BreadcrumbList",
      "@id": "https://davenporter.com/writings/opus-vs-argon-how-models-search-code#breadcrumb",
      "itemListElement": [
        {
          "@type": "ListItem",
          "position": 1,
          "name": "Home",
          "item": "https://davenporter.com/"
        },
        {
          "@type": "ListItem",
          "position": 2,
          "name": "Essays",
          "item": "https://davenporter.com/writings"
        },
        {
          "@type": "ListItem",
          "position": 3,
          "name": "Same harness, same rules, different habits: Opus vs. Argon in Antigravity",
          "item": "https://davenporter.com/writings/opus-vs-argon-how-models-search-code"
        }
      ]
    }
  ]
}

Ask The Davenporter

Ask anything about the essays and builds on this site.