A reusable civic-legal AI agent platform — built on top of the existing Naija Civic Guard RAG system — demonstrating agent orchestration, MCP-based tool integration, production-grade model serving, governance, and full observability
# Naija Civic Guard
**Grounded question-answering over the Constitution of the Federal Republic of
Nigeria (1999), built as a running platform rather than a notebook.**
Ask a question in plain English — *"What does Section 45 say about restrictions
on fundamental rights?"* — and get an answer drawn **only** from the
constitutional text, with the specific sections it came from, streamed
token-by-token. Underneath that answer is a full operational stack: an agentic
retrieval pipeline, a Model Context Protocol (MCP) tool server, an API gateway
with authentication / rate limiting / audit logging, per-request metrics in
Postgres and Prometheus, asynchronous quality evaluation on its own worker,
Grafana dashboards, and dbt models over the logs — all standing up from a
single `docker compose up`.
> ⚖️ **It is an educational tool.** Retrieval precision is not at a production
> bar for legal use (see Limitations). Treat every answer as a
> pointer to sections worth reading, not as legal advice.
---
## Contents
- Why this exists
- The system at a glance
- How a request flows
- The build, layer by layer
- 1. Ingestion & the vector store
- 2. Hybrid retrieval
- 3. The retrieval agent (LangGraph)
- 4. The MCP tool server
- 5. Generation & the provider switch
- 6. The API gateway
- 7. Request correlation
- 8. Observability — two layers
- 9. Asynchronous evaluation
- 10. Analytics (dbt)
- 11. Containerisation
- Tech stack
- Getting started
- Using it
- Observing it
- Testing
- Performance (measured)
- Project layout
- Limitations
- Roadmap
---
## Why this exists
A generic LLM will answer questions about Nigerian law from a blurry mixture of
training data, other jurisdictions, and confident guessing. For a legal document
you want the opposite: answers **anchored to the source**, with citations, that
say *"I don't know"* when the text doesn't cover it.
Retrieval-Augmented Generation gets you there — retrieve the relevant passages,
put them in the prompt, instruct the model …