Historical GitLab MR Database with Semantic Search API
Pragma indexes your GitLab merge requests and provides a REST API and an MCP server for AI assistants to query for historical context. Instead of doing code reviews locally, it acts as a searchable knowledge base that external tools (Claude Code, Gemini, etc.) can query to get institutional knowledge from past code changes, discussions, and decisions.
Connect Pragma to your AI assistant via MCP and ask questions like:
Search pragma discussions for "authentication strategy" and summarize what
the team decided in past MRs.
- Semantic Search: Find similar historical MRs using vector similarity
- Rich Context: Indexes titles, descriptions, diffs, and discussions
- REST API: Simple HTTP endpoints for external tools
- AI Code Reviews: Automated MR reviews using Gemini or Ollama models
- GitLab Integration: Fetches MRs via python-gitlab API
- ChromaDB: Local vector database for fast retrieval
# 1. Install dependencies
uv sync
# 2. Initialize configuration
uv run pragma init
# 3. Edit config.yaml with your GitLab repository details
# 4. Test connection
uv run pragma test-connection
# 5. Index historical MRs
uv run pragma index
# 6. Start API server
uv run pragma serveVisit http://localhost:8000/docs for interactive API documentation.
# Initialize and configure
uv run pragma init
# Test GitLab connection
uv run pragma test-connection
# Index merge requests (all configured repos)
uv run pragma index
# Index a specific repository only
uv run pragma index --repo my-repo
# Start API server
uv run pragma serve
# Start with custom port
uv run pragma serve --port 8080
# Development mode with auto-reload
uv run pragma serve --reload
# Review a specific MR by IID
uv run pragma review 42
# Review an MR from a specific repo (overrides config)
uv run pragma review 42 --repo my-repo
# Continuously review new open MRs
uv run pragma review-watch --interval 60- POST /search - Semantic search for similar MRs
- GET /mrs/{mr_id} - Get full details of specific MR
- GET /mrs - List all indexed MRs
- GET /stats - Database statistics
- GET /health - Health check
import requests
response = requests.post("http://localhost:8000/search", json={
"code_diff": "your code diff here",
"top_k": 5,
"min_score": 0.5
})
similar_mrs = response.json()
for mr in similar_mrs:
print(f"!{mr['mr_id']}: {mr['mr_title']} (score: {mr['similarity_score']:.4f})")Pragma includes an MCP server (src/mcp_server.py) exposing three tools:
| Tool | Description |
|---|---|
mcp__pragma__search |
Semantic search over historical MRs |
mcp__pragma__get_mr |
Get full details of a specific MR |
mcp__pragma__list_mrs |
List all indexed MRs |
Add to your MCP client configuration (e.g. Claude Code ~/.claude.json):
{
"mcpServers": {
"pragma": {
"command": "uv",
"args": [
"run",
"--project", "/path/to/pragma",
"python",
"/path/to/pragma/src/mcp_server.py"
],
"env": {
"PRAGMA_API_URL": "http://localhost:8000"
}
}
}
}The --project flag ensures pragma's virtual environment is used regardless of the current working directory.
Find team decisions about a topic:
Search pragma discussions for "API rate limiting strategy" and summarize
what the team decided in past MRs.
Review a change with historical context:
Before reviewing my change, search pragma for:
1. Discussions about similar changes to this component
2. Diffs with similar code patterns
Use both to provide context-aware feedback.
The two-query pattern — for the richest context, always make two calls to search:
content_type: "discussion"+ natural language query → finds why decisions were madecontent_type: "diff"+ the actual code diff → finds how similar changes were implemented
See CLAUDE.md for full parameter reference and advanced usage.
GitLab API → Index MRs → Embedding Model → ChromaDB
↓
External AI Tool → HTTP API → Vector Search → Historical Context
Set credentials as environment variables (never stored in files):
export GEMINI_API_KEY=your_gemini_api_key
export GITLAB_PRIVATE_TOKEN=your_gitlab_tokenEdit config.yaml for non-sensitive settings:
gitlab:
base_url: https://gitlab.example.com # Optional, defaults to gitlab.com
repository:
type: gitlab
owner: my-group/my-subgroup # Can be nested group
name: my-repo
vector_store:
type: chromadb
path: ./data/chroma_db
# Embedding model configuration
# Both indexing and search must use the same provider.
# Switching provider requires re-indexing all MRs.
embeddings:
provider: gemini # "gemini" (default) or "local"
# model: BAAI/bge-large-en-v1.5 # local only, this is the defaultConfigure the AI model used for automated MR reviews:
agent:
provider: gemini # "gemini" (default) or "ollama"
model: gemini-2.5-flash # Gemini model name
# For Ollama (local models):
# provider: ollama
# model: mistral:7b # Ollama model tag; openai: prefix added automatically
# base_url: http://localhost:11434/v1 # optional, this is the defaultGemini: requires GEMINI_API_KEY.
Ollama: requires a running Ollama instance. Set OPENAI_BASE_URL and OPENAI_API_KEY=ollama in the environment file (see systemd section below).
Reviews are saved as Markdown files under ./data/reviews/.
Gemini embedding provider (default): requires GEMINI_API_KEY in the environment.
Local provider: runs on-device using HuggingFace sentence-transformers, no API key or internet access needed at query time. The model is downloaded once on first use and cached locally.
embeddings:
provider: local
model: BAAI/bge-large-en-v1.5 # ~1.3GB, high quality
# model: all-mpnet-base-v2 # ~420MB, good quality
# model: all-MiniLM-L6-v2 # ~80MB, fast but lower qualityWhen switching providers, clear the existing index and re-index:
uv run pragma clear-index --yes uv run pragma index
The API has no authentication and binds to localhost by default. MR diffs may contain proprietary code, so avoid exposing the API on public networks without a firewall or VPN.
# Install pre-commit hooks
uv run pre-commit install
# Run linting manually
uv run pre-commit run --all-files
# Install new dependency
uv add <package-name>Pragma provides three systemd user services that start automatically on login:
pragma-api.service- The REST API serverpragma-indexer.service- Continuous MR indexer (checks for new MRs hourly)pragma-reviewer.service- Continuous MR reviewer (reviews new open MRs hourly)
GEMINI_API_KEY=your_gemini_api_key # Required when using Gemini (embeddings or reviewer)
GITLAB_PRIVATE_TOKEN=your_gitlab_token # Required for fetching MRs
# Required for self-hosted GitLab with custom CA certificates
REQUESTS_CA_BUNDLE=/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
# Required when using Ollama as the reviewer model
# OPENAI_BASE_URL=http://localhost:11434/v1
# OPENAI_API_KEY=ollama[Unit]
Description=Pragma Historical MR Search API
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
WorkingDirectory=/home/YOUR_USERNAME/repositories/github/pragma
Environment="PATH=/home/YOUR_USERNAME/.local/bin:/usr/local/bin:/usr/bin:/bin"
EnvironmentFile=%h/.config/pragma/env
ExecStart=/usr/bin/env uv run pragma serve --host 127.0.0.1 --port 8000
Restart=on-failure
RestartSec=10
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=default.target[Unit]
Description=Pragma Continuous MR Indexer
After=network-online.target pragma-api.service
Wants=network-online.target
[Service]
Type=simple
WorkingDirectory=/home/YOUR_USERNAME/repositories/github/pragma
Environment="PATH=/home/YOUR_USERNAME/.local/bin:/usr/local/bin:/usr/bin:/bin"
EnvironmentFile=%h/.config/pragma/env
ExecStart=/usr/bin/env uv run pragma watch --interval 60
Restart=on-failure
RestartSec=30
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=default.targetThe indexer checks each configured repository every 60 minutes for new merged MRs
and indexes only those updated since the last run. State is persisted in
./data/indexing_state.json.
[Unit]
Description=Pragma Continuous MR Reviewer
After=network-online.target pragma-api.service
Wants=network-online.target
[Service]
Type=simple
WorkingDirectory=/home/YOUR_USERNAME/repositories/github/pragma
Environment="PATH=/home/YOUR_USERNAME/.local/bin:/usr/local/bin:/usr/bin:/bin"
EnvironmentFile=%h/.config/pragma/env
ExecStart=/usr/bin/env uv run pragma review-watch --interval 60
Restart=on-failure
RestartSec=30
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=default.targetThe reviewer checks for new open MRs every 60 minutes, generates AI reviews using
the configured model, and saves them as Markdown files to ./data/reviews/. A GNOME
desktop notification is sent when each review completes.
systemctl --user daemon-reload
systemctl --user enable pragma-api.service pragma-indexer.service pragma-reviewer.service
systemctl --user start pragma-api.service pragma-indexer.service pragma-reviewer.service
systemctl --user status pragma-api.service pragma-indexer.service pragma-reviewer.service# View API server logs
journalctl --user -u pragma-api.service -f
# View indexer logs
journalctl --user -u pragma-indexer.service -f
# View reviewer logs
journalctl --user -u pragma-reviewer.service -f
# Restart services
systemctl --user restart pragma-api.service
systemctl --user restart pragma-indexer.service
systemctl --user restart pragma-reviewer.service
# Stop services
systemctl --user stop pragma-api.service
systemctl --user stop pragma-indexer.service
systemctl --user stop pragma-reviewer.service- Python 3.10-3.12
- GitLab private token with API read access
- Gemini API key (only when using the
geminiembedding provider) uvpackage manager
MIT
Contributions welcome! Please ensure:
- Pre-commit hooks pass
- API endpoints are documented
- Security best practices followed