blog

April 21, 2026

HATEOAS for AI: REST's oldest idea is the right pattern for agents

An LLM is a client that's bad at remembering rules. So stop making it. Let every response carry the legal next moves.

You gave a model a set of tools and it called one at the wrong time — out of order, on a step that had already moved on. So you wrote the rules into the system prompt. “First do this, then that, never the other thing.” And you hoped.

That hope is the bug. The model is holding your entire state machine in its head, from a paragraph of prose, with no feedback about where it actually is. Of course it drifts.

The most-ignored idea in REST

It’s called HATEOAS — Hypermedia As The Engine Of Application State — from Roy Fielding’s 2000 dissertation, the document that defined REST. The idea is simple: the server’s response shouldn’t just hand back data. It should hand back the links — the actions you can legally take next, from right here, in this state. The client never needs out-of-band knowledge of the workflow; it reads a response and follows a link.

Most APIs that call themselves RESTful skip this. You memorize the endpoint sequence and hard-code the order of calls; the workflow lives in your head and in a wiki. HATEOAS says that’s backwards. The workflow should live in the responses.

Why it fits agents — exactly

Think about what a language model is good and bad at, as a client. It is bad at out-of-band knowledge: carry a multi-step set of rules across 20 turns and apply them consistently, and it loses the thread. It is excellent at reading what’s in front of it and doing the obvious next thing. Give it a response that says “here are your three legal moves,” and picking one is easy.

So don’t make the model remember the state machine. Make every response carry the legal next moves. That’s the whole pattern, and Praxec is built on it. (One honest note: this is HATEOAS-inspired. The protocol underneath is JSON-RPC over MCP, not REST with hypermedia media types. What carries over is the principle that matters — server-driven navigation through links.)

What it looks like on the wire

Start a workflow with praxec.command and the response carries a links array with exactly the legal next move — create_outline — its args already shaped: the workflow ID, the version to expect, the transition name. The model doesn’t guess the transition or skip a step. It follows the link. Note the expectedVersion: every workflow carries a version that increments on each transition, and a submit must name the version it expects, so a stale snapshot is caught with STALE_WORKFLOW_VERSION instead of silently applying a move to the wrong state.

The part that matters most: being wrong

The happy path is easy. The real test is what happens when the client gets it wrong — because a model will. Try a transition whose guards don’t pass, and the rejection still carries a links array: the model made a bad move and got back, in the same response, the moves that are legal right now. It recovers without restarting and without re-reading a prompt.

That holds across every rejection the kernel produces — STALE_WORKFLOW_VERSION, INVALID_TRANSITION, INPUT_SCHEMA_VIOLATION, GUARD_REJECTED, EXECUTOR_FAILED. A wrong call is never a dead end. It’s a response with an error code and a way forward. That’s the difference between an agent that recovers and one that spirals — hand it the legal links every time and the spiral has nowhere to begin.

Two refinements

Where the pattern stops

Be clear about the boundary: links guide the model; they don’t bind it. Nothing stops a model from ignoring a link and submitting some other transition. What stops that is a separate layer — guards and actor checks the kernel enforces regardless of what the model tried. HATEOAS-style links are the ergonomics layer that makes the right move obvious; enforcement is what makes the wrong move impossible. Complementary, and not the same thing.

REST’s most-skipped principle asked human-written clients to give up their hard-coded call sequence and trust the server’s links. Most teams didn’t want to. An AI agent has the opposite preference — it would much rather read one response and follow a link. The pattern nobody adopted for REST is the one that fits agents best.

← All posts