Inspiration
Freight operators reconcile shipment paperwork by hand: a waybill, a packing list and a commercial invoice that are supposed to agree, and often don't. A 714 kg weight gap is a customs problem; a wrong container check digit is a delivery problem; an incoterm that contradicts the freight clause is a billing argument three weeks later. Operators don't fear AI being wrong, they fear it being unsupervised. So Ibuilt the supervision first and the agents second.
What it does
Five ADK agents across three departments (import ops, procurement, customer service) read a shipment's actual documents, find the discrepancies between them, chase what's missing, compare quotes, triage delays and draft the correction notice. Everything consequential stops at a policy gate for a human. Everything decided lands in an append-only ledger.
It runs two ways: an operator can ask the fleet a question during the day, and a scheduled sweep checks every open shipment at 06:00 with nobody watching. Same fleet, same gate.
One service, one door. A public homepage, then a login page with two panels, a demo login (username and password) or Google sign-in behind an invite code. Behind that, one nav:
- Desk — the approval queue the overnight sweep left, as drafted emails. Open one: the message, a contract stating exactly what approving it does, and the documents the agent read to write it. Approve or reject. The buttons are live for everyone signed in, because the safety is the fictional data and the gate, not a disabled control. Drafts cite their sources, and the console verifies every quote byte-for-byte against the named file, a quote it cannot match is flagged for the human, never silently repaired.
- Ask the fleet — a chat page in front of ADK's API. Every turn carries an inline trace (who did what, every tool call with its arguments), and every answer ends with its evidence, the documents the fleet actually read, linked or a line saying nothing was read. A panel counts tokens and prices them at Gemini 3.7 Flash's rates. You can upload a scan and ask about it.
- Sent — what actually left: subject, the address it was drafted for, where it really went, who approved it.
- Ledger · Fleet · Scoreboard — the append-only record; the catalog, which is deliberately read-only (no agent editor in the UI, adding a desk is a pull request, so the fleet's shape cannot drift at runtime); and the graded run, 7/7, served from the same image.
The loop is closed. A hold raised in the chat is the same hold the Desk approves, one approval store, one ledger, one service, and what leaves shows up on Sent under the name of the human who clicked.
How I built it
- Google ADK 2.7 for the fleet: one coordinator, five specialists, each declared in a code-owned catalog (owner, desk, tool surface, data scope, autonomy level, per-run cost cap).
- One governance seam:
before_tool_callbackon every agent. Read-only calls run; consequential ones are HELD with an approval id; unknown fail closed. Agents carry no policy — the catalog declares tools, the gate classifies them — so adding an agent cannot add a bypass. - Gemini via Vertex AI (no API keys anywhere; ADC and service accounts only).
send_emailis wired, and the gate is what makes that safe. It is CRITICAL with an external side effect, so it is held on every path and runs only as a human-approved replay from the Desk. The model never chooses the real recipient: the draftedtois recorded as intended, and delivery goes to the operator's demo mailbox plus the approver's own address if they signed in with Google. Delivery is real — Gmail SMTP from the demo account — and every send is also spooled, which is what the Sent page reads.- Our own OAuth client for Google sign-in, not IAP, so one page can offer a password form and a Google button side by side. Signed state, the invite code checked before the redirect, and the identity header stripped off every inbound request and re-set by us.
- Cloud Run for the one service and the sweep (a Cloud Run Job on Cloud Scheduler, also startable on demand from the Desk); Cloud SQL for durable per-identity chat sessions; GCS for the ledger, the approval store and uploaded documents; Secret Manager for every credential.
- Realistic intake: 26 PDFs and scan-like PNGs rendered from the canonical documents and byte-sealed;
ingesttranscribes them with Gemini's native document reading — and a judge's own upload (PDF/PNG/JPEG, ≤ 6 MB) goes into the fleet's inbox through that same step. - A scoreboard with no model in the grading path: human-written answer keys for six shipments, including a deliberately clean one where the only passing answer is "nothing wrong here."
- CI: lint, tests and fixture seals on every push with no credentials; the paid eval runs only on demand, through Workload Identity Federation, with a service account that holds
roles/aiplatform.userand nothing else.
Challenges I ran into
- Getting agents to stop. A gate that holds a write is easy to describe and hard to make airtight across five agents and a coordinator; the answer was a single seam and verdicts that can only tighten.
- Shared state on Cloud Run. The sweep's concurrent appends through GCS-FUSE lost holds to stale file handles; the fix was to write locally and publish once — and the console's reconcile page caught the divergence before I did.
- Judge access without a shared password. Google-managed IAP is a per-service switch and cannot share a page with a password form, so I implemented the OAuth code flow ourselves: signed state, the invite code checked before the redirect, and the verified email pinned as the identity server-side. A judge who declines Google gets a demo login on the same page.
- ADK's dev UI is a developer tool, and it swallowed replies the API returned fine. We put one page in front of the API instead.
Accomplishments that I am proud of
- 7/7 gradable tasks, three runs of three — a task counts only if every attempt passed.
- The clean-shipment control graded strictly: an invented finding scores zero.
- A console that checks the model's homework: every figure a draft quotes is re-read from the source file and verified byte-for-byte before the human decides — and when it cannot match a quote, it says so in red rather than vouching for it.
- A send that cannot reach a real address. The one irreversible action in the fleet is the one the gate stops on every path — and when a human does approve it, delivery goes to the operator's demo mailbox, never to the address the model wrote down.
- One live URL where the buttons actually work, for anyone the invite reaches, with a name on every row of the record.
- 259 tests that need no credentials, including "seals" that prove the console module imports no model code and ships zero JavaScript.
What I learned
Governance is the feature. The interesting claim is not "agents read documents"; it is that the approval boundary and the audit trail are the product and the agent is the engine. And you can only say how good an agent is if you wrote the answer keys first.
What's next for Freight Ops Fleet
Wire real ingestion channels (email, carrier portals) into the inbox; require a second approver on a send before it may leave; run the sweep against a live TMS. The gate and the ledger do not change.
Log in or sign up for Devpost to join the conversation.