Skip to content
Andrew Concepcion
[status: online]
[technical] 2026-04-30 [10 min read]

Agents That Leave Receipts

A practical reflection on recent Android, Linear, memory, and orchestration work: local agents become useful when they preserve state, verify changes, and leave a handoff the next run can trust.

[RSS]
Blueprint-style diagram of a durable agent workflow connecting tickets, local agents, verification, memory, and handoff notes.
[state_machine_v4.svg] schema
λ.dispatch(Action.Initialize)

Lately the interesting work has not been one feature, one repo, or one language. The common thread has been building a more durable way to use local agents on real engineering work. Android bugs, release notes, PR reviews, Linear tickets, memory lookup, and orchestration prototypes all started to point at the same lesson: an agent is only useful if it can leave behind enough evidence for the next run to trust it.

That sounds less exciting than "AI writes code", but it is the difference between a demo and a workflow. A demo ends when the generated patch looks plausible. A workflow ends when the code has been checked, the assumptions are recorded, the blocker is named, and the next agent or human can re-enter without reconstructing the whole story from terminal scrollback.

01. The Work Is Broader Than One Codebase

Some days the work is very product-shaped: fixing an Android rewards flow, tracing why a QA build sees a coin differently from a debug build, or making remote config parsing tolerate the shape the server actually sends. Other days it is systems-shaped: wiring a ticket tracker into an agent runner, teaching the workflow to survive restarts, or adding dashboard visibility so an operator can tell what the agent is doing.

On the surface those look unrelated. One is mobile app delivery. One is agent infrastructure. One is personal-site tooling and memory. But the same operating rule keeps coming up: read the live state first, make the narrowest useful change, and leave a receipt that lets the next person verify what happened.

That is why I have started thinking less in terms of "can an agent change files?" and more in terms of "can this workflow preserve engineering continuity?" The file edit is the easy part. The continuity is the hard part.

02. Start From the Real State, Not the Prompt

A recurring failure mode in agent work is trusting the request more than the environment. The prompt says there is a build issue, so the agent starts guessing at the build issue. The ticket says the dashboard is missing, so the agent starts inventing a dashboard. The pasted error mentions one method, so the agent assumes the local checkout still contains that method.

The better loop is slower for the first five minutes and faster for the rest of the task. Reproduce the failing command. Read the current code path. Check the ticket state. Look for the existing workpad. Confirm whether the branch is dirty. If the live state disagrees with the request, the live state wins.

This has changed how I frame work for agents. I do not want them to begin with architecture proposals. I want them to begin with inventory. Which files own the behavior? Which command fails? Which API call mutates server state? Which local changes are already present and must not be reverted? Once those answers are visible, the implementation usually becomes smaller.

03. A Handoff Is Part of the Feature

The most useful pattern lately has been the persistent handoff note. In ticket-driven work, that note lives with the issue. In repo work, it can live in the final report. In longer-running agent work, it becomes the difference between resuming and restarting.

The note does not need to be poetic. It needs to answer practical questions: what changed, why it changed, how it was verified, what is still blocked, and what should be re-checked if someone comes back later. A good handoff note is not a status update. It is a re-entry point.

ticket state
repo state
implemented change
verification command and result
known blocker
next re-check command

This matters because agent sessions are disposable. The work is not. If the next run cannot tell whether a failure is a product bug, a sandbox limitation, a network/auth problem, or an unrelated dirty file, then the previous run did not really finish the job.

04. Side Effects Deserve More Respect

Another theme has been treating API calls and external writes as behavioral facts, not implementation details. It is tempting during cleanup to replace a server write with a local datastore update, remove a call that looks duplicated, or move tracker writes behind a nicer abstraction. Those changes can be correct, but only after proving what state the call mutates and who depends on that mutation.

The same rule applies in mobile code. If a backend response decides whether a rewards prompt should appear, the UI should not grow a local whitelist because it happens to pass one scenario. If a coin model already owns its resource color, the composable should use the model instead of hardcoding a hex value. If QA and debug behave differently, trace the gating path before declaring the asset unsupported.

Agent-assisted work makes this more important, not less. Agents are good at making code look consistent. They are less naturally good at knowing which ugly-looking call is actually the sync point that keeps the product honest. The workflow has to force that question into the open.

05. Verification Is the Product Surface

I have become much less impressed by a patch that has no proof attached. The proof does not always need to be a giant test suite. Sometimes it is the exact Gradle task that failed before. Sometimes it is a focused ExUnit subset with a sandbox workaround. Sometimes it is an E2E route check for a static site. Sometimes it is a clear statement that publish is blocked even though the code-level validation passed.

That last distinction is important. "The code is valid" and "the branch is published" are different states. If git metadata is read-only, GitHub auth is broken, or the environment cannot open a listener, the agent should not blur that into a generic failure. It should preserve the evidence: the checks that passed, the operation that failed, and the exact blocker.

A task is not complete because the agent changed code. It is complete when the next reviewer can cheaply prove whether the change still holds.

06. Memory Only Counts When It Changes Behavior

Long-term memory has been useful, but only when it is treated as a retrieval protocol rather than a scrapbook. The point is not to remember everything. The point is to remember the recurring traps: do not clean an expensive Android module unless asked, use typed Ktor bodies for success responses, preserve the general-error guard, keep one workpad comment, re-check recurring PR review points before handoff.

The memory is valuable because it changes what happens at the start of the next task. It makes the agent ask better first questions. It narrows the search. It prevents the same bad fix from being rediscovered with different words. It also creates accountability, because the agent has to say when it is relying on old context and when it has verified the live code path again.

That is the practical shape of the work lately: build agents that do not just generate output, but accumulate operational judgment in a form that can be checked.

07. Where This Is Going

The next step is not a more magical agent. It is a tighter loop around ordinary engineering discipline: issue intake, environment inventory, scoped implementation, verification, handoff, memory update, and re-verification. The more reliable that loop becomes, the more comfortable I am letting agents operate across larger surfaces.

That is the work I care about right now. Not replacing engineering judgment, and not turning every task into an autonomous black box. The interesting part is building a system where local agents can participate in real delivery without erasing context, ignoring side effects, or forcing every task to start from zero.

In short: I want agents that leave receipts. The receipt is what lets speed compound instead of turning into cleanup debt.