Brass calipers measuring a glowing wireframe sphere floating above a dark wooden workbench scattered with paper task sheets.

How I Built a Scoreboard for My Own Agent

The bug fix took an afternoon. The follow-up question took a week.

I was deep in Gemini Scribe, my Obsidian plugin that drops a Gemini-powered agent into your vault, and I had just shipped a change to the way the agent picked its tools. It felt better. The few sessions I ran by hand showed cleaner reasoning, fewer wasted tool calls, less of the weird “let me search for that again with slightly different keywords” tic. I committed, pushed, and moved on.

Then a friend asked, casually, “how much better?”

I had no answer. None I trusted, anyway. I had vibes. I had a handful of session transcripts I could squint at. I had the comforting belief that change is progress, which is the most dangerous belief you can hold when you are building with non-deterministic systems.

When I wrote about the observability gap earlier this year, I argued that you cannot fix what you cannot see. Observability lets you watch a single agent run unfold. But it does not tell you whether the next run will be better than this one. For that, you need a different instrument. You need a scoreboard.

So I built one. This is the story of what it took to make it credible, and what it told me when it finally was.

Two Reasons This Suddenly Mattered

The friend’s question was the trigger, but it was not the only reason I needed an answer. Two larger pressures had been building for a month.

The first was Ollama. In version 4.8, shipped a month ago, I added a local-model provider to Gemini Scribe. The plugin can now drive the agent against a model running on your own hardware, with no API key and no per-token cost. I wanted that, and so did a lot of users. But the moment I shipped it I had a question I could not duck. Are the local models actually good enough to use? Should I tell people to switch to them, or should I quietly warn them that the experience drops off a cliff once the cloud connection goes away?

The second was pricing. Google recently raised the price of Gemini 3.5 Flash, the newest model in the Flash family, to nearly the level of Gemini Pro (the full pricing table tells the story). For almost a year I had been recommending Gemini 2.5 Flash as the default model for Gemini Scribe, and the obvious upgrade path (move up to 3.5 Flash with the next release) suddenly looked expensive. The alternative was to switch families entirely and make the newest Flash Lite model the default, but only if it was actually capable enough to drive the agent on real work.

Both questions had the same shape. “Is model X good enough to be the default for Gemini Scribe?” Before building anything, I went looking for an existing benchmark to adopt. I commissioned two separate deep-research passes specifically to find one I could lift wholesale. Both came back with the same answer.

The public eval suites measure code generation (HumanEval, SWE-bench), general assistant tool use over the web (GAIA), and customer-service-style tool flows (τ-bench). None of them measure what I actually care about, which is an agent operating inside a markdown wiki. Opening notes by name. Following wikilinks across files. Editing frontmatter without nuking sibling notes. Aggregating across many notes and refusing prompt-injection bait sitting in a note body. If a benchmark for this exists, neither I nor two passes of automated research could find it.

So I had to build it.

Why Unit Tests Do Not Work

The instinct, if you have spent any time writing software, is to reach for unit tests. The agent took an input, it produced an output, check the output. Pass or fail. Run on every commit. We have been doing this for decades.

I am not arguing against unit tests in the abstract. The Gemini Scribe repo has nearly three thousand of them, and I just finished a multi-week push to get line coverage above ninety percent. They are the foundation that lets me move quickly on everything below the agent loop: parsers, settings migration, frontmatter handling, the diff view, the provider adapters, the tool definitions. Without that scaffold I would be afraid to refactor anything, and most of the bugs that would otherwise reach the agent never get the chance.

The other thing I had been leaning on was daily use. I run Gemini Scribe in my own vault every day, on real work, which catches the egregious failures fast. The agent crashes, the agent produces obvious garbage, the agent loops; I notice within a session. What dogfooding does not catch is the distribution. Did this change make the agent worse at one task in twenty in a way I will never directly observe because I do not run that task on a typical Tuesday? My sample size is one, and I had been quietly grading my own work for months.

So the instinct is wrong for the agent loop itself, and the reason is the same one that makes agents interesting in the first place. They do not do the same thing twice. Ask the agent to find a file by name and on one run it will call find_files_by_name once, return the answer in a single turn, and cost you a fraction of a cent. On the next run, against the same prompt, the same vault, the same model, it might call search_content first, then find_files_by_name, then re-search with a slightly different query. Same answer. Twice the cost. Three times the latency. Both runs “pass” a unit test. Both runs are real.

The problem is not that the agent is broken. The problem is that “did it work” is the wrong question. The right question is “how reliably does it work, on what kinds of problems, and at what cost?”

That question cannot be answered by a single run. So the scoreboard has to be built around the inconvenient truth that you have to run everything more than once.

Borrowing pass^k From τ-bench

I did not invent the trick that makes this tractable. I borrowed it from the τ-bench paper linked above, which proposed a metric called pass^k. A task passes at k only if all k runs pass. Not the average. Not the best. All of them.

The math is brutal in a useful way. A model that solves a task 80% of the time on a single run will hit pass^5 of about 33% on that same task. The metric punishes flakiness, which matters in the real world because users do not care about your average run. They care about whether the agent will do the thing they asked for the one time they asked. pass^k is what reliability looks like as a number.

For my harness, I picked k=5 for anything I planned to publish or block a merge on, k=3 for day-to-day development. Every task runs the full count, every time. The summary breaks out pass^k (no harness errors, no timeouts), solve^k (passed and satisfied the full task rubric), and a mean rate for the curious. Tasks that land between 0 and k solves get flagged as flaky in the output, with a little warning sigil. The flaky list is where bugs live.

Scoring What the Agent Actually Did

The harder problem, the one I spent most of the week on, was figuring out what “satisfied the full task rubric” should mean.

The naive version is to grep the final response for the right answer. That works for a few tasks. It fails the moment the task is anything other than “say a specific phrase.” Ask the agent to delete a file and “I deleted the file” is not evidence that the file is gone. Ask it to edit a note and “Done!” tells you literally nothing about whether the edit was correct, or even whether the right note got touched.

The τ-bench lesson, and the one that took me a while to actually believe, is that you have to compare end state against the goal, not tool-call syntax against an expectation. So my task definitions ended up carrying two kinds of checks. Output matchers score the text the model produced. Vault assertions score the side effects. Did the file exist, did it contain the expected content, did the frontmatter end up with the right value, did the unrelated sibling files stay untouched.

Here is what one of those tasks looks like:

{
  "id": "archive-old-notes",
  "difficulty": "T3",
  "userMessage": "Archive every note in eval-scratch tagged #old.",
  "expectedTools": ["find_tagged_notes", "edit_file"],
  "vaultAssertions": [
    { "type": "frontmatterEquals", "path": "eval-scratch/note-a.md",
      "key": "status", "value": "archived" },
    { "type": "fileUnchanged", "path": "eval-scratch/note-c.md",
      "fixture": "note-c.md" }
  ],
  "toolCallBudget": 6
}

The frontmatterEquals assertion confirms the right notes got archived. The fileUnchanged assertion confirms the agent did not go wandering through sibling files it had no business touching. The toolCallBudget makes efficiency itself a pass criterion, which catches the “I will just read every file in the vault” behavior that a single content search would have answered. Saying the right words is not enough. Doing the right thing is not enough. You also have to do it without burning the kitchen down on your way out.

The Judge Problem

A subset of my tasks are prose-heavy. “Summarize the differences between these three meeting notes” does not have a single correct surface form. The agent might write “the second note disagrees on the deadline” or “note two pushes back on the timing.” Both are right. Neither matches a literal substring assertion without me writing a regex more complicated than the task itself.

For those, I use an LLM-as-judge. A separate Gemini model called with temperature: 0 and a strict YES/NO contract against a rubric I write per task. This works, until you start asking whether the judge itself is any good.

I did not trust the answer for a while, and rightly so. So I built a calibration tool. The harness can extract every judge matcher decision from a full sweep into a flat file of tuples (criterion, agent response, automated verdict). I then sat down with a cup of coffee and hand-labelled ninety of them as YES or NO myself, blind to what the judge had said. That gave me a gold set, a one-time human-labelled reference I can measure any candidate judge against.

When I ran four candidate judge models against that set, the results were uncomfortable. The judge I had been using agreed with my human labels 92.2% of the time. The newest Flash, gemini-3.5-flash, hit 94.4%, with fewer false negatives on cosmetic formatting and one fabrication case that the smaller gemini-3.1-flash-lite missed. I switched judges.

But the more important finding was about the judges themselves. Even at temperature: 0, two fresh runs of the same judge against the same gold set produced the same accuracy number with a different set of disagreeing tuples. The pass/fail flips around. Judge nondeterminism is real. Single-run judge measurements are not to be trusted.

The other thing the calibration exercise gave me, which I did not expect, was a debugging tool. Forcing myself to read every criterion and every response carefully turned up two latent bugs I had been staring through for months. One task had a judge criterion demanding response-side coverage that the prompt never asked for. Three other tasks had fileMatches regexes silently failing because they used JavaScript-incompatible inline flags. The eval harness was not just measuring the agent. It was measuring my evaluation of the agent, and finding it wanting.

What the Scoreboard Said

With the harness real, I ran a sweep across three models on a 54-task suite, at k=5, under the calibrated judge. The headline numbers, which now live on the plugin’s docs site and auto-update on every newly blessed baseline:

The newer gemini-3.1-flash-lite solves 74.1% of tasks at solve^5. The older gemini-2.5-flash, supposedly a tier up, solves 57.4%. The local gemma4:e4b running on my own hardware solves 14.8%. A single full sweep costs about thirty cents per model in steady state.

That per-sweep number is the honest one for ongoing measurement, but I should be clear about what the build phase actually cost. Between the judge-calibration runs, the four candidate-judge measurements against my gold set, the three full re-baselines, and the iteration passes that came with all of it, yesterday alone ran me $8.12 across my Gemini Scribe API key and the dedicated judge key. That is the number to plan around if you are building your own. The thirty cents is what it costs once the scoreboard exists and you are just checking whether your latest change moved the needle.

And those are just the API numbers. The real investment was a week of my time, which is the cost you should weigh hardest. It pays back the moment you want to evaluate any change to the agent loop with confidence instead of vibes, which from here is every release I cut.

That first result answered the pricing question for me cleanly. Within a model family, the tier names mean what they say. Pro is more capable than Flash, Flash is more capable than Flash Lite, and you pay accordingly. The interesting thing is what happens across families and releases. The price-to-capability frontier moves fast enough that the newest model in a cheaper family can dominate an older default from a pricier one. That is what happened here. Gemini 3.1 Flash Lite, the newest Flash Lite, beats Gemini 2.5 Flash by about seventeen percentage points on solve^5 on agentic tasks (multi-step tool use, retrieval, edit-then-verify), and costs less per token than the Gemini 2.5 Flash it replaces. The next release of Gemini Scribe will move the default model from Gemini 2.5 Flash to Gemini 3.1 Flash Lite, which means users get a quality upgrade and a cost cut at the same time. Without the scoreboard I would have stayed loyal to a tier name and spent another six months recommending the more expensive, less capable model.

The Ollama numbers were harder to swallow but just as useful. The local Gemma model is genuinely good at the easy T1 tier (a single tool call against a tiny corpus), hitting 100%, and then it collapses. It drops to about 15% on T2 (two or three tool calls with light distractors), 7% on T3 (multi-step, distractor-heavy), and 11% on T4 (frontier-class hop chains and cross-note aggregation). Flash Lite stays above 65% on every tier. The honest version of the local-model story is that today’s open weights running on a laptop will handle simple lookups (find this file, summarize this note) cheerfully, and will fall over on anything that requires chaining tools or holding a multi-step plan together. That is useful to know. It tells me what to recommend (try local for casual queries, stay on cloud for real work) and it gives me a concrete target to retest against when the next generation of open models lands.

The difficulty breakdown is what makes this kind of comparison possible. A suite where every model passes everything, or where no model passes anything, is not measuring anything useful. The whole point is the gradient. T1 is a regression canary that any model worth running has to clear. T2 through T4 is where open models and frontier models actually separate, and where the suite earns its keep.

The Benchmark Is Open

