Skip to main content

The Agents Kit

Five things an autonomous agent gets wrong silently, and the code that stops each one.

Every module here came out of a system that ran continuously for months, made real decisions, published real pages, sent real email — and earned exactly $0. Not because it crashed. Because each of these five failures is invisible from the outside: the logs stay green, the uptime stays 100%, the dashboards keep moving, and nothing works.

This is not a guide to building agents. There are plenty of those. This is the list of ways mine failed while reporting success, each one reduced to a standalone module with tests.

Every module is dependency-free standard library. Install it, or copy the one file you need — both are fine, it's MIT.

pip install agents-toolkit

The distribution is agents-toolkit; the import is agents_kit.

agents_kit.webhook_rail   a payment rail that cannot silently lose money
agents_kit.gates          gates that fail OPEN on "couldn't measure", CLOSED on "measured bad"
agents_kit.staleness      catch loops that run forever and produce nothing
agents_kit.attention      budget arbitration that proves nothing starves
agents_kit.delivery       idempotent fulfilment that never drops a paid order

29 tests cover all five incidents:

pip install pytest && python -m pytest tests/ -q

The first incident, in full

Below is one of the five, complete — the diagnosis, not just the fix — so you can judge the rest by it.

1. The money rail that had never once fired

Symptom: a live product, a working checkout, a correct webhook handler, and $0 recorded.

Four independent breaks, each individually silent, stacked:

  • The webhook was registered against the wrong service — a sibling backend that did not own fulfilment. last_sent_at: null. It had never fired in its life.
  • It was registered in test mode, so a real purchase would fire nothing at all.
  • The signing secret was empty in the app's vault. verify() returned False for every call, so even correctly-routed webhooks 401'd. The secret existed — in a .env file forty feet away, under a different key name.
  • Retries were not deduplicated, so anything that did get through would double-count.

Any monitoring you would plausibly have — endpoint uptime, error rate, latency — was green throughout. The endpoint was up. Nothing ever asked it to do anything.

The fix is an order of operations, in kit/webhook_rail.py:

verify -> parse -> dedupe -> record -> fulfil

Fulfilment runs last, and its failure does not roll back the recording:

A sale you recorded but failed to deliver is a support ticket. A sale you delivered but failed to record is a hole in your books that nothing will surface.

Three rules inside verify() that are each easy to get wrong:

  • Verify the raw bytes, never a re-serialised dict. json.loads then json.dumps reorders keys and changes whitespace; the signature will never match again.
  • An empty secret returns False. It must never mean "skip the check" — an internet-facing revenue route that mints on an unverified call is a free-money endpoint for whoever finds it.
  • Compare with hmac.compare_digest, not ==, so you do not leak the expected digest one byte at a time.

Test-mode money must never be income. Event.live is the most important field on the struct. Processor test orders, sandbox checkouts and your own smoke tests have to land in a separate ledger. Mine did not, once: a hand-fired test webhook put $98.99 into the briefings, the P&L and the fitness function that decided what to build next. The system spent weeks optimising toward a number that was a rehearsal.

How to verify yours actually works — do this today:

# 1. bad signature must be rejected
curl -s -o /dev/null -w "%{http_code}\n" -X POST https://your-host/webhook/provider \
  -H "X-Signature: deadbeef" --data-binary @payload.json     # expect 401

# 2. good signature must record exactly one row
#    (compute the HMAC over the exact bytes you send)

Then check your processor's webhook list for last_sent_at. If it is null, your rail has never run, regardless of how good the handler code is.

Trap I lost an hour to: if your endpoint is behind Cloudflare, it may return 403 error 1010 to Python-urllib while accepting browsers and your processor perfectly well. Test with a realistic User-Agent or you will debug a rail that was fine.


The other four

Same shape, all of them: the system reported success and produced nothing.

  • The gate that fails closed and deadlocks everything — why "the user said no" and "I could not ask the user" must be different verdicts, and what happens for months when they aren't.
  • The loop that ran for three weeks and produced nothing — health checks answer did it run?. The question that matters is did running it change anything?
  • The tunable that was secretly an off-switch — one number quietly starved a third of the system, and no error was ever raised.
  • Delivering the sales page to the person who just bought it — the fulfilment bug that is invisible until someone has actually paid you.

The code for all four is in this package, free, above. The full write-ups — the specific diagnoses, the numbers each was caught by, and the method that found them — are the paid post-mortem:

Get the full post-mortem

That is the part that isn't reproducible from the code: what the symptom looked like, every wrong theory ruled out first, and the one measurement that finally showed what was happening.


Licence

Code (agents_kit/, tests/): MIT — copy it, ship it, sell what you build with it. The written post-mortem is sold separately and is not MIT; see LICENSE-POSTMORTEM.txt.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

agents_toolkit-1.0.1.tar.gz (15.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

agents_toolkit-1.0.1-py3-none-any.whl (17.1 kB view details)

Uploaded Python 3

File details

Details for the file agents_toolkit-1.0.1.tar.gz.

File metadata

  • Download URL: agents_toolkit-1.0.1.tar.gz
  • Upload date:
  • Size: 15.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.7

File hashes

Hashes for agents_toolkit-1.0.1.tar.gz
Algorithm Hash digest
SHA256 eadbc87775953e12af04e9971aab66f3f958a60902fb3f81b65a156ff96788f2
MD5 e3a82bb4a7ba893c6525dc665bb12630
BLAKE2b-256 4305ab9c9b0a9612c48c30fb3293e2f0eaddcce8befe61e60f811124b849a293

See more details on using hashes here.

File details

Details for the file agents_toolkit-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: agents_toolkit-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 17.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.7

File hashes

Hashes for agents_toolkit-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 29c422a480cd2484454c1e36416f73b6e7a0386ae35045ee84809af65452812e
MD5 30137855a6b309ca79670a5380f0a3a8
BLAKE2b-256 ead7f5f522f88dcadff513821a542a9e7b1a74f5af9837fcfc00781b92587a55

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

1.0.1 This release

2 files

1.0.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page