Skip to main content

Ask natural-language questions about Singapore Workplace Safety and Health PDFs, with citations.

Project description

wsh-rag

Ask natural-language questions about Singapore Workplace Safety and Health (WSH) PDFs — locally indexed, Claude-powered, with inline citations.

PyPI Python CI License: MIT

wsh-rag is a small command-line tool that points at a folder of PDFs — the WSH Act, MOM Codes of Practice, bizSAFE materials, your collected Risk Assessments — builds a local vector index, and answers natural-language questions about them with inline citations back to the source file and page.

It's built for safety officers, employers, and bizSAFE candidates who routinely need to look up obligations under Singapore's Workplace Safety and Health regime and want answers traced back to the underlying paragraph.

Install

pip install wsh-rag
# or, recommended for CLI tools:
pipx install wsh-rag

Requires Python 3.11+.

Quickstart

export ANTHROPIC_API_KEY=sk-ant-...

wsh-rag index ./my-wsh-pdfs

wsh-rag ask "What are an employer's duties under the WSH Act?" \
  --folder ./my-wsh-pdfs

That's it. The first index run will download the embedding model (~130 MB, one-time). Subsequent indexes and asks are fast and run entirely on your machine — only the final answering step calls the Claude API.

What you'll see

╭──────────────────────── ANSWER ────────────────────────╮
│ Under the Workplace Safety and Health Act, every       │
│ employer must take reasonably practicable measures to  │
│ ensure the safety and health of employees at work [F1].│
│ This includes conducting risk assessments before any   │
│ work activity that may pose a risk [F2][F3], and       │
│ maintaining records of those assessments for at least  │
│ three years [F2].                                      │
╰────────────────────────────────────────────────────────╯
        ┏━━━━━━━━━━━━━━━━ SOURCES ━━━━━━━━━━━━━━━━━━━━━┓
        ┃  Tag  │  File                       │  Page  ┃
        ┠───────┼─────────────────────────────┼────────┨
        ┃  F1   │  WSH_Act_2006.pdf           │     14 ┃
        ┃  F2   │  COP_Risk_Management.pdf    │      8 ┃
        ┃  F3   │  COP_Risk_Management.pdf    │     12 ┃
        ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

Only chunks the model actually cited appear in the Sources table. The [F1] markers stay in the answer so you can trace each claim back to a row.

How it works

PDFs ─▶ pymupdf ─▶ page-bounded chunker ─▶ bge-small embeddings
                                                    │
                                                    ▼
                                              LanceDB (file-based)
                                                    │
question ─▶ query embedding ─▶ top-k retrieval ─────┘
                                          │
                                          ▼
                            Claude Sonnet 4.6 (with prompt caching)
                                          │
                                          ▼
                                cited answer + Sources table

Notable choices, briefly:

  • Page-bounded chunks — each chunk has exactly one source page, so citations stay precise.
  • Local embeddingsBAAI/bge-small-en-v1.5 runs on your machine, no embedding API cost.
  • Prompt caching — the system prompt and retrieved context are cached on the Anthropic side, so re-asking against the same context within ~5 minutes runs at a heavy discount.
  • Sources show only what was cited — if the model invented an [F9], the marker stays in the answer (so you can spot it) but the table only lists the real ones.

Configuration

Env var Purpose
ANTHROPIC_API_KEY Required for wsh-rag ask. Get one at https://console.anthropic.com/.

wsh-rag index <folder>

Flag Default Notes
--chunk-tokens 800 Tokens per chunk.
--overlap 100 Token overlap between adjacent chunks (within a page).
--embed-model BAAI/bge-small-en-v1.5 Any sentence-transformers model. Changing this requires re-indexing.

wsh-rag ask "<question>"

Flag Default Notes
--folder / -f . Folder containing the .wsh-rag/ index.
--top-k / -k 5 Chunks retrieved as context.
--model claude-sonnet-4-6 Anthropic model id.
--max-tokens 1500 Max tokens in the answer.
--embed-model BAAI/bge-small-en-v1.5 Must match what you used at index time.

Where the index lives