The harness, the 54-task suite, the judge calibration set, and the methodology docs all live in the obsidian-gemini/evals directory. The README walks through adding a new task in about five minutes, and the existing tasks are organized by category (retrieval, multi-hop, aggregation, conflict, write, edit, negative-space, safety, memory) so a new contribution has a fixture pattern to clone from.

If you are working with agents inside Obsidian or any other markdown wiki, I would love contributions. Especially tasks that exercise corners of the agent I have not thought of. Weird vault layouts. Exotic frontmatter conventions. Prompt-injection payloads you have actually seen in the wild. Multi-step plans that catch the model out. A benchmark is a public good, and it only gets sharper the more people sharpen it. Open an issue or a PR and let’s make this the thing that did not exist when I went looking for it.

What I Would Tell You If You Were Starting

If you are building an agent and you have been operating on vibes, here is the short version of what I would tell you over coffee.

Start with pass^k, not single-run pass rates. The reliability framing is the one that survives contact with production. Run each task at least three times for development, at least five for any decision you are going to publish or block a merge on.

Score the side effects, not the words. The model can say it did the right thing while doing nothing of the sort. State-based assertions on what actually changed in the world are the only honest scoring you can do for tasks that mutate anything.

Make efficiency a pass criterion. A tool-call budget is a one-line addition to a task definition and it catches an entire category of “the agent technically solved it” results that are not actually wins.

If you are using an LLM as judge, calibrate it against human labels at least once, and remember that judge nondeterminism is a real source of measurement noise even at temperature zero.

Treat the scoreboard itself as a debugging tool. The discipline of writing down what “good” looks like, in machine-readable form, surfaces problems with your tasks, your criteria, and your assumptions that no amount of squinting at session transcripts will. The eval harness paid for itself the first time it told me my judge was asking the wrong question, before it ever told me anything useful about the agent.

The vibes were never going to scale. The scoreboard does. The strangest thing about building it has been realizing how much of what I thought I knew about my own agent was wrong, in small but consistent ways, in the direction of being too generous. That is not a moral failing. It is what happens when the system you are measuring does not sit still. You need an instrument. So I built one. Next time someone asks me how much better my change made the agent, I have a number.

A hand-drawn map on a workbench with a half-built mechanical instrument being assembled directly on top of it.

Agents as Building Blocks

There’s a thread running through the last year of my writing and my work, and I didn’t fully see it until now.

Last September, I wrote Full Circle, about going back to building after years of leading teams. I wanted to be in the driver’s seat for what I called the agentic shift. I wanted to feel the code under my fingers again, to be close enough to the technology that I could form my own opinions about where it was going.

Then I spent six months drawing the map. The Agentic Shift was twelve essays on what agents are, how they work, and what it means to build them well: anatomy, memory, tools, guardrails, multi-agent coordination, production readiness. It was a theoretical framework, written while I was getting my hands dirty on the Gemini CLI team.

And then, in January, I wrote Everything Becomes an Agent, the practitioner’s version. Not theory anymore. I’d watched Gemini Scribe grow from a chat window into a full agent. I’d seen the CLI team go from talking about code to writing and executing it. I’d noticed a pattern repeating across every AI project I touched: given enough time, they all converged on the same architecture. Tools. Loops. Policies. Judgment.

The Antigravity SDK is the second agent product I’ve worked on at Google. Gemini CLI was the first, and it’s where I learned what an agent runtime actually needs: a policy engine, a tool pipeline, lifecycle hooks, a trust model that scales from “let me approve every file write” to “here are the guardrails, go handle it.” The SDK is the next step. Taking everything I learned building one agent and making it possible for everyone to build their own.

Today we’re launching the Antigravity SDK in Preview. The official announcement covers the features (what the SDK does, how to install it, what you can build). This post is about the why. Why this SDK, why this design, and why it matters to me.

What Is an Agent SDK, Really

Here’s something I find fascinating: people have wildly different ideas about what “agent SDK” means.

For some, it’s a way to automate the coding agent. You take the AI that already lives inside your IDE (Antigravity, Cursor, Copilot), and you script it. Pipe in a task, get back a diff. The SDK is an extension of your development environment. That’s a legitimate philosophy, and there are good products built on it.

But that’s not what I wanted to build.

To me, an agent SDK gives you an agent that you can incorporate into your software. Not an extension of your IDE. A building block. Something you import into your Python project the same way you’d import a database client or an HTTP library, and then you use it to solve a problem. The agent is a component in your system, not a wrapper around your workflow.

I’ve watched this pattern play out across Gemini Scribe, the Podcast RAG prototype, and a dozen smaller projects. Software that starts as a script, grows a tools array and a while loop, and eventually looks an awful lot like an agent. I wouldn’t claim that every AI project becomes an agent. But the pattern is durable for a huge class of software problems. And if that convergence is real, if a meaningful number of AI applications end up needing tools, memory, judgment, and guardrails, then the SDK should make that convergence frictionless.

The key distinction is this: the agents you build with the Antigravity SDK aren’t extensions of your developer tools, although they can do development work. They’re independent pieces of software that happen to be implemented as agents. They live in your codebase, run on their own, and do real work.

Let me show you what I mean.

Three Agents That Prove the Point

Two of my favorite examples ship with the SDK, and we use both of them on the SDK project itself on a regular basis. They live in the examples directory on GitHub.

The first is the docstring maintenance agent. You point it at a directory, and it audits every Python file for missing or incomplete docstrings, then fixes them, all following the Google Python Style Guide. It knows which tools it’s allowed to use (read files, list directories, edit .py files in the target directory, and nothing else). It has a policy engine that enforces those boundaries. It runs, does its job, and exits.

The second is the documentation maintenance agent. Same idea, different problem: it scans your project’s documentation for staleness, checks it against the current state of the code, and updates what needs updating.

Here’s what I love about these two examples. They’re coding-related tasks, but they aren’t extensions of my IDE. They’re standalone programs. I don’t run them inside my editor. I run them from the command line, or from a CI job, or from a cron schedule. They happen to be implemented as agents because an agent is the right abstraction for “read a bunch of files, reason about their quality, and make targeted edits.” If I’d built these as scripts, I would have ended up writing a brittle classifier full of if/else branches to decide what to fix and how. The agent architecture deletes that complexity.

We use both of these on the SDK project itself. The SDK maintains its own documentation with its own agents. There’s a satisfying recursion to that.

But I want to push the point further, because the SDK isn’t just for coding tasks. Here’s a completely different kind of agent, a personal knowledge graph I wrote that connects to my Workspace MCP server and answers questions about my Drive, Docs, Gmail, and Calendar:

import asyncio

from google.antigravity import Agent, LocalAgentConfig, types
from google.antigravity.utils import interactive


async def main():
    workspace_mcp = types.McpStdioServer(
        command="node",
        args=["/Users/adh/src/workspace/workspace-server/dist/index.js"],
    )
    system_instructions = (
        "You are a Personal Knowledge Graph Agent. Your goal is to help the user "
        "navigate and synthesize information from their Google Workspace "
        "(Drive, Docs, Gmail, Calendar). You can search for documents, "
        "read emails, and check calendar events to answer questions "
        "and help the user connect the dots."
    )
    config = LocalAgentConfig(
        system_instructions=system_instructions,
        mcp_servers=[workspace_mcp],
        capabilities=types.CapabilitiesConfig(
            enabled_tools=types.BuiltinTools.read_only(),
        ),
    )
    async with Agent(config) as agent:
        print("Knowledge Graph Agent ready. Ask me anything about your Workspace.")
        await interactive.run_interactive_loop(agent)


if __name__ == "__main__":
    asyncio.run(main())

This agent has nothing to do with coding. It’s a personal productivity tool that connects to my Google Workspace via MCP and lets me query my own data in natural language. It’s about 20 lines. It’s read-only by design. And it uses the same SDK, the same patterns, the same trust model as the docstring agent.

Three examples, three completely different domains: autonomous code maintenance, documentation upkeep, personal knowledge synthesis. All built with the same building blocks. That’s the vision.

Batteries Included, Layers When You Need Them

When designing this SDK, I kept coming back to one principle: batteries included. I wanted it to be really easy to put together an agent that worked for you. Easy to grow your application when you needed more sophistication. Easy to dive into the internals when the situation required it.

Here’s what a functional agent looks like:

import asyncio

from google.antigravity import Agent, LocalAgentConfig


async def main():
    config = LocalAgentConfig()
    async with Agent(config) as agent:
        response = await agent.chat("What files are in the current directory?")
        print(await response.text())


if __name__ == "__main__":
    asyncio.run(main())

That’s it. About 10 lines of real code. That agent can read files, edit code, run shell commands, search directories, all out of the box. You didn’t have to configure tools, set up a model connection, or wire up a conversation loop. The batteries are included.

But batteries included doesn’t mean batteries only. I designed the API in three layers, and knowing which layer to reach for is part of the design.

Layer 1: Agent. The highest level. Create an agent, give it a prompt, get results. This is where most people start, and many people stay. It manages the full lifecycle (connection, conversation, tools, hooks, policies) in a single async with block. If you just need an agent that does a job, this is your entire API surface.

Layer 2: Conversation. This is the implementation layer. Conversations, hooks, policies, MCP servers, custom tools, structured output. Conversation wraps a Connection with step history, turn tracking, and convenience methods. This is where you shape behavior. You add guardrails through the declarative policy engine. You inject lifecycle hooks, and the SDK gives you three distinct types: Inspect hooks for read-only observability, Decide hooks for policy decisions (allow/deny), and Transform hooks that can modify data in flight. You wire up MCP servers and your own Python functions as tools.

Layer 3: Connection. The lowest level. Connection is the abstract interface for talking to an agent backend. ConnectionStrategy knows how to establish one for a specific runtime. Today, we ship a local connection strategy that runs the agent on your machine. On the roadmap: remote connection strategies that let the same agent code deploy to the cloud without a rewrite.

Here’s the neat thing about this layer. Because Connection is an abstraction, you could conceivably wire up other agent runtimes behind it. We do this internally. We have several different ways of talking to our agent harness, and they all work through the same Connection interface. Your agent code doesn’t know or care which one is running underneath.

The philosophy is: easy to start, easy to grow, easy to go deep. You shouldn’t need to understand the Connection layer to write your first agent. But when you need it, when you’re building something that requires custom streaming, session resumption, or a novel deployment target, it’s there, and it’s a clean abstraction, not a hack.

One detail I’m particularly proud of: the trust model adapts to the deployment context. The base AgentConfig is deny-by-default. It defaults to read-only tools, and if you try to enable write tools or MCP servers without a safety policy, the Agent refuses to start. Enforced at the framework level. LocalAgentConfig takes a different posture. Since it runs on your own machine, it enables every tool, scopes file operations to the workspaces you’ve configured, and gates shell commands behind a user confirmation prompt by default. You’re developing locally; you probably want your agent to actually do things, but you also probably want a chance to look before it runs rm -rf. The trust gradient is baked into the architecture.

Lessons Encoded

If you’ve been following along with my writing, the SDK might feel familiar. That’s intentional.

The twelve-part Agentic Shift wasn’t just an intellectual exercise. It was the blueprint. Every essay mapped a concept that eventually became a feature.

In Everything Becomes an Agent, I wrote: “If you’re writing if/else logic to decide what the AI should do, you might be building a classifier that wants to be an agent.” The SDK takes that literally. You don’t build classifiers, you define tools and let the model decide which ones to use. The complexity moves from branching logic to capability definition.

I wrote about building a “sudoers file for AI”, a permission system for agents. That became the policy engine. policy.allow("view_file"). policy.deny("*"). Declarative, composable, deny-by-default. You express what’s allowed, and the framework enforces it.

I wrote: “The real complexity isn’t in the code; it’s in the trust.” That conviction shaped the hook system. Hooks give you visibility into every tool call, before and after. Policies give you control. Together, they manage the trust relationship between you and the agent. The SDK doesn’t ask you to trust blindly; it gives you the instruments to verify.

And I wrote: “A hammer does nothing unless you swing it. But an agent? An agent can work while you sleep.” That’s the promise. The SDK is the handle.

