Metadata-Version: 2.4
Name: askme-rag
Version: 0.1.1
Summary: CLI RAG tool for local codebases
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: qdrant-client
Requires-Dist: openai
Requires-Dist: rich
Requires-Dist: python-dotenv
Requires-Dist: prompt-toolkit
Requires-Dist: python-docx
Requires-Dist: pypdf

# askme - Codebase RAG CLI

A Command Line Interface (CLI) tool for local Retrieval-Augmented Generation (RAG) over your codebase. It scans, indexes
and lets you chat with your project using local LLMs (via an OpenAI-compatible API) and a Qdrant vector database,
returning context-aware answers with source citations.

The Python package is named `askme` and exposes a single `askme` console script.

---

### Key Features

- Local-first architecture
  - Runs against any OpenAI-compatible LLM/embedding endpoint (e.g. Ollama) and a Qdrant instance you control.
  - Code never has to leave your machine if you self-host the services.
- Hybrid retrieval (dense + sparse)
  - Dense vectors are produced by the configured embedding model.
  - Sparse vectors are computed locally with a built-in BM25 encoder (`src/askme/sparse.py`) for keyword/identifier
    recall.
- Smart incremental indexing
  - MD5 hashing of files detects changes, so only new or modified files are re-embedded.
  - `/reindex` forces a full rebuild on demand.
- Source citations
  - Answers include inline `[File: ...]` citations and a citation list, backed by chunk metadata stored in Qdrant.
- Conversation history
  - Sessions are auto-saved as JSON in `.cfg/history/` and can be listed, loaded or deleted via `/history`.
- Rich interactive prompt
  - Powered by `prompt-toolkit` with multiline and paste modes.

---

### Technology Stack

- Language: Python 3.11+
- Vector Database: Qdrant (1.x; remote, via Docker, or local file-based)
- LLM / Embeddings: any OpenAI-compatible API (tested with Ollama)
- Key libraries:
  - `qdrant-client` - Qdrant access (dense + sparse vectors).
  - `openai` - client for the OpenAI-compatible LLM and embedding APIs.
  - `rich` - terminal UI, panels, markdown rendering.
  - `prompt-toolkit` - interactive prompt with multiline support.
  - `python-dotenv` - environment variable loading.

---

### Project Layout

```
src/askme/
  config.py      # ConfigManager - .cfg/settings.json and chat history
  scanner.py     # FileScanner  - traversal, filtering, MD5 hashing
  vector_db.py   # VectorDBConnector - chunking, embeddings, Qdrant I/O
  sparse.py      # BM25SparseEncoder - local sparse vector generation
  llm.py         # LLMInterface - prompt building and chat completion
  list_files.py  # /index command helpers
  ui.py          # rich-based UI helpers
  utils.py       # shared utilities
  models.py      # data models
  main.py        # entry point and interactive loop
tests/           # pytest test suite
```

#### Data Flow

`Codebase` -> `FileScanner (hash + filter)` -> `VectorDBConnector (chunk + dense embed + BM25 sparse)` ->
`Qdrant (hybrid index)` -> `LLMInterface (query + retrieved context)` -> `User`

---

### Setup

#### Prerequisites

- Python 3.11+
- A Qdrant vector database, in one of two modes:
  - `server` - a running Qdrant instance (local Docker or remote).
  - `local` - a file-based store on disk, no server or Docker required (quick start).
- An OpenAI-compatible LLM and embeddings endpoint (e.g. Ollama).

#### 1. Start Qdrant (optional)

In `local` mode you can skip this step entirely - the index is stored on disk under
`qdrant_local_path` (default `./data/vector_store`) and persists between runs.

For `server` mode, run Qdrant locally via Docker:

```bash
docker run -p 6333:6333 -p 6334:6334 \
    -v $(pwd)/qdrant_storage:/qdrant/storage:z \
    qdrant/qdrant
```

If you start in `server` mode but the server is unreachable, `askme` offers to fall back to `local` file-based mode
(default answer: yes) and remembers the choice in
`.cfg/settings.json`.

#### 2. Prepare models (example with Ollama)

```bash
ollama pull llama3
ollama pull embeddinggemma:300m
```

#### 3. Install

Using `uv` (recommended for development):