wsh-rag writes its index to <folder>/.wsh-rag/ — sibling to the PDFs you indexed. It's safe to delete (rm -rf .wsh-rag) and trivially re-buildable. Add this to your .gitignore:

.wsh-rag/

Singapore WSH context

This tool is built around the kinds of documents the Singapore Ministry of Manpower (MOM) and the Workplace Safety and Health Council publish:

  • The Workplace Safety and Health Act (and its subsidiary regulations)
  • Codes of Practice (e.g. CP on Risk Management, CP on Working Safely at Heights)
  • bizSAFE training materials and audit checklists
  • MOM advisories and circulars
  • Your own Risk Assessments and Safe Work Procedures

The system prompt instructs Claude to refuse to speculate when the provided context doesn't cover a question — important because WSH guidance is precise and small wording differences matter legally.

Disclaimer: wsh-rag is not a substitute for legal advice. Always cite the source PDF, not this tool's output, when reporting or making compliance decisions.

Limitations (v0.1.0)

  • No incremental re-indexing — wsh-rag index always does a full rebuild.
  • No interactive chat REPL — every ask is one-shot.
  • English text only.
  • Scanned PDFs need OCR (not bundled). If wsh-rag index warns that a PDF produced no extractable text, it's likely scanned.
  • One vector backend (LanceDB), one LLM provider (Anthropic Claude).

Roadmap

  • Hash-based incremental re-indexing (only re-embed changed PDFs)
  • Hybrid retrieval (BM25 + vector) for better recall on specific clause numbers
  • Interactive wsh-rag chat REPL with multi-turn context
  • Optional OCR via tesseract for scanned PDFs

Development

git clone https://github.com/LogiqlyAI/wsh-rag
cd wsh-rag
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"

ruff check . && ruff format --check .
pytest

The integration test in tests/test_cli.py mocks the Anthropic client and uses a tiny reportlab-generated PDF, so the suite runs offline and without an API key.

License

MIT.

wsh-rag itself is MIT-licensed. Note that PyMuPDF, used for PDF parsing, is AGPL-licensed — wsh-rag only depends on it at runtime, so distributing wsh-rag under MIT is fine, but downstream users embedding wsh-rag should be aware of PyMuPDF's terms.

Acknowledgements

  • Anthropic Claude for answer synthesis and prompt caching
  • BAAI's bge-small-en-v1.5 for local retrieval embeddings
  • LanceDB for the file-based vector store
  • PyMuPDF for fast PDF text extraction
  • The Singapore Workplace Safety and Health Council and MOM for publishing the underlying guidance documents this tool is designed for

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

wsh_rag-0.1.0.tar.gz (19.7 kB view details)

Uploaded Source

Built Distribution

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

wsh_rag-0.1.0-py3-none-any.whl (18.7 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: wsh_rag-0.1.0.tar.gz
  • Upload date:
  • Size: 19.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for wsh_rag-0.1.0.tar.gz
Algorithm Hash digest
SHA256 bd25a5da7d6cc35b228e499ff5e54bccdf3f5867fbaf6f04d80051a4490a7f93
MD5 4b76e667f838118d6d57bbe0f32c44dc
BLAKE2b-256 a6ab81823469a5d6eb768a1c09e777fdba1b8f63acb9dc41f208d2f776cd4316

See more details on using hashes here.

Provenance

The following attestation bundles were made for wsh_rag-0.1.0.tar.gz:

Publisher: publish.yml on LogiqlyAI/wsh-rag

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

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

File metadata

  • Download URL: wsh_rag-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 18.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for wsh_rag-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 711ec91a3798e4217dd75bd981a2e6c9e76d89281de9e93753d92ee46b849a7a
MD5 aaf7eb3f286d913b093a6d9ca8674cef
BLAKE2b-256 46c6608fe130ff2bb3de233b1897516c237f38a5ec8cb90e8df33de28a387ca9

See more details on using hashes here.

Provenance

The following attestation bundles were made for wsh_rag-0.1.0-py3-none-any.whl:

Publisher: publish.yml on LogiqlyAI/wsh-rag

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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