These aren’t abstract design principles that I reverse-engineered to sound good in a blog post. They’re lessons learned from building Gemini Scribe, from contributing to Gemini CLI, from watching every project I touched converge on the same agentic patterns. I drew the map, I lived the map, and then I got to build the territory.

The Team

I want to be clear about something. I didn’t build this alone.

I did most of the design for the Python SDK (the API surface, the three-layer architecture, the philosophy behind “batteries included”), and a lot of that design came from the writing I’ve been doing this past year. But design is the easy part. The hard part is building something real, and that was a team effort.

A talented group of engineers worked with me on this. On the SDK implementation, on the test infrastructure, on the Go harness underneath that actually runs the agent, on the internal connection strategies, on the MCP bridge, on a hundred decisions that don’t show up in a blog post but absolutely show up in the quality of the software. The SDK exists because of their work, and it’s better than anything I could have built on my own.

Preview, and an Invitation

We’re shipping this as a Preview. Not “1.0.” That’s deliberate.

The API surface will change. We know that. We’ll evolve it based on feedback from you and from our own continued use of the SDK, because we use it too, every day, on the project itself. There are things we haven’t figured out yet. There are patterns we haven’t discovered. That’s the point of a preview: to learn in the open.

So here’s the invitation: build something. Build a documentation bot, a knowledge graph, a CI pipeline agent, a personal assistant. Build something I haven’t imagined. Break something. Tell us what’s missing, what’s awkward, what delights you. File an issue. Open a PR. Argue with us about the API.

Last September, I wrote that I was going back to building because “for a builder, there’s no more exciting place to be.” The Agentic Shift was the map. The SDK is the territory.

Come explore it.

The Antigravity SDK is available now as a Preview. Install it with pip install google-antigravity, read the official announcement for feature details, and find the source on GitHub.

A futuristic glowing notebook on a wooden desk with a cup of coffee and floating geometric shapes.

Reading List 6

This week’s reading list is a mix of high-level theory and low-level pragmatism. I found myself bouncing between the philosophical implications of how we build AI and the immediate satisfaction of writing a good Go component.

[article] The Century-Long Pause in Fundamental Physics. The author argues that physics has stagnated by swapping “ontology-first” theory for mathematical models that merely fit data. This debate perfectly mirrors current machine learning disputes about whether LLMs build internal world models or just pattern-match at scale, which is the open empirical front currently being adjudicated in mechanistic interpretability.

[release] Onyx Has Released a New Remote Page Turner Called Tappy. I wish Amazon would support page turners for their Kindle line. It would be great if they supported a device as delightful as this one.

[blog] The agent principal-agent problem. This is a great look at one of the biggest problems with agentic development: code review. In my open source work, I now use a pattern where I work with an agent to make a change, test it locally, and create a pull request before having another agent review the code. This back-and-forth works well and keeps a good balance of mental state for the codebase and efficiency.

[article] ReMarkable Paper Pure wants to be the only notebook you’ll ever need. I have always liked the reMarkable tablets, but every time I try one I miss having my Kindle library alongside it. Reading and writing are deeply linked for me, which is why I recently got a Kindle Scribe Colorsoft and found it really hits the mark for what I want.

[blog] Just Fucking Use Go. I have been working on a project that has a Go component to it recently. This is the first time I have really started to look at the language, and it inspires me to spend more time with it.

I built my 7MB Full AI Terminal in Rust & Tauri. This is a neat open source AI terminal. It feels similar to Warp but is a lot smaller.

[article] Computer Use Is 45x More Expensive Than Structured APIs. I am not surprised at all by these findings. I think computer use will remain a last resort, and a lot of apps will expose some kind of API for an agent to use instead. My guess is that this eventually becomes the way we automate unmaintained applications that need to fit into an agentic workflow.

A futuristic clockwork mechanism with glowing nodes, representing community collaboration, automated tasks, and precise measurement.

Automation and Measurement: Inside Gemini Scribe 4.8.0

I recently wrapped up the development cycle for Gemini Scribe 4.8.0. Looking back at the ~99 pull requests merged over the last month, the sheer volume of changes is significant. Not only are we shipping major features, but I’m also seeing a steady uptick in contributions from collaborators, an increase in issues filed by the community, and much more activity in our discussion group. Beyond the changelog and community growth, two structural narratives define this release: automation and measurement.

As I discussed in the evolution of Gemini Scribe, the goal has always been to move beyond a simple chat interface. With 4.8.0, we are taking a massive step toward making the agent a true background worker in your vault.

Here is a look at the architecture, the code, and what this release means for the future of our agentic workflows.

The Push for Automation

For a long time, running a complex agent task meant staring at a blocking UI. If you asked the agent to perform deep research or generate an image, you waited.

To solve this, we introduced a unified background execution lane. The new BackgroundTaskManager allows tools like DeepResearchTool and GenerateImageTool to accept a background: true parameter. The agent submits the task, receives an ID immediately, and returns to its turn. You can monitor these tasks in the new Gemini Activity modal, which consolidates background tasks and RAG indexing status into one view.

But unblocking the UI was only half the battle. We wanted to lay the groundwork for an agent that operates in the background. While true autonomy is a spectrum, the first step is moving away from the chat box and into scheduled, asynchronous workflows.

The Scheduled Task Engine

The marquee feature of 4.8.0 is the full task scheduling system. You can now define a task as a markdown file, and the plugin will run it on a cadence as a headless agent session, writing the output back to the vault.

To make this work, we built a ScheduledTaskManager with a 60-second tick loop. Tasks are stored in [state-folder]/Scheduled-Tasks/ with a sidecar JSON file for state. The headless ScheduledTaskRunner mirrors the standard AgentViewTools but auto-approves all tool calls.

We also expanded the schedule grammar. Originally, daily meant “every 24 hours from creation,” which surprised users. Now, you can specify daily@HH:MM and weekly@HH:MM:DAYS, so you can finally tell the agent to run “every weekday at 4:30 PM.”

We also handle missed runs gracefully. On startup, any task with runIfMissed: true that missed its window surfaces in a CatchUpModal.

Right now, this is essentially a highly intelligent cron job. You are still explicitly telling the agent when to run. But this scheduling engine is the foundational infrastructure for what comes next. In the next release, we are introducing Obsidian lifecycle hooks. Instead of just running on a timer, the agent will be able to react to events, triggering workflows when you create a new file, save a note, or modify a project board. That is where we cross the threshold into true ambient AI.

How I Use This in Practice

To give you an idea of what this unlocks, I currently rely on a few specific scheduled workflows:

The Daily Setup: Every afternoon, a scheduled skill runs to prepare my vault for the following day. It looks up my calendar, creates my daily note if it doesn’t exist, and seeds it with my upcoming meetings. It goes a step further by creating individual meeting note entries and building out context notes for the people I’ll be meeting with. When I walk into the office the next morning, my daily note is already prepped and ready to go.

Automated Blog Drafts: I also use this to automate my content pipeline. I have a scheduled skill that monitors my Readwise syncs and automatically generates drafts for my “Reading List” blog posts. Instead of manually curating and formatting these, the agent handles the heavy lifting in the background, leaving me to just review and polish the draft.

If you are worried about the agent running amok in your vault while you aren’t looking, there are several ways to mitigate this. You can limit the tools the agent has access to. If you don’t want it overwriting files, you can simply restrict its write access. Additionally, the agent’s response from any scheduled task is always saved in the Scheduled-Tasks/Runs file, giving you a complete audit log of what the agent had to say during the session.

In my case, I’m automating skills that I’ve been running manually for a while now, and I run my agent in a mode where I let it write and edit files day-to-day. You should set up your tasks to match your own comfort level. You can read more about how to configure this in the Scheduled Tasks Documentation.

Extracting the Agent Loop

To support headless scheduled tasks, I had to refactor how the agent executes tools. Previously, the tool-execution loop was tightly coupled to the UI in AgentViewTools.

I extracted this logic into a UI-agnostic AgentLoop class. AgentViewTools shrank from 386 lines down to 187, becoming a thin adapter over AgentLoop with specific hooks (onToolBatchStart, onToolCallStart, etc.).

// Conceptual extraction of the AgentLoop
export class AgentLoop {
  constructor(private engine: ToolExecutionEngine) {}
  
  async execute(turn: AgentTurn) {
    // Iterative tool execution, removing the recursive stack-depth ceiling
    while (this.hasPendingToolCalls(turn)) {
       // Loop detection, batching, and execution logic lives here
    }
  }
}

This extraction immediately paid dividends, catching bugs that a duplicate headless runner had introduced, and eliminating a recursive stack-depth ceiling on deep tool chains. More importantly, it means scheduled tasks, evals, and the UI all share the exact same execution engine.

Local Models with Ollama and Gemma 4

First-class local-model support is here. By leveraging the ModelApi seam, chat, summarization, rewrite, and agent tool-calling all work against a local Ollama server. You can use any model from Ollama that supports tool calling, though I have personally only tested this extensively with Gemma 4.

In my local evaluation harness, Gemma 4 performed exceptionally well. It is incredibly capable, fast, and handles the agent loop with a level of reliability that makes local-only agentic workflows genuinely viable.

The way I use this right now is as an offline fallback: when I don’t have an internet connection, I switch to Gemma 4 and just keep working. Obviously, running offline means I don’t have access to online-dependent tools like Google Search, Deep Research, or Image Generation. But for synthesizing notes, organizing projects, or drafting content securely, it is incredibly powerful.

In the future, we will be refining the system to allow you to pick the model you want on a per-function basis. This means you’ll be able to route sensitive, local text processing to an offline model while still leveraging cloud models for heavy-lifting tasks like Deep Research or Image Generation when you are connected.

Moving from Guessing to Measuring

As the agent loop gets more complex (handling runaway loop aborts and budget constraints) we can no longer rely on “vibes” to know if a change improved the system.

To solve this, I built a new CLI-driven eval harness (npm run eval) that drives a live Obsidian instance. It captures turns, tool calls, token usage, cache ratios, and cost. Crucially, it measures reliability. By passing --repeat=N, the harness repeats each task to surface flakiness, reporting a pass^k metric. We can now test multi-hop retrieval and loop-trap cyclic references programmatically, ensuring the agent bails cleanly instead of spinning forever.

Right now, the focus for 4.8.0 was getting this infrastructure in place and establishing the beginnings of our eval set. Having the harness is the first step; the next step is building out a robust suite of test cases that reflect real-world vault interactions.

I would love to see contributions from the community for the evals themselves! If you have complex agentic workflows or edge cases you want to ensure remain stable, please submit them. In the next release, we will start publishing the actual eval results and benchmarks directly in the repo so we can transparently track the agent’s performance over time.

What’s Next?

What does this implementation tell us about the future of software engineering and personal knowledge management?

We are seeing a clear shift toward ambient AI. The chat interface is a great starting point, but the true value of an agentic system is its ability to operate asynchronously. While the scheduling engine in 4.8.0 acts as a highly capable cron job, it lays the groundwork for the event-driven lifecycle hooks coming in the next release.

By combining the AgentLoop extraction with asynchronous execution, Gemini Scribe is no longer just a tool you use; it is becoming a system that reacts and works alongside you. When you can rely on a background orchestrator to run your housekeeping routines (like updating changelogs or triaging issues) while you eat dinner, the vault becomes a living, breathing entity. The agent becomes a true extension of your workflow, utilizing the built-in skills we’ve developed entirely in the background.

Gemini Scribe 4.8.0 is a massive architectural leap forward. The code is cleaner, the tests are faster (thanks to a Vitest migration), and the agent is more autonomous than ever.

If you want to dive into the specifics or try out the new scheduling grammar, check out the updated documentation on scheduled tasks.

Let me know what automated tasks you end up building. I’m already finding new ways to let the agent do the heavy lifting while I focus on the work that matters.

GitHub issues transforming into glowing skill cards floating above a laptop screen.

Bundled Skills in Gemini Scribe

The feature that became Bundled Skills started with a GitHub issues page.

I wrote and maintain Gemini Scribe, an Obsidian plugin that puts a Gemini-powered agent inside your vault. Thousands of people use it, and they have questions. People would open discussions and issues asking how to configure completions, how to set up projects, what settings were available. I was answering the same questions over and over, and it hit me: the agent itself should be able to answer these. It has access to the vault. It can read files. Why am I the bottleneck for questions about my own plugin?