```bash
uv sync
uv run askme
```

Or with pip from the project root:

```bash
pip install .
askme
```

Or directly from GitHub:

```bash
pip install git+https://github.com/varsey/codebase-rag.git
```

---

### Configuration

On the first run inside a project directory, `askme` prompts for configuration and stores it in `./.cfg/settings.json`.
Conversation histories are stored next to it under `./.cfg/history/`.

| Option              | Default                               | Description                                                          |
|:--------------------|:--------------------------------------|:---------------------------------------------------------------------|
| `qdrant_mode`       | `server`                              | Connection mode: `server` (remote/Docker) or `local` (file-based).   |
| `qdrant_local_path` | `./data/vector_store`                 | On-disk path for the local file-based store (used in `local` mode).  |
| `qdrant_host`       | `localhost`                           | Hostname of the Qdrant service (used in `server` mode).              |
| `qdrant_port`       | `6333`                                | Port of the Qdrant service (used in `server` mode).                  |
| `llm_api_base`      | `http://localhost:11434/v1`           | Base URL of the OpenAI-compatible LLM API.                           |
| `llm_api_base_cert` | ``                                    | Optional path to custom cert/CA bundle for LLM API TLS verification. |
| `vdb_api_base`      | `http://localhost:11434/v1`           | Base URL of the OpenAI-compatible embeddings API.                    |
| `api_key`           | `sk-...`                              | API key passed to the OpenAI-compatible client.                      |
| `llm_model`         | `llama3`                              | LLM model name.                                                      |
| `embedding_model`   | `embeddinggemma:300m`                 | Embedding model name.                                                |
| `chunk_size`        | `750`                                 | Chunk size in characters.                                            |
| `chunk_overlap`     | `250`                                 | Overlap between chunks in characters.                                |
| `buffer_size`       | `1048576`                             | Read buffer size for file scanning.                                  |
| `top_n`             | `10`                                  | Number of chunks retrieved per query.                                |
| `collection_name`   | auto-generated                        | Qdrant collection used for this project.                             |
| `file_extensions`   | `.py, .md, .js, .ts, .go, .java, ...` | File types to index.                                                 |
| `excluded_dirs`     | `.git, .venv, node_modules, ...`      | Directories skipped during scanning.                                 |

A real example lives in `.cfg/settings.json`.

---

### Usage

Inside the codebase you want to query:

```bash
askme
```

On first launch the tool guides you through configuration, scans the project and builds the Qdrant collection.
Subsequent runs reuse the existing index and only re-embed changed files.

#### Interactive commands

- `/new` - start a fresh conversation (resets the context window).
- `/history` - list, load or delete saved sessions in `.cfg/history/`.
- `/reindex` - clear the collection and re-embed the codebase from scratch.
- `/index` - show the files currently indexed.
- `/multiline` or `/m` - toggle persistent multiline input (submit with Alt+Enter).
- `/paste` - one-shot multiline input for a single query.
- `/exit` or `/quit` - end the session.

---

### Storage Schema

Each point in the Qdrant collection holds a dense vector, a BM25 sparse vector and the following payload:

```json
{
    "path": "string (relative path to file)",
    "content": "string (the actual code chunk)",
    "hash": "string (MD5 hash of the original file)",
    "chunk_index": "int",
    "total_chunks": "int"
}
```

---

### Development

- Install dev dependencies and run tests with `uv`:

  ```bash
  uv sync
  uv run pytest
  ```

- The test suite covers config defaults, connection checks, scanner behaviour, sparse BM25 encoding, history/context
  handling and the main module wiring.

---

### Known Limitations

- Very large files can be memory-heavy during scanning and embedding.
- Answer quality is bounded by the local LLM's context window.
- Only text-based source files are supported; binaries are skipped.
- Hybrid search quality depends on the corpus the BM25 encoder was fit on (the current project).

---

### Contributing

1. Fork the repository.
2. Create a feature branch (`git checkout -b feature/your-change`).
3. Keep changes focused and follow the existing code style.
4. Add or update tests under `tests/` and make sure `uv run pytest` passes.
5. Open a Pull Request with a clear description.

---

### License

MIT License - see the `LICENSE` file for details (or standard MIT terms if the file is missing).
