Inspiration

Hazel.

I have used Hazel on my Mac for years. You give it rules, it watches folders, it moves things around. It is good software and I am not building a replacement for it out of dissatisfaction.

I wanted the same thing for the cloud as Hazel only runs on my Mac Studio, on files sitting on my disk. Everything that actually arrives now arrives somewhere else: a Drive folder, an email attachment, a phone that photographs a receipt and syncs it. Hazel cannot see any of that, and the tools that can see it do not do what Hazel does.

So the starting point was narrow: Hazel, but for a Drive folder, and running somewhere that is not my Mac.

The good thing about Orden, is that once a model reads it, an issuer you have never seen needs no configuration, and there is no template to break. No need to create new rules daily.

What it does

Drop a file into one Drive folder. Orden reads it, works out what it is and who sent it, renames it to a consistent convention, and moves it into the folder where you already keep that kind of thing.

Below a confidence threshold it does not file at all. It leaves the row unticked, shows its reasoning, and asks.

It handles PDFs, Word files, spreadsheets, plain text and raw email; photos and screenshots, with the text read straight off the image; audio, transcribed and searched for commitments; and saved .webloc and .url links, filed by what they point at. It reads the document in whatever language it is written in and answers in yours.

Then the part that filing was only ever a prerequisite for. Once a year of documents has been read and recorded, arithmetic over that record answers things no filing tool can:

  • This arrives every month. Three documents from one sender at a steady interval are a series, so it works out the rhythm, the typical amount, and when the next is due.
  • This one costs more than usual. Measured against the median of the earlier ones rather than last month, so one estimated meter reading cannot redefine normal. Under 15% it stays quiet.
  • This one never came. The only thing in Orden concerning a file it was never given, and the one that costs money, because the unpaid invoice is the one nobody put in the inbox.

None of that costs a model call or a Drive call. It is arithmetic over what filing already recorded.

It also speaks. Gemini writes half a minute from the ledger and the alerts, a text-to-speech model reads it, and it plays at the top of the Insights tab.

Dates it read off a document go on a calendar it creates and names after itself, separate from yours.

And it learns. Correct it once and say why, and that sentence becomes a rule the classifier is shown on every later run. The History tab reports the agreement rate, the share of its decisions left standing.

How we built it

One rule: orden/core/ imports no vendor SDK. It imports Drive and Gemini and nothing else. No agent framework, no web framework.

Around it, two thin things. adapters/adk.py exposes the core as eight Google ADK tools. web/app.py is a FastAPI panel calling the same core directly.

I did this because I am entering several hackathons with different required SDKs and did not want to write the agent more than once. It paid off in a way I did not expect: the ADK agent and the panel are the same agent, not a library with two divergent copies of the logic on top. Fixing a filing bug fixed both.

The stack:

  • Gemini 3.6 Flash (gemini-3.6-flash) reads every document. Pinned rather than tracking -latest, so an upstream release cannot change how my documents are read without my knowing.
  • Gemini TTS (gemini-3.1-flash-tts-preview) speaks the brief.
  • Google ADK 2.7.1 exposes the core as tools.
  • Cloud Run (europe-west1) runs it, Firestore holds the state, Cloud Scheduler runs the safety net, Secret Manager the credentials.
  • Drive API v3 files, Calendar API v3 writes the dates it found.
  • FastAPI and Uvicorn on Python 3.13, in a slim Docker image.
  • The frontend is HTML, CSS and JavaScript with no framework, no CDN and no build step. Templates are read off disk and served as strings.

Drive pushes changes, so filing happens as files land. The hourly scheduled job exists because Drive expires notification channels within a week and renews nothing itself, and it re-reads the inbox in case a push was missed.

Challenges we ran into

A pinned dependency, found the hard way. google-api-core above 2.34.0 percent-encodes the Firestore database path. The default database is named (default), so the parentheses became %28 and %29 and every read failed with "400 Invalid database id". Nothing in my code could reach it; passing the name explicitly is encoded the same way. It only ever broke deployed, because the container installed the newer version while my laptop kept the older one. It is pinned now with a comment explaining why, because I would otherwise have unpinned it later.

Showing a learning loop is harder than writing one. Orden improves by being corrected, and History reports the agreement rate. A new demo has no history, so it has nothing to show. A rhythm is not a rhythm until a year of documents says so. The hosted demo therefore starts from a seeded past: sixty-odd filed documents, the corrections made along the way, and the rule those corrections hardened into, written as the same two ordinary store documents the real thing uses. Nothing is faked; the demo is given a history. Everything from there runs live.

