NRT Agentic AI Michigan State University

DEMO 13 · ADVANCED — AN AGENT LAYER OVER A SYSTEM YOU ALREADY HAVE

Funding radar

The pipeline’s highest-scoring call is one you cannot submit to. Its lowest-scoring call is the best fit in the set. Both of those are the scorer working correctly — it matched keywords in a title, which is all it had.

Download Demo 13  ↓ ← Demo 12 All demos

← Back to all demos

Looking for the step-by-step? This page explains why the demo is shaped the way it is. The handbook is the manual — prerequisites with verification commands, the full annotated file map, what every file does, how information flows, and the daily, weekly and monthly routines for keeping it running. The package itself also ships SETUP.md (step by step) and MAINTENANCE.md (how to live with it).

Package:

Demo13_funding_radar.zip · 270 KB · 35–45 minutes

Don’t rebuild the scraper

Fetching, prefiltering, deduping and scoring are deterministic. Python does them faster, cheaper, reproducibly, and with tests. Turning a scraper into agent prompts makes it slower and non-reproducible — the wrong side of Demo 8’s workflow-versus-agent line.

So this demo adds the two things a scraper structurally cannot do: read the actual solicitation, and remember what you decided last time.

The one-line diagnosis. Here is the schema of a real funding-radar project:

CREATE TABLE items    (uid, feed, source, title, url, org, score, rationale, ...);
CREATE TABLE feedback (uid TEXT, vote INTEGER, ts TEXT);

items: 90 rows. feedback: 0 rows.

The slot for the decision exists and is empty — because “passed, the $200k cap is below what the work costs” does not fit in an INTEGER. So the reason goes nowhere, and next year the same call comes round and you read it from scratch.

The half the scraper never sees

inbox/ holds six solicitations you dropped in yourself — four PDFs and two saved web pages. The scraper only ever saw their titles and abstracts. The traps are all two pages in.

ScoreCallWhat reading it reveals
96NSF 26-512 — AI Institutes Ineligible. Three dates, and the one on the cover is not binding: the institutional down-select closed in October, the required LOI closed in December.
91USDA-NIFA — Crop Resilience Already decided. The document says it reissues last year’s call unchanged, and your log says you passed in February 2025 — with the reason.
88NIH PAR-26-118 Superseded, in a banner at the top. The useful answer is not “dead” — it is go and read PAR-27-042.
85NSF 26-534 — Foundation Models Six of your keyword domains, all genuinely present. 25% cost share required, and the life sciences are explicitly out of scope.
38DOE DE-FOA-0003291 Submit. The only live call in the set.

The profile has two halves, and nobody writes the second one

Interests say what you would like. Constraints say what you can actually do, and they are what decides:

Uncommitted effort        0.35 FTE
Indirect rate             54.5% on MTDC  →  a $200k *total* cap is ~$129k direct
Smallest viable project   one student for two years ≈ $180k direct
Cost share                the college does not commit it. A requirement is a decline.
Limited submissions       down-select closes 8–10 weeks before an NSF LOI
Equipment                 no wet lab

Four of the five traps are caught by that table alone. A profile listing only research interests cannot produce a triage — it can only produce enthusiasm, which you already had.

The one at the bottom

The DOE call scored 38, lowest in the set, and the scorer was honest about why: the document never says foundation model, machine learning or deep learning. Then read its first area of interest against the profile’s first standing question:

Profile, standing question 1
“Cross-species transfer for expression prediction — a model trained on reference species, evaluated honestly on a feedstock genome it has not seen. This is the one I most want funded.”
DOE, AOI 1
“…building models that predict expression from sequence in genotypes for which no measurement exists. Applications proposing to transfer models trained in reference species to feedstock genomes are encouraged to address the generalisation problem explicitly.”

The same sentence, written by two people who have never met. All three of its areas of interest map onto the profile, and it clears every constraint.

That is the finding — and the fix is not a lower threshold. A keyword filter cannot match a description of your work that avoids your words. No amount of tuning produces this one; a reader does.

One way, and it never eats a decision

pipeline/radar.db       system of record for WHAT EXISTS      read-only, denied
      ↓  export_vault.py — one way, idempotent
opportunities/*.md      one note per call
      ↓
inbox/*.pdf             the document itself
      ↓
YOU: decision + because ← the record that does not exist today
      ↓
memos/*.md              the deliverable

The exporter refreshes every note from the database and copies your ## Decision block through verbatim. Run it twice; nothing you wrote is lost. settings.json denies writes to pipeline/, to profile/, to inbox/, and reads of .env* — a system of record an agent can edit is no longer a record.

Three agents: recurrence (no Write tool) checks the log before anything else; triage answers is this worth an afternoon? in the order eligibility → deadlines → money → scope → science; fitmemo writes the memo, and refuses to write one for a call you cannot submit to — a well-argued memo for an ineligible call is worse than nothing, because it is persuasive.

What is verified and what is not. Every trap was checked mechanically against the documents: the submission limit, all three NSF dates, the cost-share line, the out-of-scope paragraph, the supersession banner, the reissue notice, the two conflicting deadlines, and the budget arithmetic the funder states itself. The exporter was run repeatedly to confirm it preserves a decision block — an earlier version did not, and that bug was found and fixed by this check. The agent’s behaviour was not measured. The solicitations are synthetic: the programmes, numbers, agencies’ specific calls and deadlines do not exist. Do not act on anything in the package.