Skip to main content

Agentic NSF proposal first-draft generator with a panel review loop

Project description

instaprop

CLI-first open-source toolkit for drafting NSF proposals with an agentic review panel.

Give it a solicitation and a set of intellectual merit bullets. It returns a 5-page concept note vetted by a simulated panel of five NSF reviewers — in minutes, not weeks.

python3.12 -m pip install instaprop
export ANTHROPIC_API_KEY=sk-ant-...
instaprop generate \
  --solicitation https://www.nsf.gov/funding/opportunities/.../nsf26-501/solicitation \
  --contributions my_bullets.txt

How it works

instaprop supports three practical operating modes.

Starter Mode:
  Solicitation + contribution brief
    -> Writer
    -> Review panel
    -> Rubric + revision brief
    -> inspect outputs manually

Best-Of-N Mode:
  Solicitation + fixed contribution brief
    -> Writer
    -> Review panel
    -> Rubric + revision brief
    -> revise draft
    -> repeat N rounds
    -> pick best draft

Idea-On-Steroids Mode:
  Solicitation + initial contribution brief
    -> inner loop: draft -> review -> rubric -> revision brief
    -> outer loop: refine the contribution brief itself
    -> draft again from the improved brief
    -> stop when target score / fatal-flag criteria are met
    -> otherwise continue until max rounds, then return the best draft

In the strongest mode, there is a genuine double loop:

  • inner loop: proposal development
  • outer loop: idea / contribution-brief refinement

That lets the system improve not just the wording of the draft, but the raw research framing, novelty, literature positioning, and evaluation plan feeding the next draft round.

Inspired by Andrej Karpathy's writing on agentic AI systems, applied to the unglamorous but high-stakes task of academic proposal writing.


Installation

python3.12 -m pip install instaprop

# From source
git clone https://github.com/kavasserirocks/instaprop
cd instaprop
python3.12 -m pip install -e ".[dev]"

Set your Anthropic API key and verify the CLI:

export ANTHROPIC_API_KEY=sk-ant-...
instaprop check

If you want OpenAI-backed models instead, install the optional extra:

python3.12 -m pip install "instaprop[openai]"

If you want the local FastAPI server for proposal review/generation workflows:

python3.12 -m pip install "instaprop[api]"
uvicorn api:app --reload --port 8000

That server exposes:

  • GET /health
  • POST /review/text
  • POST /review/file
  • POST /generate

If you are preparing a release, see RELEASE.md.


CLI

The CLI has four user-facing commands:

instaprop generate
instaprop scores
instaprop reviewers
instaprop check

For built-in help:

instaprop --help
instaprop generate --help
instaprop check --help

For a full CLI walkthrough, see docs/CLI.md.


CLI Modes

1. Starter Mode

Use this when you have a raw idea and want one quick pass to see whether the framing is viable.

instaprop generate \
  --solicitation https://www.nsf.gov/funding/opportunities/.../solicitation \
  --contributions idea.txt \
  --rounds 1 \
  --verbose

What it does:

  • writes one draft
  • runs one panel review
  • emits a scorecard and revision log
  • lets you inspect the first set of objections before spending more tokens

2. Best-Of-N Mode

Use this when you want the system to revise the proposal draft multiple times and then select the strongest round.

instaprop generate \
  --solicitation https://www.nsf.gov/funding/opportunities/.../solicitation \
  --contributions idea.txt \
  --rounds 3 \
  --verbose

You can increase --rounds up to 5 in the standard fixed-round mode.

What it does:

  • runs a visible write-review-revise loop for N rounds
  • keeps the contribution brief fixed
  • chooses the best-scoring draft at the end

3. Idea-On-Steroids Mode

Use this when you want the system to revise both the draft and the underlying contribution brief between rounds, and keep iterating toward a pass condition.

instaprop generate \
  --solicitation https://www.nsf.gov/funding/opportunities/.../solicitation \
  --contributions idea.txt \
  --target-score 3.2 \
  --stop-on-no-fatal-flags \
  --max-rounds 5 \
  --evolve-brief \
  --verbose

What it does:

  • drafts the proposal
  • reviews it
  • rewrites the contribution brief using reviewer feedback
  • drafts again from the improved brief
  • uses the target-score / no-fatal-flags criteria as the stop condition
  • repeats until the proposal clears the threshold or hits the round cap

This is the strongest autonomous CLI mode currently implemented.


Generate

Supplying the solicitation

instaprop accepts the solicitation in two common forms:

1. NSF.gov URL (recommended — always current)

Use the solicitation page URL directly. Both the opportunity page and the full solicitation page are accepted:

