Inspiration

The US Forest Service runs a public campaign called "If You Fly, We Can't." When a civilian drone enters wildfire airspace, aerial suppression stops — the tankers go home and the fire keeps burning. Meanwhile the person deciding whether a survey drone may launch has minutes, and four unrelated systems to reconcile by hand: where the hazard is, whether the weather allows it, whether the airspace is restricted, and whether manned aircraft are already overhead.

The deeper motivation is a failure I've made myself. On a previous project I wrote a safety guard around a timeout constant I never measured — I guessed 160 seconds against a real limit of 600. The guard fired at 27% of the available time, emitted blanks, and the entry scored 5.3%. The model and the code were fine. The guessed number was the bug.

Drone dispatch is that same failure with far worse consequences. So SwarmCall is built on one rule: an absent answer and a broken sensor must never produce the same value. If it cannot establish that the sky is clear, it says so and grounds the fleet — it never treats silence as safety.

What it does

SwarmCall is an autonomous pre-flight safety authority: a governed fleet of eight agents that decides, with no human in the loop, whether disaster-survey drones should fly.

  1. DETECT (deterministic, no LLM) — resolves an NWS alert into its true warned-zone polygon (1,231 vertices; NWS returns geometry: null, so the polygon needs a second fetch).
  2. MODEL ARMOR — screens untrusted external prose for prompt injection, verdict-forcing, tool poisoning and PII before it can reach a prompt or long-term memory.
  3. AGENT GATEWAY — every tool call verifies a per-agent identity token, enforces the scope the registry granted, screens the response, and writes an audit record.
  4. ASSESS (ParallelAgent — 5 isolated scouts, one API each) — hazard, weather, live manned traffic, charted FAA airspace, disaster enrichment.
  5. FAIL-CLOSED GATE — any safety-critical scout returning UNAVAILABLE means unknown, and unknown is never clear. The run refuses and names the failed check.
  6. PLAN — Gemini 3.5 Flash assigns coverage cells within each airframe's wind limit.
  7. VERIFY/REPAIR (LoopAgent ×3)Gemma, a different model family, audits the plan against raw constraints and never sees the planner's reasoning.
  8. DISPATCH — one chokepoint, idempotent on sha256(alert + canonical action).

A real run, on live government data: Red Flag Warning, Western Klamath National Forest, gusts 27.0 m/s → **NO_GO, all three airframes grounded, with the reason stated per aircraft.

How we built it

Stack: Gemini 3.5 Flash (planner) + Gemma (independent verifier), Google ADK 2.8.0 for the Sequential/Parallel/Loop orchestration, GenAI SDK, Cloud Run (scales to zero), Firestore (state, memory tiers, idempotency), OpenTelemetry → Cloud Trace.

All five data sources are live, real and keyless — NWS/NOAA, Open-Meteo, OpenSky Network, FAA ArcGIS, GDACS. No OAuth, no scraping, no synthetic hazard data.

We built the seven GEAP surfaces as self-hosted equivalents on Firestore, Cloud Run and Cloud Trace, and each one validates itself: /identity-check, /gateway-check, /armor-check and /gate-check each score a known-good and a known-bad case, and report themselves BROKEN if the two do not separate.

Challenges we ran into

The idempotency trap — we fell straight into it. Our first key was sha256(alert_id + full_plan_json). It never suppressed duplicates, because the plan contains the model's rationale prose, which varies run to run even at temperature 0.2. Every run produced a fresh fingerprint and dispatched again. The fix was to hash the canonical action — decision plus sorted assignments — and deliberately exclude the commentary. An idempotency key must describe what happens in the world, never what the model said about it.

A guard on the wrong input. Our fail-closed gate required all five scouts to be available, including GDACS — which is enrichment, not safety. When GDACS timed out, an advisory source grounded the fleet. An over-broad guard isn't safe; it produces refusals that protect nobody.

Four APIs returning 200 does not mean the system works. We verified every endpoint individually and only later checked the join — NWS is US-only, while 94 of 100 live GDACS events fall outside US coverage. We inverted the trigger so the NWS warned zone is the hazard area.

Model Armor ran twice, so the second pass saw already-redacted text and would have hidden real findings. Moved to the Gateway so it happens once.

Rate limits became a feature. OpenSky took six attempts to yield one good response. Rather than hide that, UNAVAILABLE propagates as a refusal — the throttling demonstrates the design.

Accomplishments that we're proud of

  • Least privilege you can audit, not trust. GET /registry?can_write=true returns 1 of 8. hazard_scout → firestore.missions is denied in the live audit log, by the gateway, on the hot path.
  • A verifier that is structurally independent — different model family, and it never sees the planner's reasoning. A verifier shown the justification tends to ratify it.
  • Guards that can fail. Every guardrail is validated against something that should break it. A gate nothing can fail is a bug wearing a safety costume.
  • It refuses. The hardest behaviour to build and the most important one to have.

What we learned

  • An enabled API is not a running service. firestore.googleapis.com being on doesn't mean a database exists. gcloud firestore databases list returning "0 items" is the check that separates them.
  • A quota's label can disagree with its behaviour. The error said PerDay, quotaValue: 20; the retry delay said 40 seconds. Measuring beat believing the string.
  • Rate limiting is a design input, not an obstacle. Rate limiting is a design input, not an obstacle. OpenSky's throttling forced us to distinguish "no traffic" from "traffic unknown" — which turned out to be the single most important behaviour in the system..
  • Safety comes from structure, not model capability. A modest model checked by a different family against hard numbers is more robust than one very capable model deciding alone.

What's next for SwarmCall

  • FAA LAANC integration — today it answers should we fly? rigorously; it does not yet answer may we fly? That is the honest limit of the current build.
  • Real airframe telemetry instead of a synthetic three-drone fleet.
  • Agent-to-agent negotiation, so the verifier can propose a reduced-scope mission rather than only passing or failing.
  • Workload Identity Federation in place of HMAC capability tokens.

Built With

  • agent-development-kit
  • cloud-run
  • cloud-trace
  • faa
  • fastapi
  • firestore
  • gdacs
  • gemini
  • gemini-3.5-flash
  • gemma
  • google-adk
  • google-cloud
  • google-genai
  • httpx
  • multi-agent
  • noaa-api
  • open-meteo
  • opensky-network
  • opentelemetry
  • pytest
  • python
  • three.js
  • webgl
  • webgl-globe
  • zero-trust
Share this project:

Updates

Submission history