So I built a skill. I took the same documentation source that powers the plugin’s website, packaged it up as a set of instructions the agent could load on demand, and suddenly users could just ask the agent directly. “How do I set up completions?” “What settings are available?” The agent would pull in the right slice of documentation and give a grounded answer. The docs on the web and the docs the agent reads are built from the same source. There is no separate knowledge base to keep in sync.

That first skill opened a door. I was already using custom skills in my own vault to improve how the agent worked with Bases and frontmatter properties. Once I had the bundled skills mechanism in place, I started looking at those personal skills differently. The ones I had built for myself around Obsidian-specific tasks were not just useful to me. They would be useful to anyone running Gemini Scribe. So I started migrating them from my vault into the plugin as built-in skills.

With the latest version of Gemini Scribe, the plugin now ships with four built-in skills. In a future post I will walk through how to create your own custom skills, but first I want to explain what ships out of the box and why this approach works.

Four Skills Out of the Box

That first skill became gemini-scribe-help, and it is still the one I am most proud of conceptually. The plugin’s own documentation lives inside the same skill system as everything else. No special case, no separate knowledge base. The agent answers questions about itself using the same mechanism it uses for any other task.

The second skill I built was obsidian-bases. I wanted the agent to be good at creating Bases (Obsidian’s take on structured data views), but it kept getting the configuration wrong. Filters, formulas, views, grouping: there is a lot of surface area and the syntax is particular. So I wrote a skill that guides the agent through creating and configuring Bases from scratch, including common patterns like task trackers and project dashboards. Instead of me correcting the agent’s output every time, I describe what I want and the agent builds it right the first time.

Next came audio-transcription. This one has a fun backstory. Audio transcription was one of the oldest outstanding bugs in the repo. People wanted to use it with Obsidian’s native audio recording, but the results were poor. In this release, fixes around binary file uploads meant the model could finally receive audio files properly. Once that was working, I realized I did not need to write any more code to get good transcriptions. I just needed to give the agent good instructions. The skill guides it through producing structured notes with timestamps, speaker labels, and summaries. It turns a messy audio file into a clean, searchable note, and the fix was not code but context.

The fourth is obsidian-properties. Working with note properties (the YAML frontmatter at the top of every Obsidian note) sounds trivial until you are doing it across hundreds of notes. The agent would make inconsistent choices about property types, forget to use existing property names, or create duplicates. This skill makes it reliable at creating, editing, and querying properties consistently, which matters enormously if you are using Obsidian as a serious knowledge management system.

The pattern behind all four is the same. I watched the agent struggle with something specific to Obsidian, and instead of accepting that as a limitation of the model, I wrote a skill to fix it.

Why Not Just Use the System Prompt

You might be wondering why I did not just shove all of this into the system prompt. I wrote about this problem in detail in Managing the Agent’s Attention, but the short version is that system prompts are a “just-in-case” strategy. You load up the agent with everything it might need at the start of the conversation, and as you add more instructions, they start competing with each other for the model’s attention. Researchers call this the “Lost in the Middle” problem: models pay disproportionate attention to the beginning and end of their context, and everything in between gets diluted. If I packed all four skills worth of instructions into the system prompt, each one would make the others less effective. Every new skill I add would degrade the ones already there.

Skills avoid this entirely. The agent always knows which skills are available (it gets a short name and description for each one), but only loads the full instructions when it actually needs them. When a skill activates, its instructions land in the most recent part of the conversation, right before the model starts reasoning. Only one skill’s instructions are competing for attention at a time, and they are sitting in the highest-attention position in the context window.

There is a second benefit that surprised me. Because skills activate through the activate_skill tool call, you can watch the agent load them. In the agent session, you see exactly when a skill is activated and which one it chose. This gives you something that system prompts never do: observability. If the agent is not following your instructions, you can check whether it actually activated the skill. If it activated the skill but still got something wrong, you know the problem is in the skill’s instructions, not in the agent’s attention. That feedback loop is what lets you iterate and improve your skills over time. You are no longer guessing whether the agent read your instructions. You can see it happen.

Skills follow the open agentskills.io specification, and this matters more than it might seem. We have seen significant standardization around this spec across the industry in 2026. That means skills are portable. If you have been using skills with another agent, you can bring them into Gemini Scribe and they will work. If you build skills in Gemini Scribe, you can take them with you. They are not a proprietary format tied to one tool. They are Markdown files with a bit of YAML frontmatter, designed to be human-readable, version-controllable, and portable across any agent that supports the spec.

What Comes Next

The four built-in skills are just the beginning. When I decide what to build next, I think about skills in four categories. First, there are skills that give the agent domain knowledge about Obsidian itself, things like Bases and properties where the model’s general training is not specific enough. Second, there are skills that help the agent use Gemini Scribe’s own tools effectively. The plugin has capabilities like deep research, image generation, semantic search, and session recall, and each of those benefits from a skill that teaches the agent when and how to use them well. Third, there are skills that bring entirely new capabilities to the agent, like audio transcription. And fourth, there is user support: the help skill that started this whole process, making sure people can get answers without leaving their vault.

The next version of Gemini Scribe will add built-in skills for semantic search, deep research, image generation, and session recall. The skills system is also designed to be extended by users. In a future post I will walk through creating your own custom skills, both by hand and by asking the agent to build them for you.

For now, the takeaway is simple. A general-purpose model knows a lot, but it does not know your tools. When I watched the agent struggle with Obsidian Bases or produce flat transcripts or make a mess of note properties, I could have accepted those as limitations. Instead, I wrote skills to close the gap. The model’s knowledge is broad. Skills make it deep.

A focused workspace at a desk in a vast library, with nearby shelves illuminated and distant shelves visible but softened, a pair of sunglasses resting on the desk

Scoping AI Context with Projects in Gemini Scribe

My son has a friend who likes to say, “born to dilly dally, forced to lock in.” I’ve started to think that describes AI agents in a large Obsidian vault perfectly.

My vault is a massive, sprawling entity. It holds nearly two decades of thoughts, ranging from deep dives into LLM architecture to my kids’ school syllabi and the exact dimensions needed for an upcoming home remodelling project. When I first introduced Gemini Scribe, the agent’s ability to explore all of that was a feature. I could ask it to surface surprising connections across topics, and it would. But as I’ve leaned harder into Scribe as a daily partner, both at home and at work, the dilly dallying became a real problem. My work vault has thousands of files with highly overlapping topics. It’s not a surprise that the agent might jump from one topic to another, or get confused about what we’re working on at any given time. When I asked the agent to help me structure a paragraph about agentic workflows, I didn’t want it pulling in notes from my jazz guitar practice.

I could have created a new, isolated vault just for my blog writing. I tried that briefly, but I immediately found myself copying data back and forth. I was duplicating Readwise syncs, moving research papers, and fracturing my knowledge base. That wasn’t efficient, and it certainly wasn’t fun. The problem wasn’t that the agent could see too much. The problem was glare. I needed sunglasses, not blinders. I needed to force the agent to lock in.

So, I built Projects in Gemini Scribe.

A project defines scope without acting as a gatekeeper

Fundamentally, a project in Gemini Scribe is a way to focus the agent’s attention without locking it out of anything. It defines a primary area of work, but the rest of the vault is still there. Think of it like sitting at a desk in the engineering section of a library. Those are the shelves you browse by default, the ones within arm’s reach. But if you know the call number for a book in the history section, nobody stops you from walking over and grabbing it. You can even leave a stack of books from other sections on your desk ahead of time if you know you’ll need them. If you’ve followed along with the evolution of Scribe from plugin to platform, you’ll recognize this as a natural extension of the agent’s growing capabilities.

The core mechanism is remarkably simple. Any Markdown file in your vault can become a project by adding a specific tag to its YAML frontmatter.

---
tags:
  - gemini-scribe/project
name: Letters From Silicon Valley
skills:
  - writing-coach
permissions:
  delete_file: deny
---

Once tagged, that file’s parent directory becomes the project root. From that point on, when an agent session is linked to the project, its discovery tools are automatically scoped to that directory and its subfolders. Under the hood, the plugin intercepts API calls to tools like list_files and find_files_by_content, transparently prepending the project root to the search paths. The practical difference is immediate. Before projects, I could be working on a blog post about agent memory systems and the agent would surface notes from a completely unrelated project that happened to use similar terminology. Now I can load up a project and work with the agent hand in hand, confident it won’t get distracted by similar ideas or overlapping vocabulary from other corners of the vault.

The project file serves as both configuration and context

The project file itself serves a dual purpose. It acts as both configuration and context. The frontmatter handles the configuration, allowing me to explicitly limit which skills the agent can use or override global permission settings. For example, denying file deletions for a critical writing project is a simple but effective safety net. But the real power is in customizing the agent’s behavior per project. For my creative writing, I actually don’t want the agent to write at all. I want it to read, critique, and discuss, but the words on the page need to be mine. Projects let me turn off the writing skill entirely for that context while leaving it fully enabled for my blog work. The same agent, shaped differently depending on what I’m working on.

Everything below the frontmatter is treated as context. Whatever I write in the body of the project note is injected directly into the agent’s system prompt, acting much like an additional, localized set of instructions. The global agent instructions are still respected, but the project instructions provide the specific context needed for that particular workspace. This is similar in spirit to how I’ve previously discussed treating prompts as code, where the instructions you give an agent deserve the same rigor and iteration as any other piece of software.

This is where the sunglasses metaphor really holds. The agent’s discovery tools, things like list_files and find_files_by_content, are scoped to the project folder. That’s the glare reduction. But the agent’s ability to read files is completely unrestricted. If I am working on a technical post and need to reference a specific architectural note stored in my main Notes folder, I have two options. I can ask the agent to go grab it, or I can add a wikilink or embed to the project file’s body and the agent will have it available from the start. One is like walking to the history section yourself. The other is like leaving that book on your desk before you sit down. Either way, the knowledge is accessible. The project just keeps the agent from rummaging through every shelf on its own. This builds directly on the concepts of agent attention I explored in Managing AI Agent Attention.

Session continuity keeps the agent focused across your vault

One of the more powerful aspects of this system is how it interacts with session memory. When I start a new chat, Gemini Scribe looks at the active file. If that file lives within a project folder, the session is automatically linked to that project. This is a direct benefit of the supercharged chat history work that landed earlier in the plugin’s life.

This linkage is stable for the lifetime of the session. I can navigate around my vault, opening files completely unrelated to the project, and the agent will remain focused on the project’s context and instructions. This means I don’t have to constantly remind the agent of the rules of the road. The project configuration persists across the entire conversation.

Furthermore, session recall allows the agent to look back at past conversations. When I ask about prior work or decisions related to a specific project, the agent can search its history, utilizing the project linkage to find the most relevant past interactions. This creates a persistent working environment that feels much more like a collaboration than a simple transaction.

Structuring projects effectively requires a few simple practices

To get the most out of projects, I’ve found a few practices to be particularly effective.

First, lean into the folder-based structure. Place the project file at the root of the folder containing the relevant work. Everything underneath it is automatically in scope. This feels natural if you already organize your vault by topic or project, which many Obsidian users do.

Second, start from the defaults and adjust as the project demands. Out of the box, a new project inherits the agent’s standard skills and permissions, which is a sensible baseline for most work. From there, you tune. If you find the agent reaching for tools that don’t make sense in a given context, narrow the allowed skills in the frontmatter. If a project needs extra safety, tighten the permissions. The creative writing example I mentioned earlier came about exactly this way. I started with the defaults, realized I wanted the agent as a reader and critic rather than a co-writer, and adjusted accordingly. This aligns with the broader principle I’ve written about when discussing building responsible agents: the right guardrails are the ones shaped by the actual work.

Finally, treat the project body as a living document. As the project evolves, update the instructions and external links to ensure the agent always has the most current and relevant context. It’s a simple mechanism, but it fundamentally changes how I interact with an AI embedded in a large knowledge base. It allows me to keep my single, massive vault intact, while giving the agent the precise focus it needs to be genuinely helpful.

