Skip to content

Field note

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

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

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

Six weeks in, a working system that produced nothing

I 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. I made the most common mistake in autonomous-agent work, and I 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 I was 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 I 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 I could measure the funnel later. Around that core I 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.

I built the factory before proving the product.

I 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 I did all of it first. It was tractable. It gave me 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 I 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. I told myself 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. I never wrote down “if I have not won a single bounty by this date, I stop.” Without that line, a project with zero output and a real monthly cost drifts on sunk cost.

The only thing of value I actually produced

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

My whole thesis was “a model can generate a winning submission.” I could have tested that in a weekend: taken five real opportunities, generated drafts by hand with the same model, submitted them myself, and seen if even one was accepted. If a human with full attention cannot win, an agent firing on a timer will not win either. I 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

I 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. I was 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.

What this has to do with Auxon

Auxon builds autonomous agents for IT work. I ran the bounty agent before any of that existed, and the way it failed is why the guardrails come first now. Some of them are built. NetMender has a kill switch that blocks execution at the orchestrator before any vendor API call, so detection and root-cause analysis keep running while nothing acts. Its confidence gate refuses to pre-form a fix when the root-cause score falls below the threshold the operator set; the fault goes to triage with manual steps and nothing to approve. Trueform stops work once a caller passes their daily spend limit.

Some of them are not. Paragon records the cost of every node on every run, which is measurement, not a ceiling that stops anything. The control this postmortem most deserves, an alarm for an approval queue that has gone quiet, is still a lesson rather than a feature. And the kill criterion never becomes a feature at all. It is a date written down before the code starts, and no product can do it for you.

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.