Inspiration

Security teams get flooded with alerts every day — most are noise, but a few are genuine threats, and sorting them manually burns hours that could go toward real incident response. I wanted to build an agent that doesn't just chat about security alerts, but actually makes a judgment call and takes action on them autonomously, the way a junior analyst on triage duty would.

What it does

The agent ingests a stream of security alerts (SSH brute-force attempts, anomalous logins, port scans, privilege escalation attempts, and suspected data exfiltration) and for each one:

  • Classifies it as low-risk or high-risk using Gemini
  • Auto-remediates clearly benign activity (e.g. blocklists an IP, closes the alert) without waiting for a human
  • Escalates ambiguous or dangerous activity with a drafted incident summary and severity level, ready for a human analyst to act on immediately
  • Persists every decision to an audit trail, so the reasoning behind each action is fully traceable afterward

It calls exactly one tool per alert — no double-handling, no skipped alerts — and it runs the same core logic whether triggered from a local loop or (in the cloud-deployed version) an asynchronous Pub/Sub push subscription.

How I built it

  • Gemini (via the Gemini API) does the actual classification and reasoning for each alert
  • Google ADK orchestrates the agent: the model, its instructions, and two tools (remediate_alert, escalate_alert) that it can call
  • The audit trail is written through a small storage layer that transparently switches between a local JSON file (for development) and Firestore (for the cloud-deployed version) via a single environment variable — the agent logic itself never changes between the two
  • A separate FastAPI + Cloud Run entry point (cloud_main.py) is built to receive alerts pushed from Pub/Sub, so the agent can run asynchronously in the background rather than on a fixed schedule

Challenges I ran into

  • Iterating through Google Cloud billing/quota setup (free-tier request limits, prepay balances) while developing under a tight deadline
  • The Gemini API occasionally returned transient 503 UNAVAILABLE errors under high demand — I added an application-level retry-with-backoff layer around each alert so a temporary outage doesn't crash the whole run, which the agent demonstrated handling live during testing (visible in the included sample run output)
  • Balancing local development speed against the eventual cloud deployment path, which led to the store/entry-point split described above

Note on deployment

Due to a billing constraint outside the scope of the hackathon, this project was fully built, tested, and validated locally (see sample_run_output.txt and audit_trail.json in the repo for a complete run across all 6 synthetic alerts), but was not deployed live to Cloud Run/Pub/Sub/Firestore for this submission. The full cloud deployment code (cloud_main.py, Dockerfile, deploy.sh) is complete and ready to run — see the README's "Deploying to Google Cloud" section for exact, reproducible steps.

What I learned

  • How to structure an ADK agent so its core reasoning logic is fully decoupled from both its trigger source (local loop vs. Pub/Sub) and its storage backend (local file vs. Firestore) — a pattern that made the eventual cloud migration a near-zero-code-change process
  • How to build resilience against upstream model availability issues rather than assuming every API call succeeds

What's next

  • Complete the live Cloud Run deployment once billing is resolved
  • Add a lightweight dashboard reading directly from the audit trail collection for a more visual, judge-friendly view of agent decisions
  • Expand the synthetic alert set and tune the escalation instructions against a wider range of real-world alert types

Built With

Share this project:

Updates

Submission history