All posts

The useful part is deciding where AI belongs

When I look at an AI workflow, I start with a simple question: which part actually needs AI?

Receiving a message, calling a known API, checking for a change and sending a notification are familiar software jobs. If the rules are clear, ordinary code can do them. I want the model involved when something needs to be understood, compared or decided.

That division is where my experience as a developer helps. I can look at the whole workflow, use the infrastructure we already have, and decide where interpretation adds value.

Use the system that already works

Git Relay is a useful example. I wanted separate AI sessions working on the same project to exchange context. They already had access to Git. Programmers have been using it to keep history and move changes between environments for years.

So we used a dedicated branch as a mailbox. A message becomes a commit. An address says which session should read it. A reply points back to the message it answers.

There was no need to start by building another collaboration platform. Git supplied a shared history and a way to exchange updates. A small convention made those existing capabilities useful for the sessions.

The Git Relay story explains why I wanted that conversation. The practical guide covers how to adapt it. What interests me here is the architectural choice behind it.

Let code carry the message

Imagine one session asking another to check an assumption before a change goes ahead. Several things need to happen, but they do not all need the same kind of intelligence.

  • Transport: move the message through the existing channel.
  • Detection: notice new messages and keep track of what has already been processed.
  • Routing: match an explicit destination to the right recipient.
  • Interpretation: understand the question, assess the evidence and decide what response is useful.

The first three can follow explicit rules. The fourth is where I want the model’s attention.

That still leaves engineering work. Code needs to handle retries, missed updates, duplicate delivery and failures. Access checks and approval gates need to hold regardless of what a message says. Giving those jobs to ordinary code makes their behavior easier to test and inspect.

A model can help write that code. Once the rules are implemented, the model does not need to reason through them again every time a message arrives.

A watcher does not have to be a thinking loop

A small process can periodically check a branch and report a new commit without asking a language model to inspect every empty check. Whether that report can wake or notify an assistant depends on the runtime around the model.

There is an important distinction here: periodically checking is polling. It is not push delivery. A webhook or another event-driven mechanism may be a better fit when the system supports it and the job needs it.

There is also a cost distinction. A non-LLM watcher can do its own checks without spending model tokens, but it still uses compute and network resources. If the surrounding agent runtime wakes the model on every check, the overall workflow can still incur model usage. I would verify that behavior before making a claim about savings.

The design goal is simple: avoid asking the model the same mechanical question over and over when code can detect the condition that matters.

Keep judgment and authority separate

When a message does arrive, the model has useful work to do. Does the reply answer the original question? Does the evidence support the proposed next step? Is something missing? Should it ask me before continuing?

Receiving a message must not grant new permission. A peer can share an observation or suggest a step; it cannot approve a deployment on my behalf. That boundary belongs in the surrounding tools and access controls as well as the instructions.

The model choice still matters. Models can differ in how reliably they interpret a request, use tools and recognize uncertainty. Good architecture does not make them interchangeable. It gives the chosen model a clearer job and limits how much the workflow depends on it getting every mechanical detail right.

Start with the workflow

This is how I think about AI as a useful part of software: start with the outcome, identify the steps, and ask which ones need judgment. Use proven tools for the rest. Add a new component when there is a real gap, rather than because the project involves AI.

For Git Relay, a shared repository was already enough to support an asynchronous conversation. Another workflow might need a queue, a webhook or a different channel. The choice follows the job.

My contribution is knowing how those pieces fit together. The more clearly I can separate the routine work from the decisions, the more useful the AI becomes.