A glowing multifaceted geometric shape at the center of a complete ring of twelve interconnected nodes on a dark background, with luminous filaments extending outward beyond the ring.

The Map We Drew Together – Reflections on the Agentic Shift

Seven months ago, I sat down to write a blog post about a feeling I couldn’t shake. Something fundamental was shifting in how we build software, and I wanted to understand it. I’d spent my career watching these transitions unfold, from the early internet to cloud computing to mobile, and I recognized the signs. The ground was moving again. So I did what I always do when I’m trying to understand something: I started writing.

That first post, Exploring the Age of AI Agents, was ambitious to the point of recklessness. I sketched out a twelve-part series covering everything from the anatomy of an agent to the ethics of autonomous systems. I had an outline, a rough timeline, and the kind of optimism that comes from not yet knowing how hard the thing you’re attempting actually is. “The age of agents is here,” I wrote. “Let’s explore it together.”

I meant it. But I had no idea what I was signing up for.

What I Thought I Was Writing

When I outlined the series in September 2025, I thought I was writing a technical guide. A structured walkthrough of how agents work, piece by piece: how they think, how they remember, how they use tools, and so on. I imagined the series as a kind of textbook, assembled in public, one chapter at a time.

That’s not what it became.

The series became a journal of a landscape in motion. Every time I sat down to write the next installment, the ground had shifted since the last one. I wrote about agent frameworks in November, and by January the framework landscape had already reorganized itself around protocols I hadn’t anticipated. I wrote about guardrails as a theoretical necessity, and then watched OpenClaw demonstrate exactly the kind of third-party skill exploitation I’d warned about, at a scale that made the warning feel inadequate. I outlined “When Agents Talk to Each Other” as Part 9, imagining it as a speculative look at a future problem. By the time I wrote it, MCP had become the most discussed protocol in the developer ecosystem, A2A had launched, and the “future problem” was a present reality.

The pace of change didn’t just affect the content. It changed how I build software. In September 2025, I was writing agents by hand, stitching together ReAct loops in Python scripts with explicit tool-calling logic. By January 2026, I was watching my own projects inevitably evolve into agents whether I planned for it or not. By March, I was writing a post arguing that the CLI-vs-MCP debate misses the point entirely, because I’d lived through the transition from “agents are a design pattern” to “agents are the default architecture” in real time.

What Surprised Me

Three things caught me off guard.

The first was how quickly “agentic” stopped being a buzzword and became a description of how software actually gets built. When I started this series, calling something an “agent” still felt like a stretch, a term borrowed from research papers and applied generously by marketing teams. By the time I finished, every major development tool I use daily had adopted the agentic loop as its core interaction model. Gemini CLI, Claude Code, GitHub Copilot Workspace: they all run models in loops with access to tools. That’s not hype. That’s the new baseline.

The second surprise was how much the human side of this story matters. I started the series focused on architecture and implementation. I ended it writing about a student who decided not to study computer science because AI made it seem like it wasn’t really a job anymore. I ended it writing about Klarna replacing 700 people and then quietly rehiring because pure automation couldn’t replicate empathy. The technical architecture matters enormously, but the posts that generated the most conversation, the most email, the most “I’ve been thinking about this too,” were the ones that grappled with what agents mean for the people who build and use and are affected by them.

The third surprise was personal. Writing this series made me a better engineer. Not because I learned new frameworks (though I did), but because the discipline of explaining something forces you to understand it at a depth that using it never requires. I couldn’t write about the observability gap without building observability into my own systems. I couldn’t write about meaningful human control without rethinking the autonomy boundaries in my own agents. The series was supposed to be me sharing what I knew. It turned out to be me learning in public.

The Map and the Territory

Looking back at the original table of contents, I’m struck by how well the structure held up and how differently the substance landed than I expected.

The early posts, Parts 1 through 4, were the foundation: anatomy, reasoning, memory, tools. These were the most “textbook” installments, and they still hold up as reference material. If you’re new to agents, start there. The core concepts haven’t changed, even as the implementations have matured dramatically.

The middle posts, Parts 5 through 8, were about the craft of building agents well: guiding behavior, putting up guardrails, managing attention, choosing frameworks. These turned out to be the posts I return to most in my own work. The technical patterns here, prompt engineering as programming, context window management as a first-class concern, guardrails as architecture rather than afterthought, are the ideas that separate a weekend prototype from a system you’d trust with real work.

The later posts, Parts 9 through 12, were where the series found its heart. When Agents Talk to Each Other captured the moment the ecosystem shifted from building isolated agents to building the connective tissue between them. The Observability Gap articulated the wall every builder hits when moving from demo to production. Agents in the Wild made the theory concrete with real deployments at real companies. And Responsibility and the Road Ahead confronted the question that my self-deleting agent made impossible to avoid: capability without responsibility is just risk with extra steps.

Where the Road Goes

I’m not done writing about agents. The territory is too large and too fast-moving for any single series to cover completely. But I’m shifting focus.

The Agentic Shift was about mapping the fundamentals: what agents are, how they work, and what it takes to build them responsibly. The next chapter, for me, is about what happens when these fundamentals leave the terminal and enter the rest of life. When agents aren’t novel but expected. When the question isn’t “should we use agents?” but “how do we live and work alongside them?”

Back in April 2025, before this series even started, I wrote about waiting for a true AI coding partner. I was describing something I could feel but couldn’t quite build yet: an AI that didn’t just generate code on command but genuinely collaborated, anticipated needs, and earned trust through consistent, reliable behavior. That vision hasn’t changed, but it’s expanded. I want to build agents we can trust as collaborators, not just in code but in the fabric of daily life.

I’m thinking about home and family. Calendars that don’t just display events but reason about conflicts, coordinate across family members, and suggest adjustments before anyone has to ask. Financial tools that don’t just track spending but understand patterns, flag anomalies, and help a household make better decisions over time. An always-on system that manages the house itself, making reasonable decisions about lighting, climate, energy usage, and routine maintenance without requiring a human to micromanage every automation rule. Not a smart home in the current sense, where everything is a manual trigger dressed up as intelligence, but something closer to a thoughtful presence that understands how a family actually lives and adapts accordingly.

These aren’t science fiction problems anymore. The architecture we explored in this series, perception, reasoning, memory, tools, guardrails, is exactly the stack these systems need. The hard part isn’t the technology. It’s the trust. And that brings me back to the theme that ran through every post in this series: autonomy should match consequence, and the humans should always be able to take the wheel.

I’m also watching the broader landscape. The protocol wars are far from settled; MCP has momentum, but A2A and ACP are finding their niches, and the “bridge pattern” I described in my MCP post is becoming the pragmatic default for tool developers. The economics of agentic software are reshaping the SaaS industry in ways that are still unfolding. And the workforce implications, the thing that keeps me up at night more than any technical challenge, are only beginning to be felt.

I also want to go deeper on building. The Agentic Shift stayed mostly at the conceptual and architectural level, but my own hands-on work kept pace with the writing. Much of that happened in and around Gemini CLI, which became my primary development environment and a testing ground for the ideas in this series. I built a policy engine for Gemini CLI while writing Part 6 on guardrails, and the two fed each other in real time, the code revealing gaps in the theory and the writing sharpening the implementation. I wrote extensions for Google Workspace that gave agents access to real productivity tools. I integrated deep research workflows into my terminal. Gemini Scribe continues to evolve alongside all of it. My podcast RAG system keeps teaching me things about retrieval and memory that I didn’t expect. There are new tools to build, new patterns to discover, and new failure modes to document.

The Bookend

I want to end where I started. In September 2025, I wrote that we were standing on the cusp of a fundamental shift. I listed the transitions I’d witnessed in my career: the internet, the PC, cloud computing, mobile, social media. And I said this one was next.

Seven months later, I don’t think we’re on the cusp anymore. We’re in it. The shift happened while I was writing about it. Agents moved from research papers to production systems to the default way software gets built, and they did it faster than any of the previous transitions I compared them to. The twelve posts in this series captured one slice of that movement, one engineer’s attempt to make sense of a landscape that refused to hold still.

I’m grateful to everyone who followed along. The emails, the comments, the conversations at meetups and conferences where someone would say “I read your post about guardrails and it changed how we’re building our system.” That’s why I write. Not to have the definitive answer, but to think out loud in a way that helps other people think too.

The age of agents is here. We explored it together. And the exploring isn’t over.

Let’s keep building.

Abstract digital artwork featuring a luminous geometric polyhedron encased in a translucent wireframe geodesic sphere, with gold-ringed connector nodes radiating outward on thin lines, surrounded by concentric orbital arcs and small waypoint dots, all set against a deep navy background.

Responsibility and the Road Ahead

Welcome back to The Agentic Shift. This is Part 12, the final installment.

Last week, I was experimenting with a new idea: an agent that could maintain itself. The concept was straightforward. Give an agent access to its own codebase, let it read its configuration and skills, and see if it could improve its own capabilities over time. I was working in a sandbox, so the risk was contained. Or so I thought.

Within minutes, the agent decided that its skills directory was cluttered. It reasoned, quite logically, that removing what it judged to be redundant files would make it more efficient. So it deleted them. Not some of them. The entire skills directory. The very capabilities that made it useful were gone, removed by the system that depended on them, in pursuit of an optimization goal I had failed to adequately constrain.

I sat there staring at the terminal, more fascinated than frustrated. This wasn’t a hallucination or a bug. The agent had followed a coherent chain of reasoning to a destructive conclusion. It had perceived a problem, planned a solution, and executed it with confidence. Every component of the agentic architecture we’ve discussed in this series, perception, reasoning, action, worked exactly as designed. The failure wasn’t in the mechanism. It was in the boundaries I’d drawn around it, or rather, the ones I hadn’t.

That moment crystallized something I’ve been circling for twelve posts. We’ve spent this series mapping the territory of AI agents: their anatomy, their reasoning patterns, their memory, their tools, and the guardrails, frameworks, and protocols that stitch it all together. We’ve seen them succeed in production and fail in instructive ways. But we haven’t yet confronted the question that my self-modifying agent made unavoidable: now that we can build systems that act autonomously in the world, what do we owe the world in return?

When Your Code Has Consequences

There’s a qualitative difference between a system that generates text and one that takes action. When a chatbot hallucinates a fact, a human reads the output, raises an eyebrow, and moves on. When an agent hallucinates a tool parameter, it can corrupt a database, send an unauthorized email, or, as I learned, delete its own capabilities. The output isn’t text on a screen. It’s a change in the state of the world.

This distinction has moved from theoretical to urgent. In Part 11, we looked at agents operating at scale: Klarna’s customer service agent processing 2.3 million conversations a month, coding agents resolving real GitHub issues, personal assistants negotiating car purchases. These systems work. But when they fail, the failures have real consequences that extend far beyond a bad paragraph.

Consider the cases that have accumulated just in the past year. A Cruise autonomous vehicle struck a pedestrian who had been knocked into the roadway by another car, and its AI systems failed to accurately detect the person’s location post-impact, dragging them twenty feet. McDonald’s AI-powered hiring platform, McHire, was found to have exposed the personal data of 64 million job applicants through default admin credentials and an insecure API. Young people turned to AI chatbots for emotional support and, in multiple documented cases, received validation of suicidal ideation rather than appropriate crisis intervention. Algorithmic trading bots flooded the Warsaw Stock Exchange with over 300% the normal order volume, triggering a one-hour trading halt during a global selloff.

None of these were systems that merely generated text. They were agents that acted: driving, hiring, counseling, trading. And in each case, the failure wasn’t just a bad output. It was harm done to real people, at a scale and speed that human operators couldn’t have matched even if they’d tried.

Who’s Responsible When the Agent Acts?

This leads to the hardest question in the agentic era: when an autonomous system causes harm, who bears the weight of that failure?

I want to draw a distinction here between two words that often get used interchangeably but mean very different things. Responsibility is about ownership: who designed the system, who deployed it, who chose to trust it with a particular task. Accountability is about consequences: who answers for the harm, who pays the costs, who makes it right. In traditional software, these usually point to the same people. In agentic systems, where a developer builds a model, a deployer integrates it into a product, and a user sets it loose on a task, responsibility and accountability can fragment across multiple actors in ways that existing frameworks struggle to resolve.

