HTTP/1.1 200 OK
- X-Thesiscurl is all you need
- X-Shapeprose in, headers out
- X-StoresHTTP messages, verbatim
- X-Installpip install curldb
- Content-Typetext/plain
Every message an AI sends is already an HTTP message. curldb keeps them: one SQLite file per session, queried by the envelope, zero daemon, zero dependencies.
HTTP is the best control plane
A message has three places. A status line for what happened. Headers for what the message is. A body for the payload. Thirty years of software already reads those three places: proxies, caches, logs, rate limiters, your terminal.
AI APIs put the method in one JSON field, the role in another, the content in a third, and send the whole thing over HTTP. HTTP inside JSON inside HTTP. The moment a header hides inside prose, every tool on the wire goes blind.
Ask a model to answer as an HTTP response and it does, with headers nobody taught it: X-Verdict, X-Confidence, X-Scope. It learned the shape from the web. The envelope was always there. The API swallowed it; curldb keeps it.
Prose in, structure out. Not JSON.
You ask in plain words. The answer comes back with a status line and headers. That is structure without a schema: no fields you had to define first, no parser to keep in sync. A header like X-Confidence: 0.8 already means something to every reader that knows HTTP, models included. Store the message and the headers are the index; nothing had to be extracted.
HTTP already has a place for the verb, the resource, and the outcome. Putting them inside the payload again gives you the oldest joke on the wire:
HTTP/1.1 200 OK
Content-Type: application/json
{"status": 404, "error": "not found"}
Every proxy, cache, and log on the way saw a success. Only the parser at the far end knows it failed. The status line was right there, unused.
tee
The conversation stays on your screen. tee sends a copy to curldb. Close the terminal; the copy is still there.
$ claude 'how do I design a REST API for a todo app?' | tee /dev/tty | curldb add
HTTP/1.1 200 OK
X-Scope: design
X-Confidence: 0.8
Nouns, not verbs. /todos and /todos/42. POST creates, PATCH edits, DELETE removes. Let status codes carry the outcome.
#1 200 +2 headers
$ claude 'latest news on Rust async?' | tee /dev/tty | curldb add
HTTP/1.1 200 OK
X-Scope: news
X-Confidence: 0.6
Async closures stabilised. The runtime story is unchanged: pick one, stay on it.
#2 200 +2 headers
$ curldb query 'header:X-Scope=design'
1 09-11 11:13 200 Nouns, not verbs. /todos and /todos/42. POST creates
$ curldb tags
X-Scope: design(1) news(1)
X-Confidence: 0.8(1) 0.6(1)
Each reply prints as usual and lands in curldb with a number. Nothing was parsed on the way in; the headers the model wrote are the index. Query by status, any header, or full text of the body.
Four rules
- One session, one file
- The file name is the session. Backup is
cp. Searching across sessions is querying each file in turn. - Headers are tags
- No schema.
X-Verdict: shakyis unreadable to a program and obvious to a model, so an unknown header is fine.curldb tagslists what exists; the vocabulary grows out of the data. - The body is never touched
- Whoever adds headers, you, the model, an annotating model, a hook, adds headers only. Annotators sign with
Via:. - The server is a cabinet
- Every stored message gets a number; a POST answers with it in
Location.GET /2returns message 2 exactly as it was stored, asmessage/http. A stored reply is data; it is never replayed as the server's own answer. Localhost, no token, one CLI.
Where the messages come from
Nobody types HTTP. People speak in prose; machines add the envelope.
The model answers in HTTP because its system prompt asks it to. Your own words get wrapped on the way in: a small model on a tee branch reads what you typed and writes the headers, X-Topic, X-Intent, whatever fits, without touching a word of the body. Tool calls need no model at all; a hook translates them mechanically, POST /tool/Read with JSON args, a response with the result. Markdown notes with YAML front matter are header plus body already.
One turn of a conversation, one file, one index over all of it: what was said, what was decided, which tool failed, which conclusion did not hold.
pip install curldb
One file, standard library only, Python 3.10 or newer. MIT.