A Flask web app that puts the ETHOS Prompt Library (v2.2, September 2026) in front of RX caseworkers as a
guided chat assistant, powered by Claude (claude-opus-5-5) with web search for vendor research.
Caseworkers pick a task (or stay on Start New Assessment), type vendor/engagement information, attach documents, and get streamed, evidence-labelled drafts. Each task gets its own system prompt built from the library's core rules plus only the sections that task needs:
| Front-end task | Library section | Web search |
|---|---|---|
| Start New Assessment | Prompt 0 (+ A, B, C rules for routing) | yes |
| Vendor Research | Prompt A — profile, locations, sanctions table, net-zero | yes |
| Create Service Description | Prompt B (Scope of Work) | yes (context only) |
| Prepare Engagement Questions | Prompt C — baseline + conditional triggers | no |
| Draft Business Owner Email | Prompt C email instructions | no |
| Privacy Documentation | Prompt D | yes |
| AI Services | Prompt E | yes |
| Security Certification | Prompt F | yes |
| Translation | Prompt G | no |
| Privacy Classification | Prompt H — Global 150 | no |
The conversation carries across tasks, so a caseworker can run Vendor Research → Create Service Description → Prepare Engagement Questions → Draft Business Owner Email in one thread. The library's global grounding rules, evidence labels and final quality gate are applied to every task. The UI never names the prompt library.
Other features:
- Attachments: PDF, Word, Excel, CSV, email (.eml), text/markdown/HTML/JSON. Text is extracted server-side and sent as engagement evidence. Scanned (image-only) PDFs aren't supported.
- Web sources the model cited are listed under each answer.
- Feedback button on every answer (unnecessary question, missed question, false positive, hallucination, …)
is appended to
data/feedback.jsonl, which feeds the library's maintenance cycle (section 13). - Download conversation exports the thread as Markdown.
- A permanent "draft for human review / not legal advice" notice.
Two inputs the library refers to aren't in the document itself. Put them in data/ (see data/README.md):
security_questions.md: the approved Security question set and trigger conditions.global150.md(or.csv): the Global 150 register. Without it, Privacy Classification won't guess IDs; it asks the caseworker to attach the relevant entries.
python -m venv .venv
.venv/Scripts/pip install -r requirements.txt # macOS/Linux: .venv/bin/pip
cp .env.example .env # then set ANTHROPIC_API_KEY and APP_PASSWORD
.venv/Scripts/python -c "from ethos.app import main; main()"Then open http://127.0.0.1:5000 (set PORT to change it).
The app is stateless (the conversation lives in the browser tab and is sent with each request), so any number of instances can run behind a load balancer.
Docker
docker build -t ethos .
docker run -p 8000:8000 --env-file .env -v ethos-data:/app/data ethosPaaS (Heroku-style, Azure App Service, Render, …): the Procfile runs
gunicorn wsgi:app with threaded workers and a 600 s timeout. Web research turns can take several minutes, so
any reverse proxy in front must allow long-lived streaming responses and must not buffer them
(X-Accel-Buffering: no is already sent for nginx).
Security checklist
- Set
APP_PASSWORD(HTTP basic auth), or put the app behind your SSO proxy. Without it, anyone who can reach the URL can use it. - Serve over HTTPS only.
- Case data is sent to the Anthropic API. Confirm this is approved under your data-handling policies.
- Mount
data/on persistent storage if you want to keep feedback.
| Variable | Default | Purpose |
|---|---|---|
ANTHROPIC_API_KEY |
— | Required |
APP_USERNAME / APP_PASSWORD |
ethos / empty |
Basic auth, on when a password is set |
ETHOS_MODEL |
claude-opus-5-5 |
Claude model |
ETHOS_EFFORT |
high |
low…max. Lower is faster and cheaper |
ETHOS_MAX_TOKENS |
32000 |
Max output per reply |
ETHOS_WEB_SEARCH |
true |
Web search/fetch for research tasks |
ETHOS_WEB_SEARCH_MAX_USES |
8 |
Searches (and fetches) per turn |
ETHOS_REFUSAL_FALLBACKS |
true |
Server-side fallback if a safety classifier declines a request |
MAX_UPLOAD_MB |
20 |
Per-file upload limit |
MAX_HISTORY_CHARS |
1500000 |
Conversation size cap |
FEEDBACK_PATH |
data/feedback.jsonl |
Feedback log |
All library text lives in ethos/prompts.py, one constant per section. Bump LIBRARY_VERSION / LIBRARY_DATE
when you change it, and record owner and reason in your change log, as section 13 requires.
.venv/Scripts/pip install -r requirements-dev.txt
.venv/Scripts/python -m pytest -qTests use a fake Claude client and make no API calls.