A consultant-led tool that gets grantees money: auto-retrieved grant discovery, click-through qualification, explainably fit-ranked matches, a condition-gated application pipeline, and documents that write themselves from data already entered. Offline core; syncing is the one explicit online step. Spun off from the GrantBridge system design.
A Back Road Creative product.
| Path | What it is |
|---|---|
| PITCH.md | One page: who it's for, the problem, why it wins |
| MILESTONES.md | The whole PM layer, with a one-line proof each |
| PLAYBOOK.md | The sit-down script + weekly/quarterly cadence |
| COMPETITORS.md | Verified matrix, gap register, pain-point register, verdict |
| DEMO.md | See it running in 5 minutes |
| OPERATIONS.md | Running a real install: CLI, backups, scheduled sync, online steps |
| LICENSE | Proprietary — final text pending operator review |
system/ |
The working Flask app + test suite |
No SOP library, financial projections, org chart, compliance framework, or formal traceability docs by design — the spec module and the test suite are the traceability; the heavyweight practice lives in GrantBridge.
make setup # one-time: venv, dependencies, database init + demo seed
make run # start -> http://127.0.0.1:5001make reset-db recreates and reseeds the database only, creating the venv
first if there isn't one. It drops everything, so it is for demo databases,
not one with real work in it. Re-running setup skips the dependency install
unless requirements.txt changed. The scripts the targets wrap
(system/setup.sh, system/run.sh) still work directly — bash setup.sh --reset-db is the same thing.
GRANTPATH_DEBUG=1 bash run.sh restarts the server whenever a source file
changes — a development convenience, off by default. Leave it off for demos.
Running a real install — the operator CLI, backups, scheduled sync, database upgrades, and the online steps — is documented in OPERATIONS.md.
| Username | Password | Role |
|---|---|---|
admin |
admin-demo-1 |
Admin |
consultant |
consultant-demo-1 |
Consultant (whole portfolio) |
grantee |
grantee-demo-1 |
Client-Grantee (Riverbend, read-only) |
- Opportunity — a grant listing in the catalog (synced or imported).
- Fit score — deterministic 0–100 over eligibility, geography, focus, amount, deadline; every point carries a stated reason.
- Application — one client × one opportunity, moving shortlisted → preparing → submitted → awarded/declined → closed.
- Checklist — auto-generated per application from the opportunity and the profile; required items gate submission.
- Sources — where catalog rows come from: the federal API or named CSV packs; every sync run is logged and auditable.
make (or make help) lists them all:
| Target | What it does |
|---|---|
make setup |
venv, dependencies, database init + demo seed |
make run |
start the app -> http://127.0.0.1:5001 |
make test |
full pytest suite, offline |
make lint |
ruff, when it is installed in the venv |
make export |
rebuild system/dist/grantpath-package.bundle.html from the package docs |
make backup |
timestamped database copy into system/instance/backups/ (OUT= to write elsewhere) |
make reset-db |
recreate and reseed the database only |
make clean |
remove __pycache__ and .pytest_cache |
The same commands directly, plus the coverage run the make targets do not wrap:
cd system && .venv/bin/python -m pytest -q # full suite, offline
.venv/bin/python -m pytest -q --cov # suite + coverage floor
.venv/bin/ruff check . # lint
.venv/bin/python tools/build_export.py # one-file HTML bundleBoth tools read system/pyproject.toml. ruff check must print
All checks passed! — it is what makes the # noqa: S608 / # noqa: S310
annotations in the source enforce anything; without it they are decorative.
--cov measures app/ and tools/ and fails under 85% coverage
(fail_under in [tool.coverage.report]); the suite measured 85.85% when the
floor was set. Raise the floor as coverage climbs — never lower it to pass.
CI runs all four on every pull request against Python 3.12, and adds the 3.10
floor on the nightly and on a manual run. The nightly skips itself when master
has not moved since the last green one, so an idle day costs nothing. Editing a
package doc still runs the whole suite — tests/test_export_bundle.py is what
catches a cross-link the export bundle can no longer resolve.