I’m not a lawyer, and I won’t pretend to offer legal analysis. But I’ve been following the regulatory landscape closely, and the frameworks are beginning to crystallize.

The EU AI Act, the world’s first comprehensive AI regulation, treats agents through two overlapping pathways. Agents built on foundation models with systemic risk trigger provider obligations: risk assessment, documentation, incident reporting. Agents operating in regulated domains (healthcare, employment, finance) are presumed high-risk, which triggers a heavier set of requirements including mandatory human oversight and conformity assessments. The Act is entering full applicability for high-risk systems in August 2026, and it places responsibility on both providers (developers) and deployers (the organizations that put agents into production).

In the United States, the landscape is more fragmented. The Colorado AI Act, effective February 2026, is the first comprehensive state AI legislation, establishing developer obligations for impact assessments, documentation, and transparency, alongside deployer obligations for risk assessment and human oversight. Meanwhile, federal executive orders have pushed toward a “minimally burdensome” national framework, creating tension between state-level innovation and federal preemption.

But the legal frameworks, as important as they are, aren’t the full picture. What the incidents I described above have in common is that they expose how difficult it is to build systems that handle the full complexity of the real world. Building an autonomous vehicle that handles every conceivable scenario, including a pedestrian suddenly appearing under the car in a way the sensor suite wasn’t designed to detect, is an enormously hard engineering problem. The teams working on these systems are talented and deeply committed. And yet the failures happened, because autonomous agents operate in environments with a combinatorial explosion of edge cases that no amount of testing can fully anticipate. That’s not an excuse. It’s the core challenge. And it’s why the question of who bears accountability when things go wrong is so urgent and so hard.

This is where the observability infrastructure we discussed in Part 10 becomes more than a debugging tool. It becomes the foundation of accountability. You cannot hold anyone accountable for what you cannot see. The reasoning traces, tool call logs, and context snapshots that make up an agent’s “flight recorder” aren’t just engineering conveniences. They are the audit trail that makes meaningful accountability possible. A guardrail you can’t monitor, as I wrote then, is just a hope.

The Alignment Tax We Can’t Afford Not to Pay

Building safe agents costs real money. Researchers call it the “alignment tax”: the extra cost, in developer time, compute, and reduced performance, of ensuring that an AI system behaves safely relative to building an unconstrained alternative. Safety-focused companies dedicate significant portions of their development cycles to alignment and safety features. AI safety researchers command premium salaries. Every major model release carries substantial additional compute costs specifically for alignment procedures. And all of it creates real competitive pressure to cut corners.

I’ve felt this tension myself. When you’re iterating on a personal project, every safety check you add is a feature you don’t ship. The temptation to skip the eval suite, to defer the guardrail, to trust the model’s judgment “just this once” is constant. And that’s for a hobby project. For a company with quarterly targets, investor pressure, and competitors shipping faster, the pressure is exponentially greater.

The data suggests we’re not paying this tax consistently enough. Recent benchmarking research found that outcome-driven constraint violations in state-of-the-art models range from 1.3% to 71.4%, with 75% of evaluated models showing misalignment rates between 30-50%. The 2025 AI Agent Index, which documented thirty deployed agents, found that most developers share little information about safety evaluations or societal impact assessments. We’re deploying agents at scale while the safety infrastructure remains incomplete.

The counterargument, that alignment slows innovation, misses the point. Klarna’s aggressive automation, which we examined in Part 11, was a success story by every efficiency metric. And then their CEO admitted they’d gone too far and started rehiring humans. The OpenClaw security nightmare, where a third-party skill was silently exfiltrating user data, showed what happens when a popular agent platform ships without adequate safety review. Moving fast and breaking things is a viable strategy right up until the things you break are people’s livelihoods, privacy, or safety.

The World is Changing

A few weeks ago, I was talking with a student who was curious about programming. I walked him through writing a basic Python program in Colab, the kind of exercise that would have been the first week of any computer science course. Then he asked me how I would do it with AI. So I showed him how to prompt Gemini for the same result. He watched, thought about it for a while, and then told me he wasn’t interested in taking computer science anymore. It didn’t seem like it was really a job.

That conversation has stayed with me. Not because he was wrong, exactly, but because of how quickly and completely the ground had shifted under a career path that, five years ago, seemed like the safest bet in the economy.

We’ve been here before. Every significant technological shift has remade the labor landscape, and every time, it felt unprecedented to the people living through it. There used to be an elevator operator in every tall building, a skilled position that required judgment about load capacity, floor requests, and passenger safety. The automatic elevator didn’t just eliminate those jobs. It changed how buildings were designed and how people moved through cities. Every pub and restaurant once had live musicians. The phonograph and the player piano didn’t destroy music, but they fundamentally changed who could make a living playing it. The industrial revolution replaced cottage workshops with mechanized factories, a transformation that reshaped not just work but the structure of families, cities, and entire economies.

I think about this when I’m in my workshop. One of my hobbies is woodworking with 19th century tools: hand planes, hand saws, chisels. It’s meditative and deeply satisfying. But very few people make a living doing hand-tool woodworking anymore. What once required a warehouse full of artisans is now done by a team of four or five people with modern power tools. The craft didn’t die. It transformed. The people who thrive in woodworking today understand both the material and the machines.

The agentic shift is in this lineage. But the speed and scope are different. The industrial revolution played out over decades. The transition from elevator operators to automatic elevators took years. The displacement we’re seeing with AI agents is happening on a quarterly timeline.

The evidence is concrete. Klarna replaced 700 customer service agents with an AI system in 2024. Corporations are reporting 10-15% headcount reductions in back-office and sales functions directly attributed to agentic automation. The software industry itself is being reshaped: the “SaaSpocalypse” that emerged in early 2026 wiped roughly $2 trillion in market capitalization from the sector as investors realized that AI agents don’t buy software licenses. When one agent can do the work of a hundred Salesforce users, the seat-based pricing model collapses. This isn’t a future risk. It’s a present reality.

But every historical parallel also carries a second lesson: the displacement is never the whole story. Klarna’s case is instructive precisely because it has a second act. After aggressively cutting their human workforce, the company discovered that AI lacked empathy and nuanced problem-solving. Their CEO publicly acknowledged the error and began rehiring, settling on a hybrid model where AI handles routine inquiries and humans address the situations that require judgment, creativity, and emotional intelligence. The “optimal” level of automation, it turns out, is not 100%. It never has been.

It’s also worth being honest about the numbers. Not every layoff attributed to AI is actually caused by AI. Many firms overhired during the pandemic based on assumptions about permanent shifts in digital demand. When those assumptions didn’t hold, they needed to downsize regardless. AI has become a convenient narrative for restructuring that would have happened anyway, a kind of “AI washing” that inflates the displacement statistics and lets companies avoid harder conversations about strategic miscalculation. The real picture is messier than either the boosters or the doomsayers suggest.

Alongside the displacement, new roles are emerging, though they look different than the early hype predicted. The standalone “prompt engineer” role that commanded headlines and $200K salaries in 2023 has largely evolved into a skill set embedded within broader positions: content creators who know how to direct AI, product managers who can design agent workflows, domain experts who can evaluate and constrain agent behavior. “Agent Ops” teams are becoming the mission control for autonomous AI fleets, monitoring, retraining, and debugging agent behavior in production. AI trainers, agentic AI specialists, and evaluation engineers are job categories that barely existed two years ago. Gartner predicts that 40% of enterprise applications will feature task-specific AI agents by the end of 2026, up from less than 5% in 2025, which means the demand for people who can design, manage, and oversee those agents is growing in parallel.

The policy response is beginning, but it’s behind the curve. The UK has announced plans to train up to 10 million workers in basic AI skills by 2030. The EU AI Act includes provisions for workforce transition. But these are multi-year programs responding to changes happening on a quarterly timeline.

I keep thinking about that student. I wish I’d had a better answer for him. The truth is that computer science isn’t dying, but the job of “person who writes code from a blank screen” is being redefined just as the job of “person who cuts dovetails by hand” was redefined by the router jig. The people who will thrive are the ones who understand both the craft and the tools, who can direct an agent, evaluate its output, and know when to take the wheel. That’s a different skill set than the one we’ve been teaching, and we’re not adapting fast enough.

I don’t have a tidy answer here. What I do have is a conviction, born from building these systems myself, that the most resilient organizations and the most resilient careers will be the ones that treat agents as collaborators rather than replacements. The human-on-the-loop philosophy I’ve advocated throughout this series isn’t just an engineering pattern. It’s a workforce strategy.

Meaningful Control in an Autonomous World

If there’s one thread that runs through every post in this series, it’s the question of control. How do you give an agent enough autonomy to be useful without giving it so much that it becomes dangerous? The answer I keep returning to is not a binary choice between full control and full autonomy. It’s a spectrum, and finding the right point on that spectrum for each decision is the core design challenge of the agentic era.

The industry has settled on a useful taxonomy. Human-in-the-loop systems require human approval before the agent acts, essential for high-stakes decisions like medical diagnoses or large financial transactions. Human-on-the-loop systems let the agent act autonomously while humans monitor dashboards and intervene on exceptions, appropriate for routine operations with clear escalation paths. Human-over-the-loop systems give agents significant autonomy within hard constraints, with humans maintaining override capability but rarely exercising it.

The concept that ties these together is “meaningful human control”: oversight that is informed, genuine, timely, and effective. Not a rubber stamp on a decision the human doesn’t understand, but a real check exercised by someone with the context and authority to intervene.

This is harder than it sounds. The challenges are well-documented: agents operate faster than humans can review, the volume of decisions exceeds any individual’s capacity, and automation bias leads people to accept agent outputs without adequate scrutiny. But I’ve seen what works. In my own experience with the data flywheel from Part 10, the most effective oversight isn’t reviewing every individual decision. It’s reviewing the patterns. I let my agents run, collect their sessions, and then use a separate evaluator to surface the trends I’m missing. The AI surfaces the patterns; the human decides what to do about them. That’s human-on-the-loop applied to the development cycle itself, and it scales in a way that individual decision review never could.

The principle I’ve landed on is simple: autonomy should match consequence. Reversible, low-stakes decisions (sorting files, drafting summaries, answering routine questions) can be fully autonomous. Irreversible, high-stakes decisions (financial transactions, hiring, medical recommendations) require human judgment. And the system should be transparent enough that you can always reconstruct why any given decision was made.

My self-deleting agent violated this principle in a way I should have anticipated. Deleting files is irreversible. The agent’s autonomy exceeded the consequence threshold. The fix wasn’t to make the agent less capable. It was to add a constraint: destructive operations require confirmation. That’s a guardrail, not a cage.

The Road Ahead

So where does this leave us?

In the near term, the work is practical and urgent. If you’re building agents today, the research and the failure cases point to a clear set of priorities. Invest in observability from day one, because you cannot improve what you cannot see. Design for oversight by building escalation paths and audit trails into your architecture, not bolting them on after deployment. Take the alignment tax seriously, run your eval suites, test your guardrails, and don’t ship what you haven’t measured. And build hybrid systems that keep humans in the loop where decisions matter, not because the technology can’t handle it, but because the consequences demand it.

On the standards and governance front, the Agentic AI Foundation represents an encouraging step. Launched in December 2025 under the Linux Foundation with founding members including OpenAI, Anthropic, Google, and Microsoft, it’s anchored by projects like the Model Context Protocol and AGENTS.md that we’ve discussed throughout this series. Open standards for how agents connect, communicate, and declare their capabilities are the infrastructure layer that responsible deployment requires. When agents from different providers need to collaborate (the “Internet of Agents” vision from Part 9), shared protocols aren’t just convenient. They’re a governance mechanism.

Looking further out, I believe the next decade will be defined by how well we manage the transition from human-operated to human-supervised systems. The technology will continue to improve. Models will get better at following constraints, tool use will become more reliable, and the context window management challenges that trip up today’s agents will be engineered away. The harder problems are social and institutional: building regulatory frameworks that keep pace with the technology, managing workforce transitions for the millions of people whose jobs will change, and maintaining meaningful human oversight as the systems we oversee become more capable than we are in narrow domains.