Deciding not to ship the obvious feature. The hosted demo will not connect to your Drive. It is enforced, not discouraged: ORDEN_ALLOW_DRIVE=0, and the deployment refuses every endpoint that is not the demo. A public URL with one person's Drive behind it and no user accounts answers a stranger as readily as its owner. I would rather ship an honest demo than bolt a login onto thirty-one endpoints in the last week.

Cloudflare in front of Cloud Run. The proxy rewrites the Host header, Cloud Run matches a domain mapping on exactly that header, so a proxied DNS record answers 404. The same header is where sign-in derives its OAuth callback, so proxying breaks that too. Every record has to be DNS-only, the grey cloud.

A demo that argued against itself. It used to open with a guided tour explaining what you were about to see. It took me two weeks to notice it was pre-teaching people the exact rule they were about to teach it themselves, which is the one moment the whole product is about. The fix was one line.

Accomplishments that we're proud of

The core imports no vendor SDK, and that is verifiable rather than claimed. orden/core/ imports google.genai and googleapiclient and nothing else. No ADK, no FastAPI. The agent could be driven by a different framework tomorrow with one new file and no rewrite.

It asks instead of guessing. Every row carries a percentage and a written reason. Below the threshold Orden leaves it unticked, so approving the rest never files something it was unsure about. Every action is undoable, and undo takes the calendar events it created with it.

Deleting the clever part. I built a two-model design where a cheap model screened each file before the expensive one read it. Measuring it honestly and removing it was the single most useful change I made, and it consisted entirely of deleting code I had been pleased with.

A number that says whether the loop works. Plenty of things remember what you told them. The agreement rate says whether remembering changed the next decision for the better, and it is on screen rather than in a blog post.

What we learned

A cheap model in front of the expensive one is a false economy. The screening model vetoed nothing on a real archive while costing a call per file. The junk it was built to catch is rare, and discarding an invoice by mistake costs far more than a wasted read. One model, one path, is both cheaper and easier to reason about.

Filing is extraction, not deliberation. The answer is on the page. Measured on a rental letter, thinking spent 1,509 tokens and 5.5 of the call's 7.5 seconds to reach byte-identical values for category, destination, confidence and name. If

$$ \text{output}{\text{thinking}} = \text{output}{\text{direct}} $$

then the budget buys nothing but latency, so it is off by default. A detail that cost an afternoon: the budget is 1, not 0. Gemini 3.5 accepted 0; Gemini 3.6 rejects it with a 400 on every call, so pinning the model forward without changing that integer takes the whole agent down.

Cache on the content, not the identifier. The ledger keys on Drive file id, right for "have I filed this?" and wrong for "have I paid to read this?". The same bytes uploaded again get a fresh id, so every demo rehearsal was a full multimodal read. Reads are now keyed on the SHA-256 of the content plus the prompt. The prompt being in the key is what makes it safe: correcting a mistake invalidates exactly the entries whose reasoning changed, and nothing else.

The unglamorous constraints shape the architecture, not the model. Cloud Run discards an instance's filesystem between revisions, so state lives in Firestore. Firestore caps a document at 1 MiB, which is what sets the cache ceiling at 80 entries.

What's next for Orden: Drive intelligence

Orden reads a folder and files what it finds. Everything next widens one of those two ends: where the documents come in, or what it may do once it has understood one.

The daily brief, delivered. The brief is written and spoken today, at the top of Insights. What it cannot do is reach you without being opened. Next it arrives on its own, as a private podcast feed you subscribe to in the app you already use, or as a message. That needs a signed per-user feed URL, somewhere to keep a fortnight of audio, and a schedule that writes the brief before you wake rather than when you ask.

A calendar that stays in step. Today a date read off a document is written once. Next it keeps step both ways: a renewal that moves in an amended contract moves the event, a deleted file takes its dates with it, and an event you edited by hand is left alone. That needs a stored link from each event back to the document and the sentence that produced it, so a change can be traced rather than guessed.

Attachments straight from email. The invoice in your inbox is the one document that never reaches the folder Orden watches. An address of its own, so forwarding a message puts its attachments in the queue with sender, subject and date already known. The hard part is proving the sender rather than trusting them: an address anyone can post to is an address anyone can file into your Drive with.

Decisions that do more than file. Filing and renaming are the two safe things to do with an understood document. There are others: reply to a sender that a bill was received, flag a contract before it lapses, hand figures to a script you already run. Each would be a named action switched on one at a time, never a general licence to act, and each has to be reviewable before it runs and undoable after, or it does not ship.


August 2026. MIT licensed.

Built With

Share this project:

Updates