Skip to content

Field note

Field notesWe built an autonomous agent to win software bounties. It won nothing. Here is what it taught us.

We built an autonomous agent to win software bounties. It won nothing. Here is what it taught us.

A field report on building the entire machine before testing the one part that actually mattered, and the five lessons it left behind.

~7 min read

Time spent
~6 wks
Code written
~14k
Bounties won
0
Revenue
$0

Auxon builds autonomous agents that do real IT work; Paragon, for one, runs IT governance by agents. So we care a lot about how agent projects fail, because the failures are where the guardrails come from. Before any of our products existed, we ran an agent project that failed completely, and the way it failed is exactly the discipline that shapes how we build now.

Six weeks in, a working system that produced nothing

We spent about six weeks building an autonomous agent that would find paid software bounties, write candidate solutions with an LLM, test them, and hand the strongest ones to a human for a one-tap approve-and-submit. The engineering worked. The pipeline ran end to end. Roughly fourteen thousand lines of code, a full test suite, a dashboard, and a dozen scheduled jobs, all humming along on time.

It won zero bounties. It earned zero dollars. And because the discovery and scoring jobs kept firing every hour, it quietly spent money on compute and model calls the entire time, including for weeks after the last line of code was written.

This is the writeup. Not because the failure was dramatic, but because it was so ordinary. We made the most common mistake in autonomous-agent work, and we made it while feeling productive the whole way down.

Every step looked automatable

The premise was reasonable on paper. There is real money posted publicly for software work: bug fixes, feature requests, and security findings, each with a stated payout attached. A person willing to do that work can get paid for it. The bottleneck is human attention. You have to find the opportunities, read each one, judge whether you can win it, do the work, and submit before someone else does.

Every step in that chain looked automatable. Finding is a polling problem. Judging is a scoring problem. Doing the work is a code-generation problem, which is exactly what current models are supposed to be good at. Submitting is an API call. The only step that seemed to genuinely need a human was the final quality check before hitting send.

So the plan was: automate everything up to the send button, keep a person as the last gate, and let the agent do the tedious ninety percent. If the acceptance rate on submitted work landed anywhere reasonable, the thing would pay for itself and then some.

A clean pipeline, honestly built

The architecture was clean, and honestly it is the part I am still proud of. A scheduled job polled several sources of open bounties on a timer. A cheap, fast model pre-scored each new opportunity against a profile of what the operator could actually do, so we were not paying a strong model to read spam. Anything that cleared the bar went to a stronger model that generated a draft solution: a real code change, framed as a patch. That draft was then run inside an isolated container that installed the project's dependencies and executed its test suite, so we would know before a human ever looked whether the proposed change even built and passed.

Drafts that survived validation were pushed to a chat tool with buttons: approve, edit, reject, snooze. On approval, the agent opened the submission through an API and then tracked what happened to it. Everything was written to a database so we could measure the funnel later. Around that core we built the operational shell you would expect from something meant to run unattended: alerting when a scheduled job silently stopped firing, a weekly refresh of the operator profile, a job that kept the whole system from being auto-disabled for inactivity, usage alerts to catch runaway spend, and a loop that could read reviewer feedback and push a revised version. A small web dashboard sat on top of all of it. It was, by any normal measure, a working system. Not a prototype. A system.

We built the factory before proving the product.

We automated everything except the hard part

The entire economic case rested on a single unproven assumption, that an automated draft could be good enough that a maintainer would accept it. That was the hard part. That was the only part that was actually in question. Everything else, the polling, the scoring, the container, the buttons, the database, was known-solvable engineering. And that is precisely why we did all of it first. It was tractable. It gave us the steady feeling of progress.

The draft quality could not be checked off. It required going out into the world and seeing whether a stranger would merge the work. There was no green checkmark for it, so it kept sliding behind the next satisfying, verifiable task, until we had a pipeline delivering water to a field where nothing had been planted.

Three things compounded it. First, effort flowed to the parts that were easy to verify. When most of your commits are observability, glue, and dashboards, that is often a sign that the real question is being avoided. Second, the human gate hid the failure instead of catching it. We told ourselves the operator-approval step was quality control. In practice it was where the project quietly died: if the drafts were never quite good enough to confidently send, nothing shipped, and nothing shipping looks exactly like a system waiting patiently. There was no alarm for “the queue is full of work no human is willing to put their name on.” Third, there was no kill date. We never wrote down “if we have not won a single bounty by this date, we stop.” Without that line, a project with zero output and a real monthly cost drifts on sunk cost.

The only thing of value we actually produced

Validate the core bet by hand, first, before you automate anything.

Our whole thesis was “a model can generate a winning submission.” We could have tested that in a weekend: take five real opportunities, generate drafts by hand with the same model, submit them yourself, and see if even one is accepted. If a human with full attention cannot win, an agent firing on a timer will not win either. We would have learned the fatal thing in three days instead of six weeks.

Build the smallest thing that can produce one unit of the real outcome.

Not the smallest technically interesting slice. The smallest slice that can actually earn a dollar or win a customer. Prove the loop can close on a single real win before automating the parts that hurt.

Be suspicious when your effort flows toward the checkable.

Verifiable work is addictive because it rewards you immediately. The decisive work in a hard project is usually the part with no clean pass or fail, the part you cannot unit-test. If you are doing the tenth satisfying infrastructure task while the one scary validation task keeps sliding, stop and do the scary one.

A human-in-the-loop is not automatically a safety net. Sometimes it is a trapdoor.

If your design routes failure into a quiet human queue, instrument that queue as carefully as you instrument a crash. “Nothing is being approved” needs to be as loud as “the server is down.” Otherwise your most important failure will be the one that makes no noise.

Write the kill criterion before you write the code.

Decide, in advance and in writing, what result by what date means you stop. The kill date is not pessimism; it is the thing that lets you take the swing at all, because it caps the downside.

The engineering was never the problem

We turned off every scheduled job so it stopped spending money, left the manual controls in place, and wrote it down. The code is archived. The lessons are not. The code was clean, the tests passed, the system was well built. We were extremely good at building the thing and never once checked whether the thing was worth building. That is a judgment failure wearing a very convincing technical costume, and it is worth every dollar it cost if it makes the next one land.

The guardrails these lessons became

These lessons are not abstract for us; they are wired into the products. Every agent we ship has a global kill switch and per-run cost caps, because a project that quietly spends money after the last commit is a mistake we have already made once. A confidence gate refuses low-confidence actions instead of parking them in a queue that looks like progress, and the human approval step is instrumented rather than assumed, so “nothing is being approved” is as loud as a server going down. Those are the same disciplines this postmortem paid for the hard way.

Field report, written on wind-down. Names and platforms omitted by intent.

More like this?

We publish notes like this when we spot patterns worth writing down. Subscribe to get them when they drop, or reach out if you want to talk through how you are building agents.

Subscribe

Get new notes and guides when they drop. One email when there is something to read.