| B-number | Short description | Year | Case | Ground | Outcome | Authority | Posture | Links |
|---|
Ground detail
How often this ground is sustained, against the corpus base rate, with the 95% confidence interval its sample size supports. Computed over all 33,136 decisions — 27,232 of whose grounds are model-predicted (marked † elsewhere) — so small n's now appear on grounds that were rare in the hand-labeled subset. The side-panel filters do not apply here. Most of the apparent spread between grounds is sampling noise: the confidence band shows which differences are real.
Decision analysis
Key-element summaries of GAO bid protest decisions, written by an OpenAI-compatible model from the decision text. Pick decisions anywhere in the dashboard — the Map popups, the Table, or Dynamic Search results — then read them one at a time or compare the set. Each analysis opens with the nearest related decisions from the corpus index (vector retrieval) — click one to analyze it too. Output lands here, never in the view you picked from.
Model endpoint
Connect a model endpoint
Map, Table and Ground detail work with nothing attached. Analysis needs a model; Dynamic Search needs the search index. Both are optional, and both are yours to point wherever you like — including at a model running on your own machine.
What each tab needs
| Tab | Needs |
|---|---|
| Map, Table, Ground detail, License | Nothing. They are already working. |
| Analysis | Any OpenAI-compatible endpoint — hosted or local |
| Dynamic Search | The vector index plus scripts/serve.py |
The quick way: point the browser at an endpoint
Nothing to install. The page calls the endpoint directly from your browser.
Open the Analysis tab
Click Analysis, then expand Model endpoint at the top.
Fill in three fields
Base URL — ends in /v1, for example
https://api.openai.com/v1 or http://localhost:1234/v1.
Model — the name your endpoint answers to.
API key — leave empty for most local servers.
Pick a decision and run it
Use Select on any decision in the Table or a Map popup, then ✦ Run analysis. Choose Compare as a set for two or more.
Give it the decision text
Without the local server there is no decision text on this page, so it will ask you to drop the PDF in or paste the text. That is expected.
Endpoints that work
| Running locally | Base URL |
|---|---|
| LM Studio | http://localhost:1234/v1 |
| Ollama | http://localhost:11434/v1 |
| llama.cpp server | http://localhost:8080/v1 |
| vLLM | http://localhost:8000/v1 |
Hosted providers work the same way — OpenAI, OpenRouter, Together, Groq, Fireworks,
LiteLLM and anything else speaking /v1/chat/completions. Only the base URL,
the model name and the key change.
The tidier way: let the server hold the key
Run the project's own server and your key lives in its environment instead of in a browser. The server also reads the decision text for you, so you are not asked for PDFs, and it is the only way to turn on Dynamic Search.
git clone https://github.com/acqagent/GAO-Bid-Protest-Nexus.git
cd GAO-Bid-Protest-Nexus
python -m venv .venv && .venv/bin/pip install -r requirements.txt
export OPENAI_BASE_URL=http://localhost:1234/v1 # or any compatible endpoint
export OPENAI_MODEL=your-model
export OPENAI_API_KEY=sk-... # omit for a local server
.venv/bin/python scripts/serve.py
# then open http://127.0.0.1:8765/
The dashboard notices the server on its own and routes through it. The Model endpoint panel will say key on the server when it has one.
Turning on Dynamic Search
Full-text search runs over a vector index of the decision text, which is far too large
to ship inside this page. Either drop vector/chunks.jsonl and
vector/embeddings.npy from the full bundle into vector/, or
build the index yourself:
python3 scripts/vectorize.py --links pdf-links.csv \
--embedder api --embed-base-url http://localhost:8080/v1 \
--embed-model your-embedding-model
Use a model trained for retrieval — Qwen3-Embedding,
BAAI/bge-* or intfloat/e5-*. A general chat model will produce
vectors, but not ones that put a question near the passage answering it.
No browser at all
Every analysis the dashboard can run is also a command:
python3 scripts/analyze.py B-417327 --out reports/
python3 scripts/analyze.py --filter ground=oci,disposition=sustained \
--limit 8 --compare --out reports/
When it does not work
| What you see | Usually means |
|---|---|
| "could not reach … CORS" | The endpoint refuses browser requests. Use the server route. |
401 or 403 | Missing or wrong API key. |
404 on the model | Model name does not match what the endpoint serves. |
| "could not get the decision text" | No local corpus and no PDF reachable — drop the PDF in or paste the text. |
| Search says it is unavailable | The vector index is not loaded. See above. |
License and credits
Use it, change it, build on it, at work or commercially. Just keep the credit. Two licenses apply: one for the code, one for the data.
| What | License |
|---|---|
| Dashboard code, search backend, scripts | Apache 2.0 |
| Protest taxonomy, per-decision coding, decision metadata, vector index | CC BY 4.0 |
| The upstream decision corpus (Kevin Misener) | MIT / CC BY, per source |
| The GAO decisions themselves | Public domain (17 U.S.C. 105) |
This page embeds the decision data inside the application code. In this file the code is Apache 2.0 and the embedded data is CC BY 4.0.
How to attribute
This citation satisfies the attribution requirement:
If you modified the data, say so — for example, “Coding modified from the original.”
Credits
The Nexus is built on someone else’s work, and the corpus came first.
- The decision corpus came from Kevin Misener, in two collections: GAO-Bid-Protest on Hugging Face — the larger corpus, under the MIT License — and the earlier GAO-Bid-Protest-Dataset of roughly 5,700 decisions, under a Creative Commons Attribution license. Both are used the same way here: the PDF URLs, the 33-ground taxonomy and the per-decision coding were derived from them using AI. If you reuse the corpus, credit that source too.
- The decisions themselves are works of the U.S. federal government and are not protected by U.S. copyright (17 U.S.C. 105), so they are in the public domain. Cite GAO as the source.
What this data can and cannot tell you
The corpus is broad but uneven, and the gaps are not random. Read the numbers with these in mind.
None of this makes the corpus unusable — it makes it a starting point. Every decision links back to its page on gao.gov, and that is the authority. Use this to find decisions and see shape; use the decision itself to be sure.
Accuracy
Name and marks
The code and data are yours to reuse. The AcqAgent name and logo are not. Say your work is based on the GAO Bid Protest Nexus, but do not present a fork as an official AcqAgent release.
Earlier releases
Releases before v1.0 were published under CC BY 4.0 in full, including the code. Those releases stay available under that license. From v1.0 forward, code is Apache 2.0 and data is CC BY 4.0.
Not affiliated with GAO
AcqAgent is an independent, open source project. It is not affiliated with, sponsored by, or endorsed by the U.S. Government Accountability Office or any other federal agency. Content is provided for informational purposes only and is not legal, financial, or contracting advice.
Full terms: Apache 2.0 · CC BY 4.0