instaprop generate \
  --solicitation https://www.nsf.gov/funding/opportunities/collaboratory-advance-mathematics-education-learning-k-12/nsf26-501/solicitation \
  --contributions my_bullets.txt

2. Plain text file (escape hatch)

instaprop generate \
  --solicitation-file solicitation.txt \
  --contributions my_bullets.txt

Supplying your contributions

Use a plain .txt file or a Markdown .md file for --contributions. Markdown is optional; simple plain text is fully supported and is the lowest-friction default.

Recommended:

instaprop generate \
  --solicitation-file solicitation.txt \
  --contributions my_bullets.txt

Also supported:

instaprop generate \
  --solicitation-file solicitation.txt \
  --contributions my_bullets.md

If your notes currently live in Word or PDF, convert them to .txt or .md before passing them to the CLI.

All options

Flag Default Description
--solicitation / -s NSF.gov solicitation URL
--solicitation-file Local plain-text solicitation
--contributions / -c required Plain text or Markdown file with intellectual merit bullets
--output / -o draft.md Output path for the proposal draft
--rounds / -r 3 Writer-panel revision rounds (best-of-N)
--target-score off Optional early-stop threshold for rubric overall score
--max-rounds --rounds Cap when using stop criteria
--stop-on-no-fatal-flags off Stop early once a round has no fatal rubric criteria
--evolve-brief off Rewrite the underlying contribution brief between rounds
--provider anthropic LLM backend for writer + reviewers
--model claude-opus-4-5 Model for writer + reviewers
--extraction-provider anthropic LLM backend for non-URL solicitation extraction
--extraction-model claude-haiku-4-5-20251001 Model for non-URL solicitation extraction
--pages 5 Target page count
--verbose / -v off Stream reviewer critiques and diffs to stdout
--scorecard / --no-scorecard on Emit .scorecard.json
--log / --no-log on Emit .revlog.md revision log

Common command patterns

Default Anthropic flow:

instaprop generate \
  --solicitation https://www.nsf.gov/funding/opportunities/.../nsf26-501/solicitation \
  --contributions my_bullets.md

Save to a custom output path:

instaprop generate \
  --solicitation-file solicitation.txt \
  --contributions my_bullets.txt \
  --output outputs/camel_draft.md

Run fewer rounds for a cheaper/faster pass:

instaprop generate \
  --solicitation-file solicitation.txt \
  --contributions my_bullets.txt \
  --rounds 1

Keep iterating until the draft clears a target score or reaches the cap:

instaprop generate \
  --solicitation https://www.nsf.gov/funding/opportunities/.../solicitation \
  --contributions my_bullets.txt \
  --target-score 3.2 \
  --stop-on-no-fatal-flags \
  --max-rounds 5 \
  --verbose

Turn on the stronger self-correction loop that also rewrites the contribution brief:

instaprop generate \
  --solicitation https://www.nsf.gov/funding/opportunities/.../solicitation \
  --contributions my_bullets.txt \
  --target-score 3.2 \
  --stop-on-no-fatal-flags \
  --max-rounds 5 \
  --evolve-brief \
  --verbose

Show reviewer progress and revision output live:

instaprop generate \
  --solicitation https://www.nsf.gov/funding/opportunities/.../solicitation \
  --contributions my_bullets.txt \
  --verbose

Disable auxiliary files:

instaprop generate \
  --solicitation https://www.nsf.gov/funding/opportunities/.../solicitation \
  --contributions my_bullets.txt \
  --no-scorecard \
  --no-log

Use OpenAI-backed models if you installed the optional extra:

pip install "instaprop[openai]"

export OPENAI_API_KEY=...
instaprop generate \
  --provider openai \
  --model gpt-5-mini \
  --solicitation-file solicitation.txt \
  --contributions my_bullets.txt

Other commands

instaprop scores draft.scorecard.json   # pretty-print a scorecard
instaprop reviewers                     # list the five reviewer personas
instaprop check                         # verify Anthropic connectivity

Check Anthropic explicitly:

instaprop check --provider anthropic

Check OpenAI explicitly:

instaprop check --provider openai

Outputs

File Contents
draft.md Best-round proposal draft in Markdown
draft.scorecard.json Per-reviewer and per-criterion scores for each round
draft.revlog.md Revision log: rubric scorecard + panel discussion + revision brief per round

Scorecard structure

The scorecard is rubric-aligned. Each round contains:

  • Per-reviewer overall (1–4, mapping to NSF tier labels)
  • Per-criterion scores across 17 rubric criteria in 4 sections
  • Fatal flags — any criterion any reviewer scored 1
  • Section weighted scores (first two pages 25%, merit 35%, impacts 20%, writing 20%)
  • Simulated panel discussion — what each reviewer would say aloud
  • Revision brief — prioritised action list for the writer

