Inspiration

Opportunities such as hackathons, scholarships, grants, competitions, and student programs often look simple on the surface, but their rules can change quietly.

A single sentence can make the difference between:

  • eligible and ineligible,
  • open and closed,
  • worth applying for and not worth the time,
  • an active application task and an obsolete one.

The problem is not just finding opportunities. It is continuously understanding them, verifying the rules, remembering what changed, and updating what action should be taken.

That inspired us to build Opportunity Monitor: a verified, stateful agentic control loop that continuously evaluates opportunity information and turns changing source text into reliable operational decisions.

Rather than building another chatbot that answers a question once, we wanted a system that could repeatedly observe the same opportunity over time and respond when the underlying reality changes.


What It Does

Opportunity Monitor takes raw natural-language opportunity information and processes it through a continuous workflow:

  1. Google ADK + Gemini 3.5 Flash interpret the source text and extract structured semantic facts.
  2. The model attaches a short verbatim source quote to each extracted fact.
  3. Deterministic Python provenance checks verify that the cited evidence actually exists in the supplied source before the fact is allowed into the policy engine.
  4. Deterministic validators evaluate:
    • eligibility,
    • deadlines,
    • prize values,
    • and final opportunity status.
  5. The system compares the current verified state against the previous state stored in Firestore.
  6. If something changed, it identifies:
    • which fact changed,
    • which deterministic rule became decisive,
    • and why the final status changed.
  7. It then creates, updates, or supersedes an operational action.
  8. All state, evidence, events, and actions are persisted in Firestore.
  9. A live read-only dashboard exposes the current decision, provenance, causal change history, and action state.

The resulting loop is:

observe → interpret → verify → decide → remember → explain → act → repeat


How We Built It

The core architectural decision was to separate semantic interpretation from decision authority.

Gemini is used where probabilistic language understanding is useful:

  • interpreting eligibility language,
  • normalizing dates,
  • extracting country restrictions,
  • identifying student and adult requirements,
  • extracting prize information,
  • and attaching source evidence.

But Gemini does not own the final eligibility or status decision.

Those decisions are made by deterministic Python validators.

This matters because opportunity rules often contain ambiguous natural language, but final decisions such as whether a deadline has passed, whether a country is allowed, or whether a candidate should be marked OPEN, CLOSED, or INELIGIBLE should not depend on model improvisation.

Grounded Provenance

Instead of accepting a flat model response such as:

{
  "adult_only": true,
  "entry_deadline": "2026-09-30"
}

the model returns facts together with source evidence:

{
  "facts": {
    "adult_only": true,
    "entry_deadline": "2026-09-30"
  },
  "evidence": {
    "adult_only": {
      "quote": "Entrants must be adults aged 18 or over"
    },
    "entry_deadline": {
      "quote": "Registration and entry close on 30 September 2026"
    }
  }
}

Deterministic code then verifies that those cited quotes actually occur in the supplied source.

Only verified semantic facts are allowed to reach the policy engine.

This creates a traceable chain:

source text → model claim → source evidence → deterministic verification → policy decision

Stateful Change Analysis

The system stores both the previous and current verified state.

When a source changes, it computes a deterministic fact diff.

For example, in one deployed test:

allowed_countries:
["India", "Finland"]
→
["Finland"]

The system then produced:

OPEN → INELIGIBLE

with:

decisive_rule = COUNTRY_NOT_ALLOWED
decisive_field = allowed_countries

The model did not decide that the entrant was ineligible. It extracted the changed rule and its evidence, while deterministic Python applied the policy.

Operational Action Lifecycle

The system also maintains structured operational actions.

When an opportunity is valid and open, it can create an action such as:

REVIEW_AND_APPLY

If a later source change makes that opportunity invalid, the system can automatically supersede the obsolete action and create a new one such as:

REVIEW_ELIGIBILITY_CHANGE

This makes the workflow more than a notification system. The operational state itself evolves as the opportunity changes.


