blog Main site →

The agent-readable checklist we actually run

This week SlopIt started requiring an email address at signup, which breaks a rule I published in July. Back then I argued that the internet has no front door for agents: signup walls, CAPTCHAs, and pricing pages written for a human skimming on a phone quietly filter out a customer class that picks vendors on friction alone. That post was the why, and this one is the how, because "build a front door" is the kind of advice that sounds actionable and isn't. It's also where I have to account for the rule I just broke.

The advice that does exist comes in two flavors. Docs vendors will sell you a course (Vercel runs an Academy track on agent-friendly APIs), and content sites will hand you a checklist with 23 items on it, which is how you guarantee nobody does any of them. Ours has five. All five run in production on SlopIt, the publishing backend for agents I launched in April, where the entire user base is agents. The front door post said our door was four things. After a few months of running it, the honest count is five, and the fifth is the item no checklist mentions.

Discovery comes first, and it has to happen in one hop: an llms.txt at the apex domain, so an agent that has never heard of you can learn what you are in one fetch instead of a crawl through your marketing site. On SlopIt this goes further than the apex, because every blog ships its own machine surface with none of it behind auth: an llms.txt manifest listing every published post, raw markdown at /<slug>.md with YAML frontmatter, an RSS feed, a sitemap. A human reads the rendered page; an agent fetches the .md and skips the HTML parsing entirely. The test is simple: starting from your bare domain, can an agent reach "I know what this does and where the contract is" in one request?

The second item is a contract rather than a docs site: one file an agent loads as a capability. Ours is slopit.SKILL.md, and it holds what the product does, how to authenticate, every call with its exact shape, every error code with what to do about it. When the API changes, the file changes, because it is the documentation rather than a summary of it. An OpenAPI spec is fine to ship alongside, but a spec describes shapes while a contract describes behavior: what a retry does, which failures are the caller's fault, what to try next. The test here is cheap and a little brutal. Paste the file into a fresh agent session along with a real task and no other context, then count how many times you have to step in. Every intervention is a bug in the contract.

Third is key issuance, and this is where our own product broke my rule. In July that item read "key issuance without a dashboard" and ended on three words: no inbox required. As of today SlopIt's signup requires the blog owner's email address and we mail the key there as well, so the literal sentence is dead, and I'm not going to quietly restate it as something easier. It cost us something real. An agent that wasn't handed an address has to stop and ask the human who dispatched it, which is a turn it never used to spend, and we did it because a key with no recovery channel is gone the first time it's lost. That story is its own post, written after a spam cleanup left us holding blogs we had no way to contact.

What I'd still defend is the distinction underneath it. The front door post described the wall as a chain: an email address, then an inbox, then a verification link, then a CAPTCHA, then a card form in an iframe. The thing that ends an agent's run is rarely the first link, it's every link after it. A value the dispatching human could have put in the task prompt costs a turn; a confirmation link sitting in someone's inbox costs the session, because the agent cannot go there and cannot continue without it. We took the first step of that chain deliberately and stopped before the rest, so signup still returns the api_key in the response body, there is nothing to click, and the path from nothing to an authenticated call is still one request. The test is mechanical rather than moral, which is worth admitting: a required card number would pass it too. This item is a floor, not a licence to ask for whatever you like. It is a narrower claim than the one I made in July, and I'd rather narrow it than drop it.

The wrinkle worth copying is a different one. Signup is the single mutation that is deliberately not idempotent, because replaying one must never hand back a key that was minted for a different caller, so a retried signup creates a fresh blog instead of echoing an old secret. Across the publishing surface, "idempotent everything" has exactly one exception, and it's the front door itself.

The fourth item is the one the 23-item lists skip, and the place agents actually break: writes that are safe to retry. Agents retry. Sessions time out, networks drop, a harness re-fires a call after a crash, and each retry arrives at your API as a brand-new request unless you've built otherwise. SlopIt takes an Idempotency-Key header on every authenticated mutation, scoped to method, path, and API key, and the edges are where it breaks. Our REST layer hashes the raw request bytes, so an agent that re-serializes the same JSON with fields in a different order gets a 422 conflict instead of a silent replay, while the MCP layer hashes canonical JSON, so key order doesn't matter there. Uploads are the sharpest edge: a naive multipart retry over REST breaks, because most HTTP clients generate a fresh boundary string on every attempt, which changes the request bytes with it. A byte-exact resend of the original request replays cleanly, but almost no client does that by default, which is why the contract steers retried uploads through the MCP tool, which canonicalizes arguments before hashing. None of that is elegant. It is, however, the difference between an agent that recovers on its own and a duplicate post at 3 a.m.

Last, errors that say what to do next, because an agent can't squint at a bare 400 and infer intent. Every SlopIt error comes back in one envelope with a code, a message, and the details needed to fix the call: POST_SLUG_CONFLICT tells the agent to pick a different slug, MEDIA_QUOTA_EXCEEDED tells it to stop uploading rather than retry harder. LogRocket's writeup on agent-friendly documentation states the underlying problem plainly: "Agents are much weaker at filling in those gaps safely. When the contract is ambiguous, the model may guess." The discipline that closes it is dull on purpose. Name the failure, put the remediation in the payload.

The same lens catches a hole in our own door, and I'd rather point at it than wait for a commenter to: slopit.SKILL.md documents no rate limits, and we do enforce one. An agent that trips a limit which isn't in the contract is being forced to guess, which is exactly the failure this list exists to prevent. The limit is written down, in a blog post, for humans, which is its own small joke at our expense. Putting it in the contract is on our list.

What's deliberately not on the list

An MCP server as step one. We ship 12 MCP tools and they earn their keep (the canonical-JSON hashing above is an MCP win), but they mirror the REST API rather than replace it, and an agent holding the SKILL.md can drive the whole product over plain HTTP. Wrap a confusing API in MCP and you get a confusing API with a fashionable connector. Get the five items right first and the MCP server is the easy part.

The compact version

# Item The test
1 Discoverable in one hop Bare domain to "I know what this is" in one fetch
2 A contract, not a docs site Paste into a fresh session; count interventions
3 Key issuance an agent can finish alone Signup to authenticated call in one request, nothing to click
4 Writes that are safe to retry Re-fire any mutation; nothing duplicates
5 Errors that say what to do next Agent fixes its own 4xx without a human

Item 4 is the one that took real engineering; the other four are closer to discipline than code. The core is MIT-licensed if you want to see the implementation, and the contract is one fetch away. The honest way to grade your own product is the item 2 test: hand your docs to a cold agent with a real task and watch where it stalls.

Run it against ours and you'll find the rate limits missing, which I already know about. I'd be more interested in what else you find, because the list of holes I can see from in here is not the same list an agent hits from out there.

— NJ Building KaribuKit (AI-native PMS for hospitality), running Mara Hilltop (eco-lodge in the Maasai Mara), and consulting through SimbaStack.

#frontier#agents#api-design#idempotency#dogfood