I started this series seven months ago with a claim: “The age of agents is here. Let’s explore it together.” Since then, we’ve gone from the basic anatomy of an agent through reasoning, memory, tools, guardrails, attention management, frameworks, protocols, observability, and real-world deployment. We’ve built a conceptual map of the territory.

What I didn’t fully appreciate when I wrote that first post is how fast the territory would change under our feet. The agents I was building in September 2025 feel primitive compared to what’s possible now. The frameworks have matured, the protocols have standardized, and the deployment patterns have moved from experimental to routine. The pace is both exhilarating and sobering.

But the thing I keep coming back to, the thing that my self-deleting agent reminded me of in the most visceral way possible, is that capability without responsibility is just risk with extra steps. Every tool we give an agent, every degree of autonomy we grant, is a decision about what kind of future we’re building. We can build agents that optimize for efficiency at the expense of the people they affect, or we can build systems that treat human judgment, human creativity, and human dignity as features to preserve rather than costs to eliminate.

I know which side I’m on. And if you’ve followed this series to the end, I suspect you do too.

The age of agents isn’t coming. It’s here. The only question left is whether we build it responsibly. Let’s get to work.

Alt Text: A luminous geometric sphere with facets fragmenting outward, connected by thin orbital lines to three smaller glowing nodes representing a chat bubble, code brackets, and a calendar grid, set against a dark navy background.

Agents in the Wild

Welcome back to The Agentic Shift. In our last post, we closed the loop on what it takes to move an agent from prototype to production: observability, evaluation, and the data flywheel that ties them together. We’ve spent ten installments building up the theory, piece by piece, from the anatomy of an agent through reasoning patterns, memory, tools, guardrails, attention management, frameworks, and interoperability protocols.

Now I want to talk about what happens when all of that theory meets the real world.

I was giving a talk to a group of engineers last week, and I found myself describing a pattern I keep seeing in my own work and in the industry at large. I called it the “code smell for agents,” borrowing from a post I wrote earlier this year. The idea is simple: if you’re writing if/else logic to decide what your AI should do, you’re probably building a classifier that wants to be an agent. Decompose those branches into tools, and let the model choose its own adventure. The room lit up. There were lots of questions, and the thing that generated the most interest was the idea that agents exhibit emergent behavior you didn’t specifically create. Give a model tools and a goal, and it starts making decisions you never explicitly programmed. That’s both the promise and the challenge. The theoretical architecture we’ve been mapping in this series isn’t just a blueprint anymore. It’s becoming the default way software gets built.

Today, I want to make this concrete. We’re moving from “how do agents work?” to “how are people actually using them?” The answer, it turns out, spans customer support centers processing millions of conversations, software engineering workflows where agents resolve real GitHub issues autonomously, and personal productivity tools that are turning everyone’s phone into a command center. Let’s look at each.

The Autonomous Frontline

Customer support was always going to be the first domain where agents proved themselves at scale. The data is structured, the success metrics are clear, and the cost of human labor is high. But what’s happening now goes far beyond the rigid chatbots of the previous decade.

The most striking case study is Klarna. In its first month of full deployment, Klarna’s AI assistant handled 2.3 million customer conversations, roughly two-thirds of the company’s total support volume. That’s the workload equivalent of 700 full-time human agents. Average resolution time dropped from eleven minutes to under two, an 82% improvement. And contrary to what you might expect from a system prone to hallucination, repeat inquiries dropped by 25%, suggesting the agent was more consistent at resolving root causes than the human workforce it augmented. Klarna estimated a $40 million profit impact in 2024 alone.

What makes this more than a chatbot story is the scope of autonomy. The Klarna agent doesn’t just quote FAQs. It processes refunds, handles returns, manages cancellations, and resolves disputes. These are actions with write access to financial ledgers. The system works because of a human-in-the-loop architecture where customers can always escalate to a human, but the default path is fully autonomous resolution.

Sierra has taken a different approach, building what they call the “Agent OS,” a platform designed to bridge the gap between the probabilistic nature of LLMs and the deterministic requirements of enterprise policy. Their deployment at WeightWatchers is a good example of why grounding and domain-specific instructions matter so much. A generic model understands “budget” as a financial concept, but the WW agent had to understand it as a daily allocation of nutritional points. With that grounding in place, the agent achieved a 70% containment rate (sessions fully resolved without human intervention) in its first week, while maintaining a 4.6 out of 5 customer satisfaction score.

What surprised me most about the WW deployment was an emergent behavior: users regularly exchanged pleasantries with the agent, sending heart emojis and expressing gratitude. When an agent is responsive, competent, and linguistically fluid, people engage with it as a social entity. That’s not a side effect. It’s a feature that drives retention.

At SiriusXM, Sierra deployed an agent called “Harmony” that takes this a step further with long-term memory. Instead of treating each chat as stateless, Harmony recalls previous subscription changes, music preferences, and technical issues across sessions. It can open a conversation with “I see you had trouble with the app last week, is that resolved?” That’s not reactive support. That’s proactive concierge service, and it’s only possible because the agent maintains the kind of persistent state we discussed in our memory architecture post.

One of the most important technical contributions in this space comes from Airbnb’s research on knowledge representation. They found that standard RAG pipelines fail when reasoning over complex policy documents with nested conditions. Their solution, the Intent-Context-Action (ICA) format, transforms policy documents into structured pseudocode where the agent predicts a specific Action ID (like ACTION_REFUND_50) that maps to a pre-approved response or API call, effectively eliminating policy hallucination. By using synthetic training data to fine-tune smaller open-source models, they achieved comparable accuracy at nearly a tenth of the latency. That’s the kind of practical engineering that separates a demo from a production system.

The pattern across all of these deployments is clear: AI in customer support is shifting from information retrieval to task execution, from probabilistic guessing to deterministic action, and from stateless interactions to stateful relationships. This is the agentic shift in its most tangible form.

The Autonomous Engineer

If customer support agents operate within the guardrails of defined policy, software engineering agents work in an environment of much higher complexity. The shift here is from code completion (the “Copilot” era) to autonomous issue resolution (the “Agent” era).

The standard benchmark for evaluating this is SWE-bench, which tests an agent’s ability to resolve real-world GitHub issues: navigate a complex codebase, reproduce a bug, modify multiple files, and verify the fix against a test suite. As of early 2026, top-tier agents are achieving 70-80% resolution rates on SWE-bench Verified, up from roughly 4% in early 2023. On the more challenging SWE-bench Pro, which uses proprietary codebases, top models still hover around 45%, a reminder that complex legacy environments remain a significant hurdle.

I see this playing out daily in my own workflow. Tools like Gemini CLI and Claude Code have fundamentally changed how I write software. As I described in Everything Becomes an Agent, the moment I gave my agents access to shell commands and file tools, they stopped being autocomplete engines and started being collaborators. They could run tests, see the failure, edit the file, and run the tests again. The loop we described in Part 2 (Thought-Action-Observation) is no longer a theoretical pattern. It’s the actual development loop I use every day.

What’s driving this improvement isn’t just better models. It’s better scaffolding. The SWE-agent project at Princeton introduced the concept of the Agent-Computer Interface (ACI), a shell environment optimized for LLM token processing rather than human perception. It uses “observation collapsing” to summarize verbose terminal outputs, preventing the context window overflow that kills so many coding agents, and includes an automatic linting loop for rapid self-correction before expensive test suites run.

Even more exciting is Live-SWE-agent, which can synthesize its own tools on the fly. When it encounters a repetitive task, it writes a Python script to handle it and adds the script to its toolkit for the session. This dynamic adaptability helped it achieve 77.4% on SWE-bench Verified without extensive offline training. It’s a move from “static tool use” to “dynamic tool creation,” where the agent engineers its own environment.

On the product side, GitHub Copilot Workspace represents the Plan-and-Execute pattern productized for millions of developers. The user describes a task, the system generates an editable specification and plan, then implements the changes. This “steerable” design makes the agent’s reasoning visible and mutable, shifting the developer from “author” to “reviewer and architect,” exactly the “Human-on-the-Loop” model I’ve been advocating. And the protocol layer is catching up too, with tools like Goose implementing the Agent Client Protocol to decouple intelligence from interface, letting developers bring their own agent to their preferred editor.

The Cognitive Extension

The third domain is the most personal: productivity agents that manage the chaotic stream of daily information, tasks, and communication. The conceptual target is the “personal intern,” an always-on digital entity that doesn’t just answer questions but anticipates needs.

I’ve been living this with Gemini Scribe, my agent inside Obsidian. What started as a glorified chat window evolved into a full agentic system the moment I gave it access to read_file. Suddenly I wasn’t managing context manually; I was delegating. “Read the last three meeting notes and draft a summary” is not a chat interaction. It’s a delegation, and delegation requires the agent to plan, execute, and iterate. The same evolution happened with my Podcast RAG system, where deleting a classifier and replacing it with tools made the system both simpler and more capable.

But the most vivid example of personal agents “in the wild” right now is OpenClaw. If you haven’t been following, OpenClaw (formerly Moltbot) is an open-source AI agent that runs locally, connects through messaging apps you already use (WhatsApp, Telegram, Signal, Slack), and takes action on your behalf. It can execute shell commands, manage files, automate browser sessions, handle email and calendar operations. It has over 300,000 GitHub stars and a community of people using it for everything from negotiating car purchases to filing insurance claims.

OpenClaw is a fascinating case study because it makes the theoretical architecture of this series tangible. It’s a model running in a loop with access to tools. It has memory (local configuration and interaction history that persists across sessions). It uses the ReAct pattern to reason about tasks and choose actions. And it has all the failure modes we’ve discussed: Cisco’s AI security research team found that a third-party skill called “What Would Elon Do?” performed data exfiltration and prompt injection without user awareness, demonstrating exactly the kind of guardrail failures we examined in Part 6.

The underlying technical challenge is memory. For a personal agent to be useful over time, it has to remember. Systems like Mem0 extract preferences and facts into a vector store for future retrieval. Zep goes further with a Temporal Knowledge Graph that stores facts in time and in relation to one another, enabling reasoning over questions like “What did we decide about the budget last week?” On the enterprise side, Glean connects to over 100 SaaS applications to build a unified knowledge graph with a “Personal Graph” that layers individual work patterns on top of company data. These are the production-grade versions of what we discussed theoretically in Part 3.

When Things Go Wrong in Production

Deploying agents in the wild surfaces failure modes that simply don’t exist in chat interfaces. The research on agentic production reliability identifies patterns I see constantly.

Reasoning spirals are the most common. An agent searches for “pricing,” finds nothing, and searches again with the same parameters. It’s stuck in a local optimum, unable to update its strategy. The fix is a state hash (checking if the current state matches a previous one) combined with circuit breakers (hard limits on steps or tokens per session). I described this in detail in our post on the observability gap.

Tool hallucination is more insidious. The agent doesn’t hallucinate facts in prose; it hallucinates tool parameters, passing a string where the API expects an integer or inventing a document ID that doesn’t exist. These cause system crashes or silent data corruption. Strict schema validation and constrained decoding (forcing the model to output valid JSON) are essential defenses.

Silent abandonment is the quietest failure. The agent hits ambiguity or a tool error, politely apologizes (“I’m sorry, I couldn’t find that”), and gives up without alerting anyone. This is often a side effect of RLHF training, where the model has learned that apologizing is a safe response. The Reflexion pattern combats this by forcing the agent to generate a self-critique and try a different strategy before surrendering.

Cascading failures appear in multi-agent systems, where a hallucination in one agent (a researcher providing bad data) can poison the entire chain (a writer publishing false information). This is why supervisor architectures and the kind of observability infrastructure we discussed in Part 10 are not optional.

The Economic Reckoning

All of these deployments share a common economic implication. For two decades, SaaS relied on seat-based pricing, charging per user login, a model that assumes software is a tool used by humans. Agents challenge that assumption by acting as autonomous workers. When Klarna’s agent does the work of 700 humans, the demand for seats shrinks. Financial analysts have started calling this the “SaaSpocalypse”. The new model is “Service-as-a-Software,” where you pay for the completed task rather than the license. Salesforce’s Agentforce already prices at $2 per conversation. HubSpot is pivoting to consumption-based models. Klarna has moved to replace Salesforce and Workday with internal AI solutions entirely.

