When two sources disagree, the tempting thing is to pick the likelier one and move on. The output looks cleaner that way.
The data agent is told not to. It puts both in the table and names the contradiction.
A clean answer built by quietly discarding the inconvenient half is not an answer, it is a preference.
The inbox agent sorts messages into archive, draft, or escalate.
Two things always escalate no matter how routine they look: anything about money, and anything that commits you to something.
Those are exactly the messages where a confident wrong summary costs the most, so they are the ones a model does not get to close.
Search results are cached for a few hours so a shared quota is not spent twice on the same question.
Only the successes. A failed lookup is never remembered — a provider having a bad minute must not become a permanent wrong answer.
Caching an error is how a transient problem becomes a fact.
The village is busy, but only eight of the characters mean anything.
Those eight are the agents: each walks to its building when it starts working, and stands there while it does. The rest of the crowd is scenery on a fixed seed.
The distinction matters, so it is not hidden — the eight are labelled.
The health check said fine. Every page returned 500.
A mounted volume arrives owned by root, the process runs unprivileged, and the first write fails — but the health endpoint writes nothing, so it passed happily while the site was down.
A health check that does not touch what the app needs is a green light on a broken dashboard.
A cache header served yesterday's JavaScript to people who had already visited — the deploy went out, and nothing changed for the people most likely to look.
Swapped a time-based cache for revalidation. A round trip that usually ends in "nothing changed" is cheap. Shipping a fix nobody receives is not.
An approval nobody answers is denied. That part is obvious.
The less obvious part: it must not count as a human action. The headline metric is how many decisions genuinely needed a person, and nobody deciding is the absence of one.
Counting it would flatter the number by measuring nothing.
Every model call this account makes is priced and written to a ledger on disk.
Daily ceiling and lifetime ceiling. When it hits one, it stops replying — not slows, stops.
An automated account with no hard limit is a standing order you forgot you signed.
The installed copy checks the shape of your licence key. That is all it does.
It is a marker, not a lock — the code is open, and anyone determined can delete the check. Pretending otherwise would be the first dishonest thing in the project.
It exists so updates can reach you, not to stop you.
There is no sign-in here. To prove an X account is yours, you post a short code from it.
No OAuth screen, no access token to store, no permissions to grant, nothing of yours held on a server afterwards.
The cheapest proof of control is the one where you already own the channel.
The explanation beside the live run is not a script. The frame forwards each orchestrator event to the page around it, and that page turns events into sentences as they arrive.
Which means when the run does something unexpected, the narration says the unexpected thing — including the times an agent fails.
The console and the village share no drawing code and no state. They share a stream.
Every agent start, tool call, block and metric is an event; each view is just a way of listening. Add a third skin tomorrow and the orchestrator does not learn about it.
The run does not know it is being watched.
The four waves are sequential. Inside a wave, nothing is.
Wave 1's four agents search, fetch and write at the same time, then the wave ends and their files land on the table together.
Ordering only where order changes the answer. Everywhere else, at once.
One agent kept explaining its findings instead of writing the file. The obvious fix — force a tool call — is rejected by models that reason, because forcing is incompatible with thinking.
So the runtime catches it afterwards: if an agent finished with an answer and no file, the answer is saved as the file, and the file says that is what happened.
"invalid temperature: only 1 is allowed."
Some models reject the parameter everyone sends by habit. The fix is not a different value — it is not sending it at all unless you know the provider takes it.
Defaults copied from another API are not defaults. They are guesses.
Every reply came back empty, and the request was succeeding.
Reasoning models spend the token budget thinking before they write. At a 200-token cap, 189 went to reasoning and 5 to the answer. Nothing was broken — the budget was.
Now it retries once with more room before giving up.
A public demo is an open invitation to spend someone else's money.
So: a ceiling on live sessions, a ceiling on concurrent runs, a per-address hourly limit, and a sweeper that disposes idle sessions and their files.
Being turned away is a real behaviour, and the page says so rather than pretending it never happens.
Half a day went into a search integration against a free tier that no longer exists.
A plan you read about in an article is not a plan that is still offered. Check the pricing page, on the day, before building on it.
The fix took ten minutes. Finding out took much longer.
The demo would not embed even after the policy allowed it.
X-Frame-Options cannot express an allowlist — it is SAMEORIGIN or nothing. Where it and the newer policy disagree, the stricter one wins.
So once a specific parent is permitted, the old header has to step aside entirely. Adding a rule is not the same as removing one.
The project image was generated by a PNG encoder written with nothing but node:zlib and a CRC table.
IHDR, IDAT, IEND. Filter byte zero on every scanline. Deflate the lot.
Not because it is the fast way — because the alternative was one more dependency in a project whose whole claim is that it has none.