| 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. This hosted copy runs Analysis against a model on this machine only — your model, your hardware, nothing sent to this site and no API key to hand over.
What each tab needs
| Tab | Needs |
|---|---|
| Map, Table, Ground detail, License | Nothing. They are already working. |
| Analysis | An OpenAI-compatible server on this machine — LM Studio, Ollama, llama.cpp, vLLM |
| Dynamic Search | The vector index plus scripts/serve.py |
The quick way: point the browser at a model on this machine
The page calls the model directly from your browser, so the model has to be running on the same machine you are reading this on. Nothing you type here is sent to this site.
Open the Analysis tab
Click Analysis, then expand Model endpoint at the top.
Fill in three fields, then test
Base URL — a localhost or 127.0.0.1 address
ending in /v1, for example http://localhost:1234/v1.
Model — the model id your server reports, for example
qwen2.5-7b-instruct; LM Studio shows it beside the loaded model, and
ollama list prints it.
API key — leave blank. Local servers rarely use one: LM Studio and Ollama
ignore it, and vLLM only wants one if you started it with --api-key.
Then press Test connection. It sends a one-token request and says whether the endpoint answered, so a wrong port or a stopped server shows up here rather than halfway through an analysis. A ✓ appears beside Model endpoint once a call has gone through.
Have the decision PDF or its text ready. The page will ask you to drop it in or paste it — this copy carries no decision text of its own.
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. It asks for the decision text first, then streams the analysis into the Analysis tab.
http to it from an https page regardless. To use either,
take the server route below.
Reaching a local server from a hosted page is the fiddly part. CORS is only the first hurdle — llama.cpp and vLLM may need a flag to send the headers at all, while LM Studio and Ollama do by default. Even with CORS correct, Chrome requires a private-network preflight before a public page may touch a local address, and Safari may refuse the request outright. If Test connection reports it could not reach your server, that is usually why, and the fix is a browser flag, a tunnel, or the server route below — which sidesteps all of it by having the server make the call.
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 |
Anything else speaking /v1/chat/completions works too, as long as it
answers on localhost or 127.0.0.1 on this machine. A model on
another machine — a LAN box, a Tailscale address, a hosted provider — is reachable only
through the server route below.
The other way: run it yourself, and use any endpoint you like
Run the project's own server and the local-only restriction no longer applies — the server calls the endpoint, so any OpenAI-compatible provider works, hosted or local, and your key lives in the server's 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. Build it once, into vector/chunks.jsonl and
vector/embeddings.npy:
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