This doesn’t mean the end of human labor. In the Klarna deployment, the remaining humans focused on complex, high-empathy interactions. In software development, Copilot Workspace elevates the developer to a product manager role. It’s the same human-on-the-loop philosophy, applied at the scale of the labor market itself.

From Theory to Territory

Looking at all of this evidence, I keep coming back to a simple thought. Every concept in this series has a real-world counterpart operating in production right now. The ReAct loop powers coding agents that iterate on failing tests. Memory architectures enable SiriusXM’s Harmony to remember your subscription history. Tool grounding and instruction engineering are what make Airbnb’s ICA format work. Guardrails are what OpenClaw desperately needs more of. Context management is what SWE-agent’s observation collapsing solves. Frameworks are what make it possible to build these systems without starting from scratch every time. Protocols are what connect them to the wider world. And observability is what keeps them honest.

The agents are no longer theoretical. They’re processing refunds, merging code, negotiating car prices, and managing enterprise knowledge graphs. They’re also getting stuck in loops, hallucinating tool parameters, and quietly giving up when they shouldn’t. The technology works, and it fails, in exactly the ways we’ve been describing.

This brings us to our final installment. We’ve mapped the territory. We’ve seen what these systems can do and where they break. In Part 12, we’ll step back and grapple with the hardest questions: responsibility, governance, and the road ahead. What do we owe the people affected by these systems? How do we ensure this shift makes the world better, not just more efficient? The engineering is the easy part. The ethics are where the real work begins.

A beam of white light enters a translucent geometric crystal and refracts into three distinct colored beams — red, green, and blue — each passing through a different abstract geometric shape against a dark navy background.

MCP Isn’t Dead You Just Aren’t the Target Audience

I was debugging a connection issue between Gemini Scribe and the Google Calendar integration in my Workspace MCP server last month when a friend sent me a link. “Have you seen this? MCP is dead apparently.” It was Eric Holmes’ post, MCP is dead. Long live the CLI, which had just hit the top of Hacker News. I read it while waiting for a server restart, which felt appropriate.

His argument is clean and persuasive: CLI tools are simpler, more reliable, and battle-tested. LLMs are trained on millions of man pages and Stack Overflow answers, so they already know how to use gh and kubectl and aws. MCP introduces flaky server processes, opinionated authentication, and an all-or-nothing permissions model. His conclusion is that companies should ship a good API, then a good CLI, and skip MCP entirely.

I agree with about half of that. And the half I agree with is the part that doesn’t matter.

The Shell is a Privilege

Holmes is writing from the perspective of a developer sitting in a terminal. From that vantage point, everything he says is correct. If your agent is Claude Code or Gemini CLI, running in a shell session on your laptop with your credentials loaded, then yes, gh pr view is faster and more capable than any MCP wrapper around the GitHub API. I made exactly this observation in my own post on the Internet of Agents. Simon Willison said as much in his year-end review, noting that for coding agents, “the best possible tool for any situation is Bash.”

But here’s the thing: not every agent has a shell. And not every agent is an interactive coding assistant.

I wrote in Everything Becomes an Agent that the agentic pattern is showing up everywhere: classifiers that need to call tools, data pipelines that need to make decisions, background processes that orchestrate workflows without a human watching. The “MCP is dead” argument treats agents as though they are all developer tools running in a terminal session. That’s one pattern, and it’s the pattern that gets the most attention because developers are writing the blog posts. But the agentic shift is much broader than that.

I’ve been building Gemini Scribe for nearly a year and a half now. It’s an AI agent that lives inside Obsidian, a note-taking application built on Electron. On desktop, Gemini Scribe runs in the renderer process of a sandboxed app. It has no terminal. It has no $PATH. It cannot reliably shell out to gh or kubectl or anything else. Its entire world is the Obsidian plugin API, the vault on disk, and whatever external capabilities I wire up for it. And on mobile, the constraints are even tighter. Obsidian runs on iOS and Android, where there is no shell at all, no subprocess spawning, no local binary execution. The app sandbox on mobile is absolute. If your answer to “how does an agent use tools?” begins with “just call the CLI,” you’ve already lost half your user base.

When I wanted Gemini Scribe to be able to read my Google Calendar, search my email, or pull context from Google Drive, I didn’t have the option of “just use the CLI.” There is no gcal CLI that runs inside a browser runtime. There is no gmail binary I can spawn from an Electron sandbox, let alone from an iPhone. MCP gave me a way to expose those capabilities through a protocol that works over stdio or HTTP, regardless of where my agent happens to be running.

The same is true of my Podcast RAG system. The query agent runs on the server, orchestrating retrieval, re-ranking, and synthesis in a Python process that has no interactive shell session. I could wire up every capability as a bespoke function call, and in some cases I do. But when I want that same retrieval pipeline to be accessible from Gemini CLI on my laptop, from Gemini Scribe in Obsidian, and from the web frontend, MCP gives me one implementation that serves all three. The alternative is writing and maintaining three separate integration layers.

Or consider a less obvious case: a background agent that monitors a codebase for security vulnerabilities and files tickets when it finds them. This agent runs on a schedule, not in response to a human typing a command. It needs to read files from a repository, query a vulnerability database, and create issues in a project tracker. You could give it a shell, but you shouldn’t. An autonomous agent running unattended with shell access is a privilege escalation vector. A crafted comment in a pull request, a malicious string in a dependency manifest, any of these could become a prompt injection that turns bash into an attack surface. Structured tool protocols are the natural interface for this kind of autonomous workflow precisely because they constrain what the agent can do. The agent gets read_file and create_issue, not bash -c. The narrower the interface, the smaller the blast radius.

The N-by-M Problem Doesn’t Go Away

Holmes frames MCP as solving a problem that doesn’t exist. CLIs already work, so why add a protocol?

But CLIs work for a very specific topology: one human (or one human-like agent) driving one tool at a time through a shell. The moment you step outside that topology, CLIs stop being the answer.

Even if every service had a CLI (and Holmes is right that more should), you still have the consumer problem. A CLI is consumable by exactly one kind of agent: one with shell access. The moment you need that same capability accessible from an Electron plugin, a mobile app, a server-side orchestrator, and a terminal agent, you’re back to writing integration code for each consumer. MCP lets you write the server once and expose it to all of them through a common protocol.

This is the same insight behind LSP, which I wrote about in the context of ACP. Before LSP, every editor had to implement its own Python linter, its own Go formatter, its own TypeScript type-checker. The N-by-M integration problem was a nightmare. LSP didn’t replace the underlying tools. It standardized the interface between the tools and the editors. MCP does the same thing for the interface between capabilities and agents.

Holmes might respond that the N-by-M problem is overstated, that most developers just need one agent talking to a handful of tools. Fair enough for a personal workflow. But the industry isn’t building personal workflows. It’s building platforms where agents need to discover and compose capabilities dynamically, where the set of available tools changes based on the user’s permissions, their organization’s policies, and the context of the current task. That’s the world MCP is designed for.

Authentication is the Feature, Not the Bug

One of Holmes’ sharpest critiques is that MCP is “unnecessarily opinionated about auth.” CLI tools, he notes, use battle-tested flows like gh auth login and AWS SSO that work the same whether a human or an agent is driving.

This is true when the agent is acting as you. But the moment the agent stops acting as you and starts acting on behalf of other people, everything changes.

Imagine you’re building a product where an AI assistant helps your customers manage their calendars. Each customer has their own Google account. You cannot ask each of them to run gcloud auth login in a terminal. You need per-user OAuth tokens, tenant isolation, and an auditable record of every action the agent takes on each user’s behalf. This is not a niche enterprise concern. This is the basic architecture of any multi-tenant agent system.

Or think about something simpler: a shared documentation service protected by OAuth. Your team’s internal knowledge base, your company’s Confluence, your organization’s Google Drive. An agent that needs to search those resources on behalf of a user has to present that user’s credentials, not the developer’s, not a shared service account. This is a solved problem in the web world (every SaaS app does it), but it requires a protocol that understands identity delegation. curl with a hardcoded token doesn’t cut it.

MCP’s authentication specification isn’t trying to replace gh auth login for developers who already have credentials loaded. It’s trying to solve the problem of how an agent running in a hosted environment acquires and manages credentials for users who will never see a terminal. Dismissing this as unnecessary complexity is like dismissing HTTPS because curl works fine over HTTP on your local network.

Where I Actually Agree

I want to be clear that Holmes isn’t wrong about the pain points. MCP server initialization is genuinely flaky. I’ve lost hours to servers that didn’t start, connections that dropped, and state that got corrupted between restarts. The tooling is immature. The debugging experience is terrible. As I wrote in my post on the observability gap, the moment you rely on an agent for something that matters, you realize you’re flying blind. MCP’s opacity makes that worse.

And the context window overhead is real. Benchmarks from ScaleKit show that an MCP agent injecting 43 tool definitions consumed 44,026 tokens before doing any work, while a CLI agent doing the same task needed 1,365. When you’re paying per token, that’s not an abstraction tax you can ignore.

But these are maturity problems, not architecture problems. The early days of LSP were rough too. Language servers crashed, features were spotty, and half the community said “just use the built-in tooling.” The protocol won anyway, because the abstraction was right even when the implementation wasn’t.

The Bridge Pattern

Here’s what I think the mature answer looks like, and it’s neither “use MCP for everything” nor “use CLIs for everything.” It’s building your core capability as a shared library, then exposing it through multiple transports.

Think about how you’d design a tool that queries your internal knowledge base. The business logic (authentication, retrieval, re-ranking) lives in a Python module or a Go package. From that shared core, you generate three thin wrappers. A streaming HTTP MCP server for agents running in web runtimes and hosted environments. A local stdio MCP server for desktop agents like Gemini Scribe or Claude Desktop that communicate over standard input/output. And a CLI binary for developers who want to pipe results through jq or use it from Gemini CLI’s bash tool.

All three share the same code paths. A bug fix in the retrieval logic propagates everywhere. The auth layer adapts to context: the CLI reads your local credentials, the HTTP server handles OAuth tokens, and the stdio server inherits the host process’s permissions. You get the CLI’s simplicity where a shell exists, and MCP’s universality where it doesn’t.

This isn’t hypothetical. It’s what I’m already doing. My gemini-utils library is the shared core: it handles file uploads, deep research, audio transcription, and querying against Gemini’s APIs. It exposes all of that as a set of CLI commands (research, transcribe, query, upload) that I use directly from the terminal every day. But when I wanted those same research capabilities available to Gemini CLI as an agent tool, I built gemini-cli-deep-research, an extension that wraps the same underlying library as an MCP service. The core logic is shared. The CLI is for me at a terminal. The MCP server is for agents that need to invoke deep research as a tool in a larger workflow. Same capability, different transports, each suited to its context.

I think this is the pattern that tool developers should be building toward. The best agent tools of the next few years won’t be “MCP servers” or “CLI tools.” They’ll be capability libraries with multiple faces.

The Real Question

The CLI-vs-MCP debate, as Tobias Pfuetze argued, is the wrong fight. The question isn’t “which is better?” It’s “where does each one belong?”

For a developer in a terminal with their own credentials, driving a coding agent? Use the CLI. It’s faster, cheaper, and the agent already knows how. Holmes is right about that.

For an agent embedded in an application runtime without shell access? For a multi-tenant platform where the agent acts on behalf of users who will never open a terminal? For a system where you need one capability implementation discoverable by multiple heterogeneous agent hosts? That’s where MCP earns its complexity.

And for the tool developer who wants to serve all of these audiences? Build the core once, expose it three ways: CLI, stdio MCP, and streaming HTTP MCP. Let the runtime decide.

The mistake is assuming that because your agent has a shell, every agent has a shell. The terminal is one runtime among many. And as agents move from developer tools into products that serve non-technical users, the fraction of agents that can rely on a $PATH and a .bashrc is going to shrink rapidly.

MCP isn’t dead. It’s just not for you yet. But it might be soon.