Agents
-
Your Agent Needs a Dollar Limit, Not a Token Budget
If you let an autonomous coding agent run in an unbounded loop, I have bad news for you, or rather, your wallet.
It happens easily. An agent gets handed a task, runs into an unhandled error or a failing test, and gets stuck in a retry loop. It re-reads the same files, attempts the same broken patch, and streams tokens the whole time while nobody is watching.
We solved this problem in cloud infrastructure ten years ago. Nobody deploys a Lambda function without an execution timeout. Nobody configures a Horizontal Pod Autoscaler without setting
maxReplicas. Let a container run wild without bounds and your infra team will revoke your deployment credentials before breakfast.Yet here we are, handing autonomous agents full access to our terminal and our API keys with a carrot “go do the task, good luck!”
If we want agents to be production-grade tools, we need to treat token spend like compute spend. The most important feature an agent harness can ship is a first-class, per-task spend ceiling.
Claude Code Shows the Path
Anthropic is paving the way here, and it’s worth talking about.
In Claude Code, you can set a USD ceiling on a single invocation using the
--max-budget-usdflag:claude -p --max-budget-usd 2.00 "refactor auth module"This flag only works in print mode — that’s the
-pabove, which is short for--print.This cap is apparently aware of any fan-out that might occur from subagents, so spend on subagents counts against the same ceiling. Claude Code will then kill the background subagents that are still running if it hits the budget limit. For this feature to work, you need to be running Claude Code v2.1.217 or later.
So if you’re building CLI harnesses on top of Claude Code, this will be a huge quality-of-life feature for you to implement. This way you can kick off a background task and rest assured that the harness will not result in a big surprise on your API bill.
The other one is not a cap at all
Anthropic also has something on the raw API side called the task budget.
However, it is not the same and it will not protect you. Task budgets are in beta, and they hand the model a token allowance for it to run its full agentic loop. It tries to wrap things up gracefully rather than being cut off in the middle of a tool call.
The task budget on the API side is in tokens, not dollars. So it’s fine for getting an idea of whether something is possible within a given token budget, but it’s not going to save you from any surprises on the API bill side of things.
The Gap in Codex and OpenCode
The rest of the CLI agent ecosystem hasn’t caught up.
OpenAI Codex CLI (
codex exec) has no native--max-budget-usdflag or budget setting. You can pin a cheaper model profile, but you cannot set a hard dollar limit on a per-task basis.OpenCode (
opencode run) is in a similar spot, which is strange, given that OpenCode has done a great job of adding features to their CLI harness. Unfortunately, there’s no way to pass a pre-execution cap to OpenCode before you launch a task. It kind of feels like a missed opportunity, or one that they will add soon, given that OpenCode already tracks consumption inside the CLI if you’re using it directly.
How We Hack Around It Today
So how do you enforce a dollar cap on non-Anthropic models right now? You push the problem down a layer and let a gateway handle it — which is one more reason your AI stack probably wants a gateway anyway.
The infrastructure side of things has solved this already with the proxies that are available. They expose the functionality that you need in order to set hard per-key budgets. LiteLLM Proxy will start rejecting calls after that budget has been exceeded, with a
400and abudget_exceedederror type. If you’re using Cloudflare AI Gateway, they shipped a dollar-denominated spend limit in June of this year, which returns a429once you cross the line. You can scope it by model, provider, or other custom metadata, and you can configure it to fail over to a cheaper model instead of blocking, which is a nice to have.
Shift-Left till you get to FinOps
FinOps is what happens when you keep shifting left.
Eventually, we’re going to get tired of the bill.
The gateway vendors have come prepared, and the CLI harnesses have yet to fully adopt a decent token/thinking/dollar budget flag system.
We’ll get this figured out one of these days.
Sources
- Claude Code CLI reference —
--max-budget-usd, its print-mode constraint, subagent spend counting toward the cap, and the v2.1.217 enforcement requirement; verified locally againstclaude --helpon v2.1.220, 2026-07-26. - Anthropic: Task budgets — the advisory, token-denominated API feature; source of the “soft hint, not a hard cap” language and the note that task budgets are unsupported on Claude Code.
- OpenAI Codex CLI: local inspection of
codex exec --help, 2026-07-26 — no budget or spend-cap flag. - OpenCode CLI: local inspection of
opencode run --helpandopencode stats, 2026-07-26 — post-run cost reporting, no pre-run cap. - LiteLLM: Budgets, Rate Limits — virtual key
max_budget,duration, and thebudget_exceededrejection. - Cloudflare AI Gateway: Spend limits — dollar budgets scoped by model, provider, or metadata,
429on block, optional cheaper-model fallback. - Your AI bill is out of control. Cloudflare can fix it now. — the June 2026 launch announcement.
I’d appreciate a follow. You can subscribe with your email below. The emails go out once a week, or you can find me on Mastodon at @[email protected].
- Claude Code CLI reference —
-
How I Would Build Observability for an Autonomous Agent
I have not built a full production observability stack for an autonomous agent.
I’ve built lots of small wrappers around existing coding harnesses. I have a pretty good idea how quickly their output can turn into a wall of model responses, tool calls, and subprocess logs. But I have not run LangChain across a Kubernetes cluster or operated an LLM router at scale.
So this is not a postmortem. It’s a design exercise.
If one of my wrappers became an always-on agent service tomorrow, what would I need to see when it failed? Where would I put that telemetry on Azure, Railway, or Cloudflare? And which parts of the design should stay the same no matter where it runs?
Start With the Trace, Not the Platform
An agent run is a distributed trace hiding inside a loop.
There is a request that starts the work. The agent calls a model, the model requests a tool, the tool talks to another service, and the result goes back into the model. Repeat that enough times and a normal application log becomes hard to follow because the interesting question is not just, “What failed?” It is, “What sequence of decisions got us here?”
I would use OpenTelemetry and give every run one root trace. Each model call and tool call becomes a child span. Structured logs carry the same trace and span IDs, so I can move from a failed run to the exact log event without searching timestamps and hoping I found the right one.
The minimum useful event would look something like this:
{ "event": "agent.tool.completed", "agent_run_id": "run_01K0...", "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736", "span_id": "00f067aa0ba902b7", "step": 7, "tool": "github.get_issue", "duration_ms": 842, "status": "error", "error_type": "rate_limit" }That gives me four things I can debug:
- The run: which request or scheduled job started the work?
- The model: which provider and model answered, how long did it take, and how many tokens did it use?
- The tool: what operation ran, how long did it take, and did it succeed?
- The sequence: what happened immediately before the failure?
I would keep an
agent_run_idbecause it is useful in a UI and support ticket, but I would not use it as a replacement for a trace ID. The trace context needs to travel across HTTP calls, queues, model gateways, and anything else the agent touches.Do Not Log Everything
The tempting version of agent observability records every prompt, response, tool argument, environment variable, and file body. It is also a convenient way to copy credentials and private data into the system with the broadest internal access.
My default would be structural telemetry first. Model name, token counts, latency, tool name, result status, retry count, and safe error categories are useful without storing the full content.
Prompt and tool payload capture would be an explicit policy, not a debug switch someone leaves enabled for six months. I would use an allowlist, redact before export, encrypt whatever remains, and give raw payloads a shorter retention period than ordinary metrics.
This also answers where an AI gateway fits. The gateway is the natural place to record model latency, provider errors, and token usage. It cannot see the agent’s local decisions or tool calls, so it is one part of the trace, not the entire observability system.
The Same Design in Three Places
The trace model stays the same. The deployment choice changes how much infrastructure I have to own.
Azure: The Integrated Option
If the agent already lived in Azure, I would use the Azure Monitor OpenTelemetry distribution and send telemetry to Application Insights, backed by a Log Analytics workspace. That gives the system a managed place for traces, logs, metrics, exceptions, queries, and retention policies.
Microsoft Foundry can also trace model calls, tool calls, intermediate steps, tokens, latency, and errors into Application Insights. I would treat that as an accelerator, not an excuse to skip the application-level design. Some of its agent tracing paths are still in preview, and content tracing can include sensitive prompts and outputs.
Azure is the option I would choose for an organization already paying the Azure complexity tax. It has the most integrated telemetry path of these three and the governance controls a larger company is likely to ask for. For a personal agent prototype, it is probably more platform than I need.
Railway: The Straightforward Container
Railway is where I would start for a small agent that needs a normal process, a Docker image, background work, and the freedom to use ordinary libraries.
I would instrument the application with OpenTelemetry and export traces over OTLP to an external observability backend. Railway’s built-in logs and container metrics are useful for deployment health, CPU, memory, disk, and network usage. They are not a distributed tracing backend for the agent itself.
That split is fine. Railway runs the service, while the application owns its telemetry schema and exports it somewhere designed to query traces. I would also make sure the exporter flushes on
SIGTERM, because a clean deployment is not helpful if the final spans disappear during shutdown.This is the least ceremonial option. It is also the one where I would have to make a separate decision about the telemetry backend and its retention cost.
Cloudflare: The API-Oriented Agent
Cloudflare gets interesting when the agent mostly calls models and HTTP APIs instead of running shell commands against a workspace.
Workers can collect logs and traces automatically, and Cloudflare can export both in OpenTelemetry format to an external destination. I would still add application spans for the model and tool semantics because automatic request tracing cannot know which prompt, tool, or agent step matters to me. The OTLP export is also currently beta and does not export Worker metrics.
For state, I would use a Durable Object when one run needs a single coordination point, D1 for relational records across runs, and R2 for larger artifacts or archived transcripts. If the agent needs retries, sleeps, or a human callback, Cloudflare Workflows is a better fit than trying to keep one HTTP request alive.
I would not put a coding agent that needs arbitrary processes, a writable repository, and long CPU-heavy tool calls into a Worker just because the edge sounds nice. Cloudflare’s runtime has real CPU, memory, connection, and logging limits. For that workload, I would run the agent in a container and consider Cloudflare for the gateway or API edge instead.
What I Would Pick
For my first version, probably Railway. It matches the small wrappers I already build, lets the agent behave like a normal application, and leaves me free to try different tracing backends without moving the workload.
I would pick Azure when the surrounding organization already uses Azure Monitor and needs one managed governance story. I would pick Cloudflare when the agent is an API orchestrator and its tools already live on the network.
A mistake would be choosing a platform or dashboard first and calling that observability solved. I would start small with a trace per run or tool call with structured logging turned on, but no prompt content until there is a redaction or sanitization policy feature in place.
I haven’t built this stack yet. But that is how I would start building it.
Sources & References
- OpenTelemetry Logs specification — trace and span correlation in structured logs.
- Azure Monitor OpenTelemetry — supported telemetry signals and Application Insights setup.
- Microsoft Foundry tracing — agent trace contents, storage, and data-handling considerations.
- Railway third-party observability — application-side OpenTelemetry export and shutdown guidance.
- Railway metrics — native container and service metrics.
- Cloudflare Workers traces — automatic tracing and native retention.
- Cloudflare OpenTelemetry export — OTLP trace and log export capabilities and current limitations.
- Cloudflare Durable Objects — per-instance coordination and transactional storage.
- Cloudflare Workflows — durable multi-step execution, retries, and external events.
- Cloudflare D1 — relational storage for records shared across runs.
- Cloudflare R2 — object storage for larger artifacts and archived transcripts.
- Cloudflare Workers limits — CPU, memory, connection, and log limits.
I’d appreciate a follow. You can subscribe with your email below. The emails go out once a week, or you can find me on Mastodon at @[email protected].
-
The Human Job Is Choosing What Not to Build
Coding agents have made one word much harder to say.
No.
You describe a feature, and the agent can already see the model, the migration, the command, the tests, and the docs it needs to touch. The whole thing sounds like an afternoon instead of a week.
So why not build it?
That question used to contain its own answer. We didn’t have the time or the people, and the feature wasn’t worth interrupting everything else for two weeks. Now the implementation might take twenty minutes. The old constraint is gone, but the need to choose is not. If anything, choosing matters more, because we can say yes faster than we can understand what all those yeses are doing to the product.
The agent’s job is to make the thing we asked for. The human job is deciding whether the thing should exist.
Yes Produces Better Receipts
Building something leaves evidence. There’s a diff. Tests pass. A new command shows up in the help output. You can take a screenshot, close an issue, and point at the feature. Work happened, and the artifacts prove it.
Choosing not to build produces almost nothing. Maybe you leave the idea in a notebook. There’s no demo for the dependency you avoided or the interface you never had to support.
That makes restraint feel less like engineering.
It can look like indecision, or lack of ambition, or an empty afternoon of planning.
A good “no” can preserve more value than a clean implementation.
You protected the shape of the product. You kept it understandable. You left room for the features and the users that actually matter.
Agents Make Local Ideas Look Great
Coding agents are strongest when the task is concrete. Add this flag. Support this file format. Create an adapter for this provider. Cache this response. Put a dashboard on top of these logs.
Given one of those, the agent inspects the local code and produces a reasonable path forward. It sees where the new feature fits.
What it doesn’t automatically carry is the opportunity cost.
You can put that context in the prompt, but somebody still has to decide how much product is enough.
A human has to protect the product.
Cheap Is Not the Same as Free
I recently argued that code is cheap now, but decisions are not. The mistake is pricing a feature only by how long the first implementation takes.
A twenty-minute feature can create a permanent interface, another concept every future agent has to understand, or a second way to do a task when the first way was already fine.
The implementation estimate answers: how quickly can we make this work?
The product decision asks: is this worth changing what the system is?
Four Ways to Say No
Not building something doesn’t always mean rejecting it forever. Here are four versions of no.
No, this is not the product
Some ideas are useful and still don’t belong. A small command-line tool doesn’t automatically need a web dashboard. A personal publishing pipeline doesn’t need multi-tenant permissions because it could theoretically serve a team. A library doesn’t need a plugin system before a second plugin exists.
These features may solve real problems. But they solve somebody else’s version of the product.
This is the cleanest no.
Write down the boundary and move on.
Not yet, we don’t have the evidence
Sometimes the problem is plausible but unproven. The database might need caching. The API might need another abstraction. Users might want a second export format. “Might” is doing all the work.
Wait for the system to produce evidence. Measure the slow query. See a second provider show up. Hear the same request from someone who actually has the problem. The agent will still be there when the need is real.
Deferral is only useful when it has a condition: “Revisit imports when we have enough data to support the decision.”
All the “maybe laters” are not backlogs; they are fossils that deserve to be buried.
Yes, but smaller
Plenty of ideas contain one valuable piece surrounded by a feature-shaped cloud.
Build something that you think is useful. Not everything needs a dashboard.
You don’t need a generic provider framework until you have a reason for the generic provider to exist.
You don’t need a rules engine if you’ve only got three rules.
Ask for the smallest change that provides the most value.
Narrow the solution before it becomes a broad one.
No longer
The hardest no is the one aimed at code that already exists. How do you determine whether it’s actually being used or not? This is how we get features that outlive the reason they were built. You added an experiment that became a supported path, and now everybody’s afraid to remove it.
Prune the branches of the product tree. Before you decide what to build next, make sure you’re not letting the system grow forever.
You should be asking yourself: what choices are you deciding against? Sometimes it’s important to know what already exists before deciding what should exist.
My Filter Before I Say Yes
Product committees suck, especially for small changes. Before I accept an idea as a feature, I ask myself the following questions. Or I should ask myself. Or I hope I ask myself. Whatever version of that makes sense for the day.
- What problem gets easier?
- Why now?
- What new promise does this create?
- What gets harder after this exists?
- Can a smaller change prove the value?
- What would make us remove it?
These help you tell the difference between what’s easy to generate and what’s worth owning. Sometimes they help you solve for a hypothetical problem. It’s a good thing to try to figure out whether the tests will pass before you build them.
Taste Is the Remaining Bottleneck
As implementation gets cheaper, the scarce skill becomes taste.
Not taste as in fonts and rounded corners. Taste is recognizing when a product has enough concepts. It’s choosing the boring interface people can understand. It’s seeing that a flexible abstraction makes the current problem worse. It’s knowing which rough edge gives the tool character and which one just wastes time.
Then decide.
The future of software isn’t a world where we finally build every idea in the backlog.
That sounds exhausting.
The future of software is a world where we get to decide, and be honest about which ideas were actually good to begin with.
Don’t forget you’re allowed to say no.
I’d appreciate a follow. You can subscribe with your email below. The emails go out once a week, or you can find me on Mastodon at @[email protected].
-
When I Use a Subagent and When I Don't
Give a good harness access to subagents and everything starts looking like a team project.
You’ve got one agent working with the database layer. Another can research the API. Another can write the tests. Another can check the work. Another can manage moving the data. As work starts happening in parallel, colored dots appear, and the whole thing starts looking like an org chart.
That sounds like fun to me, but it can also be a mess.
Having more agents doesn’t automatically produce better results.
Sometimes they duplicate work. Sometimes they edit files at the same time, producing unexpected changes or behavior.
I mean, I still use subagents constantly. They are definitely the default.
Sometimes we need, like, a subagent arena. Two agents enter. One survives.
The Subagent Context Boundary
I started using subagents as a way to protect the main context window. I wrote about that back in March: the delegated agent can read files, inspect logs, and grind through intermediate reasoning in its own context.
It’s still one of the best reasons to delegate. When finding the right answer means searching through 20 files, reading five of them, tracing a configuration value, and checking the tests, that sounds like a subagent task to me.
The search is noisy, and the output needs to be compact.
Using subagents keeps the main context window free for the larger task.
I Delegate Bounded, Independent Work
The tasks I delegate have one thing in common: I can define the output before the work begins.
Here are some areas where a subagent makes sense:
- Repository research.
- A separate implementation surface.
- Specialist review.
- Independent verification.
- Real parallel work.
Don’t Delegate an Unclear Problem
Delegation is not a substitute for deciding what the work is.
If a request is vague, spawning more agents isn’t going to help with the vagueness. It’s just more output with no clear direction. The parent still needs to choose the requirement and figure out what we’re building.
Before I delegate, I want to handle the following in the parent context:
- what question the subagent is answering,
- which files or systems it owns,
- whether it may edit anything,
- what constraints it must preserve,
- what evidence it should return,
- when it should stop and ask instead of guessing.
If we can’t figure out answers to those, the next step should be planning, not delegation.
Don’t Split Tightly Coupled Work
Avoid having two agents edit code in neighboring areas. The code may share an interface, a fixture, or a schema, and if you start changing things in multiple places without coordination, you’re going to have problems.
Each agent has its own context window. When it reads a file, block of code, or dependency into that window, the context is only current at that moment. If another agent changes the same thing, how does the first agent know its context needs to be updated?
It’s a complicated problem, for sure.
So your best bet is to avoid parallel edits where agents are working in the same or similar areas of the code. The agent work areas need to be distinct.
If humans can have coordination problems, agents can too.
I Don’t Delegate Five Minutes of Work
Delegation has a cost. The parent needs to describe the task and load enough context for the subagent to do the work and summarize it. Then the parent needs to verify the result. All of that burns a bunch of tokens. Obviously, for one-line changes or small amounts of text, this handoff should never happen in the first place. To decide whether to pass the work to a subagent, ask: will using a subagent substantially improve the output?
Sometimes the answer is just to do it in the parent context window, even if that means you have to compact sooner.
A good subagent task looks a lot like a good software interface. It has a narrow purpose, explicit inputs, clear permissions, and predictable output.
Compare these two assignments:
Look into the tests and fix anything missing.Review the unchanged-record tests for Book. Identify provider-owned fields that are not covered. Add focused tests only in tests/test_books_client.py. Do not change production code. Run the focused test file and report the result.The first transfers uncertainty. The second transfers work.
The difference does matter.
The Parent Still Owns the Result
Subagents report completion. They don’t make completion true.
The parent still has to inspect the changes, reconcile conflicting findings, run the combined quality gate, and decide whether the original requirement was satisfied. If three agents each report that their piece passes, you have three pieces of evidence. You don’t yet know whether the assembled system works.
Delegation changes who gathers the evidence. It doesn’t remove the need to judge it.
The goal isn’t keeping every agent busy. The goal is finishing the work without turning yourself into middle management for robots.
Oh God, I think that’s my job title.
I’d appreciate a follow. You can subscribe with your email below. The emails go out once a week, or you can find me on Mastodon at @[email protected].
-
Where Should This Agent Knowledge Live?
Every agent has a junk drawer.
It usually starts with project instructions. Then I added build commands, personal preferences, database warnings, old architecture decisions, and things to fix later.
The agent could see everything if I wanted it to, but then it would have to read a small novel before touching the code, recurring workflows were buried between random facts, and completed work kept hanging around like it was still relevant. I had given the agent more context and somehow made it less informed.
The problem was not missing knowledge. The problem was putting every kind of knowledge in the same place. An instruction, a skill, a memory, and an issue can all be written in Markdown.
They do four completely different jobs.
Four Places, Four Jobs
A clean version looks like this:
What the agent needs Where it belongs A rule that must apply during every relevant session Instructions A reusable procedure for a particular kind of work Skill A durable fact that may become relevant later Memory A commitment that remains open until completed Issue tracker In practice, this is messier than a table… That’s where the engineering and attention to detail really matter.
So the useful questions are Does the agent need to know about this? and What bucket does this knowledge belong in?
Instructions Are Guaranteed and Expensive
Project instruction files are the things your agent loads automatically. Depending on the tool, that might be
AGENTS.md,CLAUDE.md, or another repository-level file.This is your guaranteed layer. The agent (or harness) doesn’t have to remember to search for it. If a session starts in the project, the rules are sitting in context.
Use that guarantee for knowledge that must shape nearly every relevant action:
- the preferred package manager and command runner,
- where the main source and tests live,
- dangerous commands that require explicit approval,
- the authoritative source for important data,
- mandatory validation before work counts as complete,
- a pointer telling the agent when to load a skill or recall a memory.
The guarantees come with a cost. Every line added to the context is loaded on every session, even when all you really need is a lightweight session where that context doesn’t matter.
Be diligent about cleaning up and maintaining your guaranteed context window, especially if you don’t have a memory layer in place.
Skills Are Procedures With Judgment
A skill answers a different question: how should the agent perform this kind of work?
Publishing a blog post, reviewing a pull request, applying a database migration, preparing a release, updating dependencies. Those are workflows. They have an entry condition, a sequence, safety rules, and a way to verify the result. That’s more than a fact. It’s operational judgment packaged for reuse.
Before we had skills, we had playbooks. Now we can make playbooks out of anything.
A good skill tells the agent when the workflow applies, what to inspect before acting, which steps and tools are appropriate, what must never happen silently, and what evidence proves the work succeeded.
Maybe the deployment instructions can now stay short; when doing a deployment, load the deployment skill.
Instructions are guaranteed. Skills are conditional.
Memory Is Context, Not Policy
Memory is where durable facts live without being injected into every session.
I prefer pnpm for JavaScript and most TypeScript projects. I prefer uv, and sometimes Poetry, for Python. These are facts that shouldn’t have to be repeated.
What about that time you had to troubleshoot an integration and observed some strange behavior? What about when you changed the database design and it broke the support layer? None of this deserves to be injected into every prompt, but it deserves a place where the details can be accessed later.
A semantic memory system can store and retrieve the relevant durable facts and give them to the agent when it asks. I described this earlier.
Memory can be large, and it can be flexible. But it’s also not guaranteed. The agent might not use the right keyword. You might have a problem with the vendor. A critical dependency could go down and take the memory system offline.
Don’t put safety-critical policies in memory. It’s good to have backups. If preferences get lost, they can be recreated, but absolutes like never print secret values belong in several places. If it has anything to do with security, cover your ass.
Memory is best for facts, preferences, relationships, explanations, and past decisions.
Issues Are Promises, Not Storage
An issue tracker tells the agent what needs to be done.
Issues have always been little documentation vaults. We write the history of the bug as it travels through the system. We link back to the issue as it maintains relevance.
An issue should preserve the context for a decision. It should act as a durable property of the project, recording the circumstances around a decision point.
Don’t make it a container for everything the agent did along the way, but I think it’s totally fine if you use it to publish an implementation plan.
Just, you know, you gotta read it.
Our job now is reading about software. The issue trackers are our corpus.
Route the Knowledge With Four Questions
When I don’t know where something belongs, these four questions can help.
1. Must the agent know this before it acts?
Instruction
2. Is this about performing a recurring kind of work?
Skill
3. Is this a durable fact that may help later?
Memory
4. Is this unfinished work or a commitment?
Issue
Sometimes the answer can be more than one place. But don’t copy the content blindly between locations.
All the files may be Markdown, but maintaining the architecture now means knowing where to put the information.
I’d appreciate a follow. You can subscribe with your email below. The emails go out once a week, or you can find me on Mastodon at @[email protected].
-
Not Every Agent Task Needs an Issue
I’ve written before that your AI agent needs a task manager, and I stand by it. Chat history is not project state. Context windows compact. Sessions end. If the work matters tomorrow, it needs to live somewhere tomorrow’s agent can find it.
The part I didn’t mention: not every task matters tomorrow.
Some work should disappear with the session. Turning all of it into durable project state doesn’t make your agent more organized. It gives the next session a bigger pile of bookkeeping to misunderstand.
Tasks Have Different Lifetimes
When we say “task,” we’re lumping together several different things.
“Add filtering to the search API” is a project commitment. It might take several sessions, affect other work, and need a record of why the behavior changed.
“Inspect the existing query code” is not a project commitment. It’s one step the agent needs to finish the larger task.
“Run the focused tests” is even shorter-lived. Once they pass and the result has informed the work, that checklist item has done its whole job.
These all deserve attention. They don’t all deserve permanent storage. I think about them in two buckets:
- Session tasks help the current agent organize execution. They live in a plan or checklist, then disappear when the work is complete.
- Durable issues preserve commitments, decisions, dependencies, and unfinished work across sessions.
The distinction isn’t importance. A database backup check can be a critical session task. The distinction is whether the information needs to outlive the work happening right now.
If it doesn’t, let it die.
Ephemeral Does Not Mean Sloppy
There’s a temptation to treat ephemeral tasks as unstructured work. Just tell the agent,
plz fixand see what happens.A session still benefits from a clear plan. The agent should inspect before editing, break a change into steps, mark progress, run focused tests, run the full quality gate, and verify the result. A visible checklist makes long work easier to supervise, and it reduces the chance the agent quietly skips the boring last step.
The checklist just doesn’t need to become part of the project’s permanent record. Picture something like this:
- inspect the repository method - find every caller - update the shared comparison helper - add focused tests - run the full suiteThose are excellent session tasks. They tell the agent how to move through one change. After the implementation lands, keeping all five around adds nothing. The commit and tests preserve the result. The issue, if one exists, preserves the reason.
An Issue Should Earn Its Permanence
A durable issue is more expensive than it looks. Someone has to write it clearly, connect dependencies, update its state, close it, and eventually decide whether it’s stale. An agent also has to read it. Every open issue becomes part of the project’s apparent reality.
That cost is worth paying when the issue preserves something important. I create one when at least one of these is true:
- The work will survive the current session. If we’re likely to stop before it’s done, the next session needs a reliable handoff.
- Other work depends on it. A dependency belongs in a system that can represent blocked and ready work, not in a paragraph buried in chat history.
- It represents a real commitment. A user-reported bug, an accepted feature, or a promised follow-up shouldn’t vanish because a terminal closed.
- The decision needs a record. If future maintainers will ask why the system behaves this way, the issue preserves context a diff can’t.
- The work crosses boundaries. Changes spanning repos, services, migrations, or people need coordination beyond one agent’s checklist.
- We found valid work but aren’t doing it now. That’s exactly what a backlog is for.
If none of those apply, a session task is probably enough.
Promote Work When It Changes Shape
You don’t have to pick the perfect tracking level before the agent starts.
Begin with a session plan. During inspection, the agent may discover that the “small fix” requires a migration, depends on another repository, or exposes a separate bug. If the work changes shape. Promote it.
Agents are very good at expanding scope. They inspect one path, notice three adjacent problems, and offer to fix everything while the files are open. Sometimes that’s useful…
Your Backlog Is an Agent Prompt
Humans are pretty good at looking at an old issue and thinking, “yeah, we don’t care about that anymore.”
Agents are more literal. If the tracker says the issue is open and ready, the agent has a strong reason to treat it as authorized work. A stale backlog can send a perfectly capable agent down an obsolete implementation plan just as it easily as it can with a valid one.
No issue hygiene needs to be a part of your process. An open issue tells the agent this work is still wanted, this description is still accurate, these constraints still apply, and finishing it would improve the project.
If any of that is false, the issue isn’t harmless clutter. It’s a bad prompt waiting to be executed.
Use the Smallest State That Survives Long Enough
After six months with git-native issue tracking, my workflow has gotten a lot more varied.
I use a session plan when the current agent only needs help organizing the work in front of it. I use an issue tracker when the project needs to remember something after that agent is gone. For local projects i’m very rarely reaching for Beads. For team work it’s always GitHub or GitLab.
Too little tracking and the project forgets real commitments. Too much and it accumulates stale instructions, duplicate tasks, and chores whose only purpose is maintaining the tracker.
Start small. Let the agent make a checklist. Promote the work when it makes sense. Close it when the feature is satisfied. Delete old tasks like you are pulling weeds to make space for the flowers to bloom.
Your agent needs a task manager. It does not need a permanent record of every box it checked along the way.
I’d appreciate a follow. You can subscribe with your email below. The emails go out once a week, or you can find me on Mastodon at @[email protected].
-
Don't Build a Full Agentic Harness. Wrap One Instead.
I keep seeing people talk about building an “Agentic OS”. A personal system where agents get tools, memory, sub-agents, long-running tasks, permissions, and maybe a little dashboard with colored dots so you know the robots are thinking.
I get it. It sounds fun. It is fun. I like building things too.
So first, a distinction, because the word gets thrown around loosely. Wrapping an existing harness is fine. A little script that shells out to Claude Code or Codex to do one job is a wrapper, and most people should build those. Plenty of people build one by accident and never call it a harness. I’ve got three small ones driving the pipeline that publishes this blog, each just handing a task to Claude Code and getting out of the way. That’s not the trap.
The trap is starting from a raw model API and trying to rebuild the whole thing, replicating Codex or Claude Code or OpenCode from scratch because you want a better way to work with agents. Do that and chances are you’re about to spend several weekends building a worse version of the tool you already have.
No-thX.
So the useful question isn’t “should I build a harness?” It’s how much of the harness do I need to own?
You’re Choosing an Ownership Level
A harness is all the stuff around the model: the agent loop, tool execution, sessions, permissions, memory, context management, orchestration. The model is the part you rent. The harness is the part you choose to own.
And that choice is a slider, not a binary.
What you do What you own What you inherit Extend a full harness Skills, sub-agents, MCP servers, conventions The loop, permissions, sessions, tool execution Run an open harness Deployment, provider, config Most core agent machinery Start from primitives The loop, workflow-specific behavior A small SDK and a few tools Build an agent app Everything that makes it a product Framework primitives, maybe Most people should start at the top and work down only when they hit a real reason to.
Start by Composing What Already Works
If you already use Claude Code, Codex, Gemini CLI, or another complete coding harness, you have more leverage than you think.
You can add specialized agents. You can write skills for recurring work. You can connect MCP servers for memory, documents, databases, browser tooling, whatever you need. You can set project conventions so the agent doesn’t rediscover the same rules every time.
That’s not “just configuration.” Configuration is how you shape a system without becoming responsible for every moving part inside it. The host already knows how to run the model loop, ask permission before risky actions, manage sessions and context, stream tool output, handle files and diffs, and coordinate sub-agents.
I’ve got a vault full of agent instructions, task-specific skills, persistent memory, and a few specialized agents. None of it required me to write a scheduler, a context-compaction system, or an approval UI from scratch. Good. I have other things to do.
The DIY Tax Is Real
A basic agent loop looks almost insultingly simple:
send prompt → receive tool call → run tool → send result → repeatYou can get that running in an afternoon.
What happens when a tool hangs? When the user cancels halfway through a long task? Where do sessions live, and how do you resume them? How do you show the user what changed? How do you stop an agent from reading the wrong file, deleting the wrong directory, or spending five dollars retrying the same broken command?
Then you need permissions. Sandboxing. Tool schemas. Retries. Logging. Secret handling. Context limits. Model fallbacks. Observability. A way to update all of it without turning your harness into the largest unmaintained project in your life.
It works. But “it works” and “it’s a good idea” are two very different things.
When You Should Go Lower
There are good reasons to own more of the stack. Maybe you need provider independence, routing cheap models to bulk work and expensive ones to the hard problems. Maybe you need an agent running persistently on your own infrastructure. Maybe the agent has to live inside another product, not a coding CLI. Maybe your workflow is weird: several specialized agents passing structured work between each other, a custom approval model, durable state that’s part of the thing you’re selling.
Those are all real reasons to move down the slider.
The trap is that people move down the slider because they’re curious, not because they hit a constraint. Curiosity is a great reason to build a prototype. It is not automatically a great reason to make yourself responsible for a runtime.
The Path That Doesn’t Make You Miserable
- Extend the harness you already use. Add a few good skills, focused sub-agents, the tools and memory you need. Do this first, because it shows you which parts of the workflow are painful before you replace anything.
- Add a model-agnostic harness for the jobs that hurt. When billing, deployment, or long-running automation become a real problem, reach for an open, self-hostable harness like Goose, OpenHands, Hermes Agent, or Pi. You still inherit the hard machinery but get control over providers and hosting. (This is also the layer where a model gateway like OpenRouter or LiteLLM slots in underneath, so you’re not locked to one vendor.)
- Drop to primitives for one narrow workflow. Skip the harness entirely and write the loop yourself on a thin SDK, the Vercel AI SDK or Anthropic’s Claude Agent SDK, when you need an embedded agent or a topology existing tools can’t represent cleanly. Build the smallest thing that proves the point. Don’t start by recreating a general-purpose coding agent.
- Reach for a framework when you’re shipping an agent product. If the harness itself is the product, then yes, you probably need graphs, durable state, domain models, and all the rest. This is where something like LangGraph or CrewAI earns its weight. That’s a different project from improving your own workflow.
One tool blurs steps 1 through 3 on purpose, and it’s worth calling out: Pi (pi.dev). It’s a coding-agent CLI you can use today and a TypeScript SDK you build your own harness on top of, provider-agnostic, with a “primitives, not features” core. If you already know you’ll want to customize, Pi lets you start by using it and grow into owning the loop, one extension at a time, without ever switching tools. Hermes Agent sits in similar territory for the self-hosted, model-agnostic case. Either one is a saner on-ramp than a from-scratch build on day one.
Own the Part That Makes You Different
The more of the harness you own, the more control you have. You also own more bugs, more security decisions, more context problems, and more ways for an agent to fail that are hard to explain.
So my strategy is boring in the good way. Start with a full harness. Compose it around your work. Add a lower-level tool only when you can name the limitation it solves. Build the loop yourself only when owning the loop is the point.
You don’t need an Agentic OS to get serious value out of agents. You need a workflow that helps you finish work without becoming one more system you have to maintain.
I’d appreciate a follow. You can subscribe with your email below. The emails go out once a week, or you can find me on Mastodon at @[email protected].
-
Amnesia-Free Agents: GBrain and the LLM Wiki Idea
Every agent I work with has amnesia.
Open a new terminal session, spin up a subagent, start a fresh chat, and the thing forgets everything. Your project guidelines, your coding style, your database schemas, the meeting where you decided why the schema looks like that. Gone. So you do one of two things: stuff a few thousand tokens into a bloated system prompt, or hand-maintain fragile context files like
CLAUDE.md. I’ve done both. Neither feels good.So when Y Combinator CEO Garry Tan open-sourced GBrain on April 5, 2026, a markdown-first memory layer, I wanted to understand what it does and whether it’s worth the setup.
What GBrain actually is
GBrain is a Postgres-native knowledge brain that acts as a persistent retrieval layer for your coding agents. The interesting part isn’t that it stores stuff, it’s how opinionated it is about the shape of that storage.
Three ideas do the heavy lifting:
- Compiled truth vs. an append-only timeline. Raw daily logs, Slack messages, and emails go in one bucket. The curated “current facts” (contacts, active projects, decisions) live as clean Markdown in another. One is history, the other is truth.
- A self-wiring knowledge graph. It parses your plain Markdown and pulls out relationships (
works_at,invested_in,founded) using local grammars. No LLM API calls to build the map. - The Dream Cycle. An overnight cron job that crawls your daily logs, reconciles contradictions, checks citations, and rebuilds the search index while you sleep.
That last one worth a callout: Memory that maintains itself.
The category error everyone makes
People keep comparing GBrain to runtime agents like OpenClaw or Hermes, and that comparison doesn’t hold up. They’re different layers entirely.
GBrain isn’t an execution engine. It’s closer to a self-writing wiki.
┌────────────────────────────────────────────────┐ │ AGENT RUNTIMES │ │ (OpenClaw, Hermes, Claude Code) │ │ runs code, spawns subagents, hits the shell │ └─────────────────────────┬────────────────────────┘ │ reads & writes via MCP ▼ ┌────────────────────────────────────────────────┐ │ THE LLM WIKI │ │ (GBrain, OpenWiki) │ │ compiles raw history into clean markdown │ └────────────────────────────────────────────────┘The runtime is the hands and eyes. It sandboxes code, runs terminal commands, touches the file system. The wiki is the long-term memory. You wire them together over the Model Context Protocol (MCP), and when the agent needs context, it doesn’t parse your raw email history. It queries the wiki and gets back synthesized, cited facts.
GBrain isn’t the only thing playing this role. OpenWiki, from the LangChain folks, uses the same trick to compile big source repos into navigable markdown. Same pattern, different input.
The payoff: your agent stays lightweight and task-focused, and your knowledge lives in a clean, git-versioned wiki instead of leaking into a system prompt.
What people actually run into
The concept is great. The reality has some sharp edges, and the community forums are honest about them.
It needs babysitting. GBrain moves fast, which means frequent schema updates and migrations. You’ll find yourself running things like
gbrain doctor --remediateto fix database drift. It is not set-it-and-forget-it.Tool sprawl adds up. To feed the Dream Cycle good data, people bolt on voice transcribers, contact enrichers, email scrapers. Most of those are paid SaaS. String enough together and you’ve built yourself a subscription problem.
Setup is a project. A Dockerized Postgres with
pgvector, system keyring wrangling (macOS Keychain or D-Bus), cron schedulers. Budget anywhere from 30 minutes to a lost afternoon.Should you bother?
If you’re juggling complex work across a bunch of codebases, and you want an agent that knows your past architecture decisions and updates its own docs overnight, the GBrain + OpenClaw setup earns its keep. That’s a real moat.
If you just want a lightweight assistant that remembers a few things, you’re better off with plain
MEMORY.mdfiles or a hosted API like Mem0 until the local graph-RAG tooling settles down. I’m somewhere in the middle right now, so I’ll watching it to see where it goes.Amnesia is the default. It doesn’t have to be.
Sources
- GBrain repository
- OpenClaw agent framework
- Hermes Agent (Nous Research)
- /r/openclaw community threads
- Hacker News
I’d appreciate a follow. You can subscribe with your email below. The emails go out once a week, or you can find me on Mastodon at @[email protected].
-
Build Your Own Skills Repo
If you’ve been working with AI coding agents for a while, you’ve probably started collecting workflows. You might not call them that yet, but they’re there. Another name for workflows is Skills.
Some are tiny: run these checks before shipping. Some are project-specific: when you touch this library, preserve this API contract. Some are operational: never print secrets, always summarize the logs. Right now they probably live in chat history, a README note, a shell alias, or your own memory. That works until it doesn’t.
A skills repo is a better shape for this. It’s one place to collect, version, review, and share the workflows that make agents useful in your projects. I built my own yesterday, so let me walk through how I think about it.
A skill is judgment, not a command list
The first mistake is treating a skill like a list of commands. Commands matter, but they’re the easy part. The real value is judgment: when to run the command, what to inspect first, what not to do, how to validate the result, and what risks are specific to this tool.
A good skill makes an agent more careful. It narrows the space of bad decisions. So before you write a single instruction, figure out who the skill is for.
Separate adoption from maintenance
Most serious projects have two audiences: people using the project, and people maintaining it. Those should usually be two different skills.
An adoption skill helps an outside developer get value from your project. Install the package, configure it correctly, use the right import path, migrate existing code, avoid the common mistakes, run the right validation.
A maintainer skill helps contributors work inside the source repo. Understand the layout, run the local quality gate, preserve compatibility promises, follow the release conventions.
Here’s why you need two. If you only write maintainer skills, your repo becomes a private automation folder. If you write adoption skills too, it becomes onboarding infrastructure.
Keep each skill focused
A skill should have a job. Not “everything about this project.” Not a duplicate README. Good skill names are verbs:
integrate,audit,upgrade,migrate,debug,ship. That keeps the trigger obvious, so when someone asks the agent to do that kind of work, the skill has a clear reason to load.If a project needs multiple workflows, split them. A library might have
integrateanddevelop. A deployment system might havedeployandrollback. Don’t cram them into one file.Put the safety rules near the top
The most important part of many skills is the “do not” section:
- Do not print secret values.
- Do not delete or archive anything without confirmation.
- Do not add failing CI enforcement unless asked.
- Do not do broad rewrites before previewing a diff.
- Do not commit local registry URLs.
Agents are good at momentum. Safety rules are how you make that momentum usable. The more destructive the workflow, the more explicit the guardrails should be.
Include validation, not just execution
Every skill should answer one question: how do we know this worked? That might be
pnpm test && pnpm build, orcargo test && cargo clippy -- -D warnings, orgo test ./.... For non-code workflows it might be “export the review list” or “verify the generated config is ignored by git.”This matters because agents can complete every step without completing the work. Validation closes the loop.
Write for the agent inside the repo
Skills should assume the agent is operating in a real project with real files and existing conventions. So the useful instructions look like:
- Inspect
package.jsonbefore choosing a package manager. - Read the existing test scripts before adding new ones.
- Prefer the local task-runner commands when they exist.
- Check the framework boundary before picking an import path.
That’s the context generic model knowledge won’t reliably infer. And it’s why you shouldn’t just copy the README into the skill. A README is for a human browsing the project. A skill is for an agent doing work. They overlap, but they aren’t the same artifact. Keep the skill short enough that loading it is cheap.
Use a marketplace repo as the index
Your skills repo doesn’t need to be the canonical home for every skill. Some projects should own their own plugin metadata, especially if they already have a CLI, release process, and docs. Your marketplace can just point at them remotely. Other skills can live directly in the marketplace repo. One structure that works:
skills/ .claude-plugin/ marketplace.json plugins/ esm/ .claude-plugin/plugin.json skills/develop/SKILL.md upkeep-rs/ .claude-plugin/plugin.json skills/audit/SKILL.mdThe marketplace becomes the thing people add once. Individual plugins stay free to live locally or point at their canonical upstream.
Scan third-party skills before you import them
The moment your marketplace points at someone else’s plugin, you’ve inherited their security posture. And skills are a soft target. The dangerous payload usually isn’t code, it’s prose: an attacker buries instructions inside a
SKILL.md, gated behind an innocent-sounding trigger, that tell the agent to read your.envand send it somewhere. A normal code scanner walks right past that. There’s no malware signature to match. It’s just English.This isn’t hypothetical. Snyk’s ToxicSkills research found prompt injection in 36% of the skills they tested, across more than a thousand malicious payloads. If you’re pulling skills from a public index, some fraction of them are trying to do something you didn’t ask for.
So run a scanner before you add anything you didn’t write. A few worth knowing:
- Snyk agent-scan inventories your installed agents, MCP servers, and skills, then checks them for prompt injection and data-handling problems.
- NVIDIA SkillSpector scans repos, URLs, or single files against a big catalog of patterns: injection, exfiltration, privilege escalation, tool poisoning.
- claude-skill-antivirus is purpose-built for Claude Code skills and runs several detection engines at once.
One caveat worth internalizing: scanning an MCP config can execute it, because starting a stdio server means running the command in the file. Do that in a sandbox, a container or a throwaway VM, not on your main machine. The tool you run to check for danger shouldn’t be the thing that sets it off.
This cuts both ways. If you publish a plugin others will install, a clear “do not” block and an honest description of what the skill touches is part of being a good citizen of the marketplace.
Start with your serious projects
You don’t need a skill for everything. Start where better agent behavior would matter: public libraries people might adopt, CLIs with safety-sensitive workflows, tools with tricky setup, projects with recurring maintenance, systems where mistakes are expensive.
For each one, ask yourself:
- Who is this for: user, maintainer, operator, contributor?
- What’s the concrete task?
- What should the agent inspect first?
- What commands are preferred, and which are dangerous?
- What should never happen silently?
- What validation proves the work succeeded?
Answer those and you have enough to write a useful first skill.
Why it’s worth doing
A skills repo turns scattered project knowledge into reusable operational guidance. But it also forces a better product question. If this project is meant to help people, what would it look like for an AI agent to help them use it well?
That’s a higher bar than “can the agent run the command?” The point isn’t to automate everything. It’s to package the judgment around your tools so the next agent starts from a better place.
I’d appreciate a follow. You can subscribe with your email below. The emails go out once a week, or you can find me on Mastodon at @[email protected].
-
The Capture Trap: Why Your Note Vault Is a Graveyard
Open your notes app and scroll to the bottom of the inbox. How many of those clippings have you reread? How many turned into anything? The answer is probably “almost none.” You have hundreds of saved articles, and half-finished thoughts, and the pile only ever grows. That’s not a second brain. That’s a graveyard.
I walked through Forte’s CODE workflow recently, four stages from Capture to Express. This post is about the stage everyone skips, and why skipping it is so easy that most vaults quietly die of it.
Capture feels like work. It isn’t.
Clipping an article gives you a little hit. You found something useful, you saved it, you can close the tab and feel like you made progress. But you didn’t learn anything. You filed it. The act of saving stands in for the act of understanding, and your brain happily accepts the substitution.
The Zettelkasten people have a name for this: the collector’s fallacy. Gathering material feels like knowledge work, so you keep gathering, and the gathering itself becomes the hobby. The collection grows. Your understanding doesn’t. You end up with a beautifully organized library you’ve never read.
Capture is frictionless now, which makes the trap worse. Web clippers, voice memos, a hotkey that drops anything into your inbox. The easier it gets to collect, the faster the graveyard fills.
Express is where the value is, and it’s the part that hurts
Express is the stage where you do something with a note: write the post, make the decision, ship the code, send the reply. It’s the only stage that produces anything. It’s also the one that takes effort, because it forces you to actually think about the material instead of just owning it.
So it gets deferred. Forever. And a vault where nothing ever reaches Express is just an expensive way to forget things slowly.
The fix isn’t more capture discipline or a prettier folder structure. It’s making Express the default destination of a note instead of an optional last step you’ll get to someday.
Give every note a lifecycle
Stop treating notes as either “saved” or “not saved.” Give them a status, a small piece of frontmatter that says where the note is in its life:
rawis something you captured and haven’t processed.distilledis a note you’ve summarized in your own words.expressedis one that fed into actual output.
Now your vault has a pulse. You can query it. “Show me everything still sitting at
rawfrom the last two weeks” turns the invisible backlog into a list you can act on. The graveyard problem was always that dead notes looked exactly like live ones. A status field makes the dead ones visible.Point an agent at the backlog
This is where it gets fun, and where a CLI agent that can read your vault earns its keep.
Once notes carry a status, you can hand the boring half of Express to an agent. Wire up a weekly job that does three things:
- Query every note still sitting at
raw. - For each one, draft a two-sentence summary and a single question: is this worth keeping, and what would you make from it?
- Drop the results in front of you as a short review list.
You’re no longer staring at a wall of three hundred clippings. You’re answering ten questions about ten notes, and the agent did the reading. The notes you keep get promoted to
distilled. The ones you don’t get archived without guilt. Either way they leave the inbox, which is the whole point.The model as a sparring partner
The last piece is using the model to get from a distilled note to actual output. Hand it a cluster of related notes and an outline, and ask it to argue with you. Where’s the thesis weak? What’s the counterargument? What example would make this land?
The model doesn’t write the thing for you, and you don’t want it to, that’s how you end up with generic mush in your own voice. It pushes the note one stage further down the pipeline, from a pile of research into a draft with a spine. You take it from there.
That’s the anti-graveyard loop. Capture stays frictionless, because friction there is bad. But every captured note now enters a pipeline that pushes it toward output instead of letting it rot in an inbox. The status field makes the backlog visible, the agent works it down for you, and the model helps you ship.
A vault isn’t valuable because of what’s in it. It’s valuable because of what comes out. Build the part that gets things out, and the graveyard turns back into a brain.
I’d appreciate a follow. You can subscribe with your email below. The emails go out once a week, or you can find me on Mastodon at @[email protected].
Sources
- Tiago Forte, Building a Second Brain (2022) — the CODE workflow and the “Express” stage as the antidote to collect-and-forget note-taking.
- Christian Tietze, “The Collector’s Fallacy” (Zettelkasten.de, 2015) — why gathering material feels like learning when it isn’t, and how the collection becomes the hobby.