Google Technologies Used

The project uses:

  • Google Agent Development Kit (ADK) for agent runtime and orchestration,
  • Gemini 3.5 Flash for semantic interpretation,
  • Google Cloud Run for deployment,
  • Google Firestore for persistent state, event history, provenance, and operational actions.

The deployed workflow was tested through the real Google ADK + Gemini execution path.


Challenges We Faced

Keeping the Model From Becoming the Final Authority

The simplest architecture would have been:

source → Gemini → final answer

But that would make critical eligibility and deadline decisions depend on probabilistic output.

We instead preserved a strict boundary:

Gemini interprets language; deterministic code owns decisions.

That required more engineering, but produced a far more reliable architecture.

Making AI Output Auditable

A model can produce a plausible structured fact without making it obvious where the fact came from.

We addressed this by requiring source evidence for model-derived claims and verifying that the quote exists in the original source before accepting the fact.

One important limitation remains: literal quote verification proves that the evidence is present, but it does not mathematically prove that the quote semantically entails the extracted value. We deliberately document this rather than claiming perfect model correctness.

Idempotency

A continuously running monitor must not create duplicate actions every time it sees the same unchanged source.

The system therefore uses deterministic state comparison and deterministic action identities.

Repeated evaluation of an unchanged source produces:

transition_count = 0
action_count = 0

instead of duplicating operational work.

Preserving Historical Causality

If every run simply overwrote the latest candidate state, important historical transitions could disappear.

We added append-only event records so the system can retain:

  • what changed,
  • when it changed,
  • which rule became decisive,
  • and which action was affected.

Avoiding Complexity for Its Own Sake

We deliberately avoided adding features purely for presentation, such as:

  • unnecessary multi-agent decomposition,
  • a general-purpose crawler,
  • a vector database,
  • extra models without a clear architectural role,
  • and broad third-party integrations.

Instead, we focused on making one coherent autonomous control loop observable and auditable.


What We Learned

The biggest lesson was that agentic depth does not necessarily come from adding more agents.

A single agent becomes much more useful when it participates in a disciplined control loop with:

  • durable memory,
  • deterministic policy,
  • provenance,
  • causal change analysis,
  • operational state,
  • idempotency,
  • and failure isolation.

We also learned that the most valuable role for an LLM in this kind of system is not to act as an unquestioned decision-maker.

Instead, it works well as a semantic sensor:

good at interpreting messy human language, but surrounded by deterministic systems that decide what the extracted information is allowed to affect.


Accomplishments

We are especially proud that the final system successfully demonstrated:

  • real Google ADK + Gemini execution,
  • grounded model-derived facts,
  • deterministic eligibility and deadline decisions,
  • persistent Firestore state,
  • causal source-change analysis,
  • autonomous action superseding,
  • idempotent retries,
  • append-only event history,
  • and a live backend-connected dashboard.

In a real deployed test, changing the source from allowing India and Finland to allowing Finland only caused the system to:

  1. detect the changed allowed_countries fact,
  2. retain the new Gemini source quote,
  3. deterministically fire COUNTRY_NOT_ALLOWED,
  4. transition from OPEN to INELIGIBLE,
  5. identify allowed_countries as the decisive field,
  6. automatically supersede the previous application action,
  7. create a new eligibility-review action.

That end-to-end transition is the clearest expression of what we wanted to build.


What's Next

The current build intentionally focuses on the control-loop architecture rather than broad ingestion.

Future versions could add:

  • configurable URL, RSS, and email source adapters,
  • user-specific opportunity profiles,
  • richer action lifecycles,
  • deadline reminders,
  • application checklists,
  • document preparation,
  • ranking across opportunities,
  • and submission-progress tracking.

The architecture is designed so those capabilities can be added without changing the core trust model:

semantic interpretation remains probabilistic, while policy and operational state remain deterministic and auditable.

Built With

Share this project:

Updates

Submission history