Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions .claude/settings.local.json

This file was deleted.

41 changes: 21 additions & 20 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,36 @@
# e.g. postgresql://user:password@localhost:5432/rag
DATABASE_URL=

# ── Embedding backend (EMBED_BACKEND) ────────────────────────────────────────
# "voyage" (default) — uses Voyage AI voyage-code-3, requires VOYAGE_API_KEY
# "ollama" — uses local Ollama, requires ollama running
EMBED_BACKEND=voyage

# Voyage AI — code-optimised embeddings (https://www.voyageai.com)
# Required when EMBED_BACKEND=voyage
VOYAGE_API_KEY=

# Ollama — local embeddings (https://ollama.com)
# Required when EMBED_BACKEND=ollama
# OLLAMA_HOST=http://localhost:11434
# OLLAMA_EMBED_MODEL=mxbai-embed-large

# ── LLM backend for scripts/ask.py (LLM_BACKEND) ────────────────────────────
# "anthropic" (default) — requires ANTHROPIC_API_KEY
# "ollama" — requires Ollama running
# LLM_BACKEND=anthropic

# Anthropic — required when LLM_BACKEND=anthropic (https://console.anthropic.com)
# Anthropic — optional, only required for scripts/ask.py (https://console.anthropic.com)
# ANTHROPIC_API_KEY=

# Ollama chat model — used when LLM_BACKEND=ollama
# OLLAMA_CHAT_MODEL=llama3.1

# GitHub — optional; raises API rate limit from 60 to 5000 req/hr; required for private repos
# GITHUB_TOKEN=

# ── MCP HTTP authentication (required when running --transport http) ───────────
# In HTTP mode this server is its own OAuth authorization server: MCP clients
# (Claude Code, the claude.ai connector) register with it via Dynamic Client
# Registration, and it brokers sign-in with Google behind the scenes. Clients
# need only the server URL — no Google client id/secret of their own.
#
# This server's externally reachable base URL (no path, no trailing slash).
# Required whenever GOOGLE_ALLOWED_DOMAIN/GOOGLE_ALLOWED_EMAILS is set.
# MCP_PUBLIC_URL=https://your-app.up.railway.app

# The server-side Google OAuth "Web application" client used to broker sign-in.
# Create one in Google Cloud Console (APIs & Services → Credentials) and add
# <MCP_PUBLIC_URL>/auth/google/callback as an Authorised redirect URI. The
# secret is confidential — set it in the deploy environment, never commit it.
# GOOGLE_OAUTH_CLIENT_ID=123-abc.apps.googleusercontent.com
# GOOGLE_OAUTH_CLIENT_SECRET=

# Optional: override the OAuth callback path (must match the redirect URI you
# register with Google). Defaults to /auth/google/callback.
# MCP_OAUTH_CALLBACK_PATH=/auth/google/callback

# Restrict access to a Google Workspace domain (e.g. "bes.au")
GOOGLE_ALLOWED_DOMAIN=

Expand Down
17 changes: 17 additions & 0 deletions .github/workflows/claude-code-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Claude Code Review

on:
pull_request:
types: [opened, reopened, synchronize]
issue_comment:
types: [created]

jobs:
claude-review:
if: >-
github.event_name == 'pull_request' ||
(github.event_name == 'issue_comment' &&
github.event.issue.pull_request != null &&
contains(github.event.comment.body, '/review'))
uses: beyondessential/maui-team/.github/workflows/claude-code-review.yml@main
secrets: inherit
10 changes: 3 additions & 7 deletions .github/workflows/reindex.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ name: Sync RAG Index

on:
schedule:
- cron: "0 2 * * *" # Daily at 02:00 UTC
- cron: "0 15 * * *" # Daily at 15:00 UTC
workflow_dispatch:
inputs:
job:
Expand All @@ -31,6 +31,7 @@ jobs:
github.event_name == 'schedule' ||
(github.event_name == 'workflow_dispatch' && github.event.inputs.job == 'sync')
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4

Expand All @@ -47,17 +48,15 @@ jobs:
uv run python scripts/sync.py $ARGS
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
EMBED_BACKEND: ${{ secrets.EMBED_BACKEND || 'voyage' }}
VOYAGE_API_KEY: ${{ secrets.VOYAGE_API_KEY }}
OLLAMA_HOST: ${{ secrets.OLLAMA_HOST }}
OLLAMA_EMBED_MODEL: ${{ secrets.OLLAMA_EMBED_MODEL }}
GITHUB_TOKEN: ${{ secrets.GH_PAT }}

full-reindex:
if: |
github.event_name == 'workflow_dispatch' &&
github.event.inputs.job == 'full-reindex'
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4

