DEV Community

Cover image for Steve Doesn't Need to Know About `git diff`: A Different Take on AI Agent Architecture
Sandro Garcia
Sandro Garcia

Posted on

Steve Doesn't Need to Know About `git diff`: A Different Take on AI Agent Architecture

A few days ago, @sylwia-lask published a brilliant article showing that an AI agent — her sarcastic code reviewer Steve — can be built in roughly 80 lines of JavaScript without heavy frameworks like LangChain or CrewAI.

Her post proves that frameworks aren't doing magic. But it got me thinking:

What if the real problem isn't the framework? What if the problem is that we give the agent too much responsibility in the first place?


The Traditional Agent: Steve Knows Too Much

Steve is a perfect example of the "classic" agent pattern. Look at what his cognitive layer must handle:

  • He knows the tools: getDiff, getFile, listFiles
  • He knows their JSON schemas and parameter types
  • He decides which tool to call and when
  • He executes them locally
  • He maintains the full conversation history with functionResponse payloads

In other words, the reasoning layer is tightly coupled to the execution layer. The LLM is doing infrastructure work.

Sylwia's agent.ts handles all of this beautifully, but those ~80 lines are doing a lot:

// Import types, declarations, tool mapping, retry logic...
const declarations: FunctionDeclaration[] = toFunctionDeclarations(tools);
// Handle rawParts for Gemini 3 thoughtSignature
// Map functionCall → local execution
// Build functionResponse messages
// Maintain full message history
// Handle 503 retries manually

It's elegant. But it's also brittle. If you add a new tool, Steve's prompt grows. If a schema changes, you redeploy Steve. If Steve is compromised, he has direct access to your repository.

What If Steve Knew Nothing?

I've been experimenting with a pattern called BFA (Backend for Agents), specifically the IRC-A protocol (https://github.com/SandroG1977/bfa-sdk).

The mental model is almost the opposite:

The core idea: Discovery is an infrastructure concern, not an intelligence concern.

How It Would Work for Steve

Instead of Steve carrying getDiff / getFile / listFiles in his system prompt, the flow looks like this:

  1. Steve (a BFAAgent subclass) receives: "Review the current git diff."

  2. He doesn't reason about tools. He simply asks the BFA Gateway: "I need help reviewing code changes."

  3. The Gateway performs a semantic vector search (FAISS) over registered capabilities, finds a GitReviewMCP server, and returns:

    • The direct endpoint URL
    • An ephemeral DET (Delegated Execution Token) — a cryptographically signed ticket (PASETO) scoped only to review_git_diff for this specific repo

4, Steve calls the endpoint directly (P2P), presents the DET, and receives a sanitized JSON result.
He processes that result and writes the sarcastic review we all love. 😄

The Lines of Code Comparison
Sylwia's core loop is ~80 lines. With the BFA SDK, Steve shrinks to this:

from bfa_sdk.core.agent import BFAAgent

class Steve(BFAAgent):
    def __init__(self, url: str):
        super().__init__(
            agent_id="steve",
            name="Steve",
            description="Sarcastic senior engineer with 15 years of experience.",
            tags=["code review", "git", "diff", "pull request"],
            examples=["review my changes", "check this diff"],
            url=url
        )

    async def run(self, user_message: str, context) -> str:
        # The BFA Gateway handles discovery, DET minting, and routing.
        # Steve just processes the final sanitized result.
        return f"Steve's review: ..."  # sarcasm included
Enter fullscreen mode Exit fullscreen mode

That's ~15 lines of actual agent logic.

  • The base class (BFAAgent) handles:
  • Registration & challenge-response handshake
  • DET token validation (offline, zero-trust)
  • Semantic discovery via the Gateway
  • Parameter lockdown and scope enforcement

Even Sylwia's agent.ts — ~80 lines — would drop to roughly 10–15 lines of domain-specific code.

The rest (security, routing, tool binding, retry logic, token validation) is inherited from the SDK or delegated to the Gateway.

The Deeper Point: Security by Design

Your for loop cap to prevent token burn is smart. IRC-A solves the same problem at the infrastructure level: DETs have a short TTL (exp), so even if an agent loops, the token dies and the loop stops.
But there's more:

  • If Steve doesn't know about git diff, he can't be tricked into leaking it via prompt injection.
  • If Steve doesn't hold DB credentials (the MCP server does), a compromised OS container can't access the database.
  • If the Gateway issues ephemeral DETs scoped to single operations, Steve can't accidentally (or maliciously) call destructive tools.

This isn't just less code. It's a different security posture.

So... Is the Current Paradigm Wrong?

Sylwia's article proves that frameworks like LangChain aren't doing magic. But I'd go one step further:

Maybe the agent itself shouldn't be doing the magic either.

We've been treating the LLM as an orchestrator, a schema validator, a credential holder, and a decision engine all at once. What if we stripped all of that away and let the agent simply state its intent and trust the infrastructure to route it?

Steve would still be Steve — sarcastic, experienced, impossible to argue with. He just wouldn't need to know what a git diff is.

What do you think? Have you considered pushing the tool-binding responsibility out of the agent entirely? I feel like Steve would appreciate having fewer things to worry about. 😄

Resources

Some tracing in Langsmith

Just note the constant amount of used tokens:

Top comments (2)

Collapse
 
sylwia-lask profile image
Sylwia Laskowska

Thanks so much for the mention! I really like this idea, and I can definitely imagine it being the direction the industry is heading.

For smaller tasks, I think my little Steve is still perfectly sufficient. 😉 But for larger, long-running systems, I can absolutely see the benefits of separating intent from execution and letting the infrastructure handle more of the orchestration.

One thing I'm curious about, though: how would this approach deal with latency and the error feedback loop? If the infrastructure is responsible for routing and execution, how does the agent learn that something went wrong and decide what to do next? I'd love to hear your thoughts.

Collapse
 
sandrog profile image
Sandro Garcia

I like you POV! And thanks for the kind words — means a lot coming from you.

You're absolutely right to ask about this. The agent doesn't lose control; it just delegates execution, not decision-making.

On latency: The BFA Gateway only handles discovery and DET minting. Once Steve gets his ticket, he talks directly (P2P) to the MCP server — no Gateway in the hot path. The DET itself has a short TTL, so if the call hangs, it expires and Steve gets a clean timeout he can reason about, just like your for loop cap.

On the error feedback loop: The agent still receives the result — success or failure. If the GitReview MCP returns an error, Steve gets that sanitized JSON back and decides: retry, ask the user, or try a different capability via another discovery round. The loop is still there; it's just that the agent reasons over outcomes, not over tool schemas.

For long-running or async tasks: That's where a message queue shines. The agent fires a request with a DET, the MCP processes it asynchronously, and the result comes back via callback or queue. Steve doesn't block; he gets notified when the "diff review" job is done.

So the mental model is: Steve stays Steve — sarcastic, decision-making, in control. He just doesn't need to know what a git diff is to review one. 😄