The review panel

Each reviewer scores only the criteria within their focus area — the rubric aggregator merges sparse partial scorecards into a complete weighted score.

Reviewer Focus Primary criteria
Domain expert Field-specific depth novelty, detail, feasibility, literature, scope
Program officer NSF fit & fundability hook, gap, approach summary, scope
Methodological skeptic Rigor & validity detail, feasibility, problem statement, scope
Interdisciplinary generalist Clarity & framing hook, gap, prose, coherence, structure
Societal impact Real-world stakes specific impact, application, exciting

Panel dynamics are grounded in the NSF reviewing process described by C. Grimm (Oregon State).


Writing your contributions file

The --contributions file is the most important input. A strong one:

## Project title
Learning Causal Structure from Observational Time-Series

## Core intellectual contributions

- **Non-trivial novelty**: We introduce a provably identifiable estimator for
  causal DAGs in non-stationary, non-Gaussian settings — a regime where
  existing methods (PCMCI, Dynotears) fail.

- **Theoretical foundation**: We prove identification under a new "local
  stationarity" condition weaker than global stationarity, with sample
  complexity bounds.

- **Scalable algorithm**: Our algorithm runs in O(T log T d²) vs O(T² d³)
  for existing approaches, enabling application to climate and neuroscience
  datasets (T > 10⁶, d > 500).

- **Empirical validation**: Three domains — synthetic benchmarks, ERA5 climate
  data with expert-annotated causal structure, Allen Brain Atlas neural recordings.

## Why this is non-trivial
Existing methods assume stationarity or Gaussianity — neither holds in
the target domains. Relaxing both simultaneously requires a new theoretical
framework, not just an engineering improvement.

The panel's domain expert will scrutinise these claims hardest. Be specific, be falsifiable, cite the gap.


Contributing

Contributions welcome. The highest-value areas:

  • Reviewer prompts (instaprop/prompts/reviewer_prompts.py) — if you have served on NSF panels, your input on the personas is invaluable
  • Evaluation harness — scoring generated drafts against real funded proposals
  • CLI ergonomics — better progress output, resumability, and export options
  • --resume flag — continue from a saved round state

Publishing

The package metadata is set up for PyPI/TestPyPI publication. The minimal flow is:

python3.12 -m pip install -e ".[dev]"
python3.12 -m build
twine check dist/*
twine upload dist/*

For a fuller release checklist, use RELEASE.md.


Roadmap

  • v0.1 — Core agentic loop
  • v0.1 — NSF.gov URL fetcher (HTML + structured extraction)
  • v0.1 — PDF solicitation reader (pypdf → Claude extraction)
  • v0.1 — Rubric-aligned scorecard (17 criteria, 4 sections, fatal flags)
  • v0.1 — Panel discussion simulation + revision brief
  • v0.2 — Streaming output to terminal during generation
  • v0.2 — --resume flag to continue from a saved round
  • v0.3 — Configurable reviewer personas via YAML
  • v0.4 — Better CLI workflows and integration hooks for external frontends
  • v1.0 — Full 15-page proposal mode

License

MIT. See LICENSE.


Citation

If instaprop contributes to a funded proposal (congratulations!), consider adding an acknowledgment:

This proposal draft was developed with assistance from instaprop (https://github.com/kavasserirocks/instaprop).

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

instaprop-0.1.0.tar.gz (45.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

instaprop-0.1.0-py3-none-any.whl (45.9 kB view details)

Uploaded Python 3

File details

Details for the file instaprop-0.1.0.tar.gz.

File metadata

  • Download URL: instaprop-0.1.0.tar.gz
  • Upload date:
  • Size: 45.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for instaprop-0.1.0.tar.gz
Algorithm Hash digest
SHA256 1bbfc8921d42a73d48ccd2038b7a071b7d1445e2d81fc804dfe294167a24301e
MD5 60da74e68db0f71fbf4bac251cdd8051
BLAKE2b-256 2e21519763713a36cb1a32e2b0b52819619a893595b9422a39a0ba2e8032f74d

See more details on using hashes here.

File details

Details for the file instaprop-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: instaprop-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 45.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for instaprop-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2fb4c2999d3d69c6597d796c3e579de196d2399f9a1d3bddb3cc6ae6030a6914
MD5 32332929b22692f75a0d6d868ef9a35f
BLAKE2b-256 63973bec312b61f84c7be1ea7a2c06984df0291c7beff3ed74c72886757d46f4

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page