Expand All @@ -72,8 +71,5 @@ jobs:
--namespace "${{ github.event.inputs.namespace }}"
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
EMBED_BACKEND: ${{ secrets.EMBED_BACKEND || 'voyage' }}
VOYAGE_API_KEY: ${{ secrets.VOYAGE_API_KEY }}
OLLAMA_HOST: ${{ secrets.OLLAMA_HOST }}
OLLAMA_EMBED_MODEL: ${{ secrets.OLLAMA_EMBED_MODEL }}
GITHUB_TOKEN: ${{ secrets.GH_PAT }}
16 changes: 0 additions & 16 deletions .github/workflows/sync-codeowners.yml

This file was deleted.

2 changes: 1 addition & 1 deletion .maui
Submodule .maui updated from 28cd61 to 9d2c9b
11 changes: 0 additions & 11 deletions .mcp.json

This file was deleted.

17 changes: 5 additions & 12 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@ Generic RAG pipeline for GitHub repositories — ingest, index, and query any re
## Architecture

```
Ingest: GitHub repo → chunk (langchain-text-splitters) → embed → upsert (pgvector)
Ingest: GitHub repo → chunk (langchain-text-splitters) → embed (voyage-code-3) → upsert (pgvector)
Query: question → embed → hybrid search (vector + FTS with RRF) → context chunks
MCP: search_codebase / get_file / list_files / get_repo_structure / list_namespaces / namespace_info → returns raw context (client LLM answers)
```

Embedding backend is pluggable via `EMBED_BACKEND` env var: `voyage` (Voyage AI voyage-code-3, default) or `ollama` (local Ollama, e.g. mxbai-embed-large).

The MCP server does **retrieval only** — it never calls an LLM. The calling agent (Claude Code, Cursor, etc.) does the answering using the returned context chunks.

## Key files
Expand All @@ -25,7 +23,7 @@ The MCP server does **retrieval only** — it never calls an LLM. The calling ag
- `rag/db.py` — DB setup and upsert helpers
- `rag/auth.py` — Google OAuth token verifier for HTTP transport
- `scripts/ingest.py` — ingest a repo into pgvector
- `scripts/ask.py` — local CLI for full retrieve + answer pipeline (Anthropic or Ollama; dev convenience only)
- `scripts/ask.py` — local CLI for full retrieve + answer pipeline (uses Anthropic API; dev convenience only)
- `scripts/reindex.py` — drop and re-ingest a namespace

## Transport modes
Expand All @@ -42,18 +40,13 @@ Each indexed repo gets a namespace (e.g. `tupaia`), creating `{namespace}_code`
| Variable | Used by |
|---|---|
| `DATABASE_URL` | All DB operations |
| `EMBED_BACKEND` | Selects embedding backend: `voyage` (default) or `ollama` |
| `VOYAGE_API_KEY` | Embedding when `EMBED_BACKEND=voyage` |
| `OLLAMA_HOST` | Ollama server URL when `EMBED_BACKEND=ollama` (default: `http://localhost:11434`) |
| `OLLAMA_EMBED_MODEL` | Ollama embedding model (default: `mxbai-embed-large`) |
| `LLM_BACKEND` | `scripts/ask.py` LLM: `anthropic` (default) or `ollama` |
| `ANTHROPIC_API_KEY` | `scripts/ask.py` when `LLM_BACKEND=anthropic` |
| `OLLAMA_CHAT_MODEL` | `scripts/ask.py` Ollama chat model (default: `llama3.1`) |
| `VOYAGE_API_KEY` | Embedding (ingest + query) |
| `ANTHROPIC_API_KEY` | `scripts/ask.py` only — not required for MCP |
| `GOOGLE_ALLOWED_DOMAIN` / `GOOGLE_ALLOWED_EMAILS` | HTTP transport auth (optional) |

## Conventions

- Python 3.11+
- Dependencies managed via `pyproject.toml` / `uv`
- `voyageai`, `anthropic`, and `ollama` are optional dependencies — install the extras you need (e.g. `uv sync --extra voyage --extra ollama`)
- `anthropic` is **not** a core dependency — it is only needed for `scripts/ask.py`
- SQL in `retrieve()` uses parameterised queries; never interpolate user input directly
8 changes: 5 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
COPY pyproject.toml uv.lock ./

# Install dependencies (frozen = respect lockfile exactly)
RUN uv sync --frozen --no-dev --no-install-project --extra voyage
RUN uv sync --frozen --no-dev --no-install-project

# Copy application code
COPY mcp_server.py ./
COPY rag/ ./rag/

# Railway injects PORT at runtime
ENV PORT=8080
# Railway injects PORT; default to 8765 for local testing
ENV PORT=8765

EXPOSE ${PORT}

CMD uv run python mcp_server.py --transport http --host 0.0.0.0 --port